diff --git a/pkg/cmd/grafana-cli/commands/install_command.go b/pkg/cmd/grafana-cli/commands/install_command.go index f88bb9bbfff99..d758633fea5b2 100644 --- a/pkg/cmd/grafana-cli/commands/install_command.go +++ b/pkg/cmd/grafana-cli/commands/install_command.go @@ -57,6 +57,8 @@ func installCommand(c CommandLine) error { return InstallPlugin(pluginToInstall, version, c) } +// InstallPlugin downloads the plugin code as a zip file from the Grafana.com API +// and then extracts the zip into the plugins directory. func InstallPlugin(pluginName, version string, c CommandLine) error { pluginFolder := c.PluginDirectory() downloadURL := c.PluginURL() @@ -152,6 +154,10 @@ func downloadFile(pluginName, filePath, url string) (err error) { return err } + return extractFiles(body, pluginName, filePath) +} + +func extractFiles(body []byte, pluginName string, filePath string) error { r, err := zip.NewReader(bytes.NewReader(body), int64(len(body))) if err != nil { return err @@ -161,12 +167,18 @@ func downloadFile(pluginName, filePath, url string) (err error) { if zf.FileInfo().IsDir() { err := os.Mkdir(newFile, 0777) - if PermissionsError(err) { + if permissionsError(err) { return fmt.Errorf(permissionsDeniedMessage, newFile) } } else { - dst, err := os.Create(newFile) - if PermissionsError(err) { + fileMode := zf.Mode() + + if strings.HasSuffix(newFile, "_linux_amd64") || strings.HasSuffix(newFile, "_darwin_amd64") { + fileMode = os.FileMode(0755) + } + + dst, err := os.OpenFile(newFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileMode) + if permissionsError(err) { return fmt.Errorf(permissionsDeniedMessage, newFile) } @@ -184,6 +196,6 @@ func downloadFile(pluginName, filePath, url string) (err error) { return nil } -func PermissionsError(err error) bool { +func permissionsError(err error) bool { return err != nil && strings.Contains(err.Error(), "permission denied") } diff --git a/pkg/cmd/grafana-cli/commands/install_command_test.go b/pkg/cmd/grafana-cli/commands/install_command_test.go index 52b329adf7ff2..3554dda82a9e1 100644 --- a/pkg/cmd/grafana-cli/commands/install_command_test.go +++ b/pkg/cmd/grafana-cli/commands/install_command_test.go @@ -1,6 +1,8 @@ package commands import ( + "io/ioutil" + "os" "testing" . "github.com/smartystreets/goconvey/convey" @@ -37,3 +39,42 @@ func TestFoldernameReplacement(t *testing.T) { }) }) } + +func TestExtractFiles(t *testing.T) { + Convey("Should preserve file permissions for plugin backend binaries for linux and darwin", t, func() { + err := os.RemoveAll("testdata/fake-plugins-dir") + So(err, ShouldBeNil) + + err = os.MkdirAll("testdata/fake-plugins-dir", 0774) + So(err, ShouldBeNil) + + body, err := ioutil.ReadFile("testdata/grafana-simple-json-datasource-ec18fa4da8096a952608a7e4c7782b4260b41bcf.zip") + So(err, ShouldBeNil) + + err = extractFiles(body, "grafana-simple-json-datasource", "testdata/fake-plugins-dir") + So(err, ShouldBeNil) + + //File in zip has permissions 777 + fileInfo, err := os.Stat("testdata/fake-plugins-dir/grafana-simple-json-datasource/simple-plugin_darwin_amd64") + So(err, ShouldBeNil) + So(fileInfo.Mode().String(), ShouldEqual, "-rwxr-xr-x") + + //File in zip has permission 664 + fileInfo, err = os.Stat("testdata/fake-plugins-dir/grafana-simple-json-datasource/simple-plugin_linux_amd64") + So(err, ShouldBeNil) + So(fileInfo.Mode().String(), ShouldEqual, "-rwxr-xr-x") + + //File in zip has permission 644 + fileInfo, err = os.Stat("testdata/fake-plugins-dir/grafana-simple-json-datasource/simple-plugin_windows_amd64.exe") + So(err, ShouldBeNil) + So(fileInfo.Mode().String(), ShouldEqual, "-rw-r--r--") + + //File in zip has permission 755 + fileInfo, err = os.Stat("testdata/fake-plugins-dir/grafana-simple-json-datasource/non-plugin-binary") + So(err, ShouldBeNil) + So(fileInfo.Mode().String(), ShouldEqual, "-rwxr-xr-x") + + err = os.RemoveAll("testdata/fake-plugins-dir") + So(err, ShouldBeNil) + }) +} diff --git a/pkg/cmd/grafana-cli/commands/testdata/grafana-simple-json-datasource-ec18fa4da8096a952608a7e4c7782b4260b41bcf.zip b/pkg/cmd/grafana-cli/commands/testdata/grafana-simple-json-datasource-ec18fa4da8096a952608a7e4c7782b4260b41bcf.zip new file mode 100644 index 0000000000000..f9263ab3e78a3 Binary files /dev/null and b/pkg/cmd/grafana-cli/commands/testdata/grafana-simple-json-datasource-ec18fa4da8096a952608a7e4c7782b4260b41bcf.zip differ