diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 78f9c2b7a47..16433b94be9 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -224,8 +224,8 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i "commit": commit, "buildstamp": buildstamp, "edition": hs.License.Edition(), - "latestVersion": plugins.GrafanaLatestVersion, - "hasUpdate": plugins.GrafanaHasUpdate, + "latestVersion": hs.PluginManager.GrafanaLatestVersion, + "hasUpdate": hs.PluginManager.GrafanaHasUpdate, "env": setting.Env, "isEnterprise": hs.License.HasValidLicense(), }, diff --git a/pkg/api/frontendsettings_test.go b/pkg/api/frontendsettings_test.go index 1e9bf4e1e09..a1c720ef6fe 100644 --- a/pkg/api/frontendsettings_test.go +++ b/pkg/api/frontendsettings_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/services/licensing" @@ -47,8 +48,9 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg) (*macaron.Macaron, *HT hs := &HTTPServer{ Cfg: cfg, Bus: bus.GetBus(), - License: &licensing.OSSLicensingService{}, + License: &licensing.OSSLicensingService{Cfg: cfg}, RenderService: r, + PluginManager: &plugins.PluginManager{Cfg: cfg}, } m := macaron.New() @@ -74,13 +76,17 @@ func TestHTTPServer_GetFrontendSettings_hideVersionAnonyomus(t *testing.T) { } cfg := setting.NewCfg() + cfg.Env = "testing" + cfg.BuildVersion = "7.8.9" + cfg.BuildCommit = "01234567" m, hs := setupTestEnvironment(t, cfg) req := httptest.NewRequest(http.MethodGet, "/api/frontend/settings", nil) - setting.BuildVersion = "7.8.9" - setting.BuildCommit = "01234567" - setting.Env = "testing" + // TODO: Remove + setting.BuildVersion = cfg.BuildVersion + setting.BuildCommit = cfg.BuildCommit + setting.Env = cfg.Env tests := []struct { desc string diff --git a/pkg/api/index.go b/pkg/api/index.go index 57b782017cb..ae2165cd6e1 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -408,8 +408,8 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat GoogleTagManagerId: setting.GoogleTagManagerId, BuildVersion: setting.BuildVersion, BuildCommit: setting.BuildCommit, - NewGrafanaVersion: plugins.GrafanaLatestVersion, - NewGrafanaVersionExists: plugins.GrafanaHasUpdate, + NewGrafanaVersion: hs.PluginManager.GrafanaLatestVersion, + NewGrafanaVersionExists: hs.PluginManager.GrafanaHasUpdate, AppName: setting.ApplicationName, AppNameBodyClass: getAppNameBodyClass(hs.License.HasValidLicense()), FavIcon: "public/img/fav32.png", diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 6e58f1881fc..c7f5b08692b 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -368,7 +368,7 @@ func (hs *HTTPServer) getCachedPluginSettings(pluginID string, user *models.Sign } func (hs *HTTPServer) GetPluginErrorsList(c *models.ReqContext) response.Response { - return response.JSON(200, plugins.ScanningErrors()) + return response.JSON(200, hs.PluginManager.ScanningErrors()) } func translatePluginRequestErrorToAPIError(err error) response.Response { diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 5e217d87dcb..e6370a29e75 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -32,11 +32,7 @@ var ( PluginTypes map[string]interface{} Renderer *RendererPlugin - GrafanaLatestVersion string - GrafanaHasUpdate bool - plog log.Logger - - pluginScanningErrors map[string]*PluginError + plog log.Logger ) type unsignedPluginConditionFunc = func(plugin *PluginBase) bool @@ -61,6 +57,9 @@ type PluginManager struct { // AllowUnsignedPluginsCondition changes the policy for allowing unsigned plugins. Signature validation only runs when plugins are starting // and running plugins will not be terminated if they violate the new policy. AllowUnsignedPluginsCondition unsignedPluginConditionFunc + GrafanaLatestVersion string + GrafanaHasUpdate bool + pluginScanningErrors map[string]PluginError } func init() { @@ -82,11 +81,11 @@ func (pm *PluginManager) Init() error { "app": AppPlugin{}, "renderer": RendererPlugin{}, } - pluginScanningErrors = map[string]*PluginError{} + pm.pluginScanningErrors = map[string]PluginError{} pm.log.Info("Starting plugin search") - plugDir := filepath.Join(setting.StaticRootPath, "app/plugins") + plugDir := filepath.Join(pm.Cfg.StaticRootPath, "app/plugins") pm.log.Debug("Scanning core plugin directory", "dir", plugDir) if err := pm.scan(plugDir, false); err != nil { return errutil.Wrapf(err, "failed to scan core plugin directory '%s'", plugDir) @@ -105,21 +104,21 @@ func (pm *PluginManager) Init() error { } // check if plugins dir exists - exists, err = fs.Exists(setting.PluginsPath) + exists, err = fs.Exists(pm.Cfg.PluginsPath) if err != nil { return err } if !exists { - if err = os.MkdirAll(setting.PluginsPath, os.ModePerm); err != nil { - pm.log.Error("failed to create external plugins directory", "dir", setting.PluginsPath, "error", err) + if err = os.MkdirAll(pm.Cfg.PluginsPath, os.ModePerm); err != nil { + pm.log.Error("failed to create external plugins directory", "dir", pm.Cfg.PluginsPath, "error", err) } else { - pm.log.Info("External plugins directory created", "directory", setting.PluginsPath) + pm.log.Info("External plugins directory created", "directory", pm.Cfg.PluginsPath) } } else { - pm.log.Debug("Scanning external plugins directory", "dir", setting.PluginsPath) - if err := pm.scan(setting.PluginsPath, true); err != nil { + pm.log.Debug("Scanning external plugins directory", "dir", pm.Cfg.PluginsPath) + if err := pm.scan(pm.Cfg.PluginsPath, true); err != nil { return errutil.Wrapf(err, "failed to scan external plugins directory '%s'", - setting.PluginsPath) + pm.Cfg.PluginsPath) } } @@ -241,7 +240,7 @@ func (pm *PluginManager) scan(pluginDir string, requireSigned bool) error { if signingError != nil { pm.log.Debug("Failed to validate plugin signature. Will skip loading", "id", plugin.Id, "signature", plugin.Signature, "status", signingError.ErrorCode) - pluginScanningErrors[plugin.Id] = signingError + pm.pluginScanningErrors[plugin.Id] = *signingError continue } @@ -255,7 +254,7 @@ func (pm *PluginManager) scan(pluginDir string, requireSigned bool) error { jsonFPath := filepath.Join(plugin.PluginDir, "plugin.json") // External plugins need a module.js file for SystemJS to load - if !strings.HasPrefix(jsonFPath, setting.StaticRootPath) && !scanner.IsBackendOnlyPlugin(plugin.Type) { + if !strings.HasPrefix(jsonFPath, pm.Cfg.StaticRootPath) && !scanner.IsBackendOnlyPlugin(plugin.Type) { module := filepath.Join(plugin.PluginDir, "module.js") exists, err := fs.Exists(module) if err != nil { @@ -460,7 +459,7 @@ func (s *PluginScanner) allowUnsigned(plugin *PluginBase) bool { return s.allowUnsignedPluginsCondition(plugin) } - if setting.Env == setting.Dev { + if s.cfg.Env == setting.Dev { return true } @@ -473,9 +472,10 @@ func (s *PluginScanner) allowUnsigned(plugin *PluginBase) bool { return false } -func ScanningErrors() []PluginError { +// ScanningErrors returns plugin scanning errors encountered. +func (pm *PluginManager) ScanningErrors() []PluginError { scanningErrs := make([]PluginError, 0) - for id, e := range pluginScanningErrors { + for id, e := range pm.pluginScanningErrors { scanningErrs = append(scanningErrs, PluginError{ ErrorCode: e.ErrorCode, PluginID: id, diff --git a/pkg/plugins/plugins_test.go b/pkg/plugins/plugins_test.go index a9879e93021..3ea2caa527b 100644 --- a/pkg/plugins/plugins_test.go +++ b/pkg/plugins/plugins_test.go @@ -17,6 +17,9 @@ import ( ) func TestPluginManager_Init(t *testing.T) { + staticRootPath, err := filepath.Abs("../../public/") + require.NoError(t, err) + origRootPath := setting.StaticRootPath origRaw := setting.Raw origEnv := setting.Env @@ -25,16 +28,16 @@ func TestPluginManager_Init(t *testing.T) { setting.Raw = origRaw setting.Env = origEnv }) - - var err error - setting.StaticRootPath, err = filepath.Abs("../../public/") - require.NoError(t, err) + setting.StaticRootPath = staticRootPath setting.Raw = ini.Empty() setting.Env = setting.Prod t.Run("Base case", func(t *testing.T) { pm := &PluginManager{ Cfg: &setting.Cfg{ + Raw: ini.Empty(), + Env: setting.Prod, + StaticRootPath: staticRootPath, PluginSettings: setting.PluginSettings{ "nginx-app": map[string]string{ "path": "testdata/test-app", @@ -55,14 +58,8 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With external back-end plugin lacking signature", func(t *testing.T) { - origPluginsPath := setting.PluginsPath - t.Cleanup(func() { - setting.PluginsPath = origPluginsPath - }) - setting.PluginsPath = "testdata/unsigned" - pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{PluginsPath: "testdata/unsigned"}, } err := pm.Init() require.NoError(t, err) @@ -71,14 +68,9 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With external unsigned back-end plugin and configuration disabling signature check of this plugin", func(t *testing.T) { - origPluginsPath := setting.PluginsPath - t.Cleanup(func() { - setting.PluginsPath = origPluginsPath - }) - setting.PluginsPath = "testdata/unsigned" - pm := &PluginManager{ Cfg: &setting.Cfg{ + PluginsPath: "testdata/unsigned", PluginsAllowUnsigned: []string{"test"}, }, BackendPluginManager: &fakeBackendPluginManager{}, @@ -90,14 +82,10 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With external back-end plugin with invalid v1 signature", func(t *testing.T) { - origPluginsPath := setting.PluginsPath - t.Cleanup(func() { - setting.PluginsPath = origPluginsPath - }) - setting.PluginsPath = "testdata/invalid-v1-signature" - pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{ + PluginsPath: "testdata/invalid-v1-signature", + }, } err := pm.Init() require.NoError(t, err) @@ -106,15 +94,11 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With external back-end plugin lacking files listed in manifest", func(t *testing.T) { - origPluginsPath := setting.PluginsPath - t.Cleanup(func() { - setting.PluginsPath = origPluginsPath - }) - setting.PluginsPath = "testdata/lacking-files" - fm := &fakeBackendPluginManager{} pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{ + PluginsPath: "testdata/lacking-files", + }, BackendPluginManager: fm, } err := pm.Init() @@ -124,15 +108,11 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("Transform plugins should be ignored when expressions feature is off", func(t *testing.T) { - origPluginsPath := setting.PluginsPath - t.Cleanup(func() { - setting.PluginsPath = origPluginsPath - }) - setting.PluginsPath = "testdata/behind-feature-flag" - fm := fakeBackendPluginManager{} pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{ + PluginsPath: "testdata/behind-feature-flag", + }, BackendPluginManager: &fm, } err := pm.Init() @@ -143,14 +123,10 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With nested plugin duplicating parent", func(t *testing.T) { - origPluginsPath := setting.PluginsPath - t.Cleanup(func() { - setting.PluginsPath = origPluginsPath - }) - setting.PluginsPath = "testdata/duplicate-plugins" - pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{ + PluginsPath: "testdata/duplicate-plugins", + }, } err := pm.Init() require.NoError(t, err) @@ -160,14 +136,10 @@ func TestPluginManager_Init(t *testing.T) { }) t.Run("With external back-end plugin with valid v2 signature", func(t *testing.T) { - origPluginsPath := setting.PluginsPath - t.Cleanup(func() { - setting.PluginsPath = origPluginsPath - }) - setting.PluginsPath = "testdata/valid-v2-signature" - pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{ + PluginsPath: "testdata/valid-v2-signature", + }, BackendPluginManager: &fakeBackendPluginManager{}, } err := pm.Init() @@ -188,16 +160,15 @@ func TestPluginManager_Init(t *testing.T) { t.Run("With back-end plugin with invalid v2 private signature (mismatched root URL)", func(t *testing.T) { origAppURL := setting.AppUrl - origPluginsPath := setting.PluginsPath t.Cleanup(func() { setting.AppUrl = origAppURL - setting.PluginsPath = origPluginsPath }) setting.AppUrl = "http://localhost:1234" - setting.PluginsPath = "testdata/valid-v2-pvt-signature" pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{ + PluginsPath: "testdata/valid-v2-pvt-signature", + }, } err := pm.Init() require.NoError(t, err) @@ -208,16 +179,15 @@ func TestPluginManager_Init(t *testing.T) { t.Run("With back-end plugin with valid v2 private signature", func(t *testing.T) { origAppURL := setting.AppUrl - origPluginsPath := setting.PluginsPath t.Cleanup(func() { setting.AppUrl = origAppURL - setting.PluginsPath = origPluginsPath }) setting.AppUrl = "http://localhost:3000/" - setting.PluginsPath = "testdata/valid-v2-pvt-signature" pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{ + PluginsPath: "testdata/valid-v2-pvt-signature", + }, BackendPluginManager: &fakeBackendPluginManager{}, } err := pm.Init() @@ -238,16 +208,15 @@ func TestPluginManager_Init(t *testing.T) { t.Run("With back-end plugin with modified v2 signature (missing file from plugin dir)", func(t *testing.T) { origAppURL := setting.AppUrl - origPluginsPath := setting.PluginsPath t.Cleanup(func() { setting.AppUrl = origAppURL - setting.PluginsPath = origPluginsPath }) setting.AppUrl = "http://localhost:3000/" - setting.PluginsPath = "testdata/invalid-v2-signature" pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{ + PluginsPath: "testdata/invalid-v2-signature", + }, BackendPluginManager: &fakeBackendPluginManager{}, } err := pm.Init() @@ -258,16 +227,15 @@ func TestPluginManager_Init(t *testing.T) { t.Run("With back-end plugin with modified v2 signature (unaccounted file in plugin dir)", func(t *testing.T) { origAppURL := setting.AppUrl - origPluginsPath := setting.PluginsPath t.Cleanup(func() { setting.AppUrl = origAppURL - setting.PluginsPath = origPluginsPath }) setting.AppUrl = "http://localhost:3000/" - setting.PluginsPath = "testdata/invalid-v2-signature-2" pm := &PluginManager{ - Cfg: &setting.Cfg{}, + Cfg: &setting.Cfg{ + PluginsPath: "testdata/invalid-v2-signature-2", + }, BackendPluginManager: &fakeBackendPluginManager{}, } err := pm.Init() diff --git a/pkg/plugins/update_checker.go b/pkg/plugins/update_checker.go index d1e60e05208..0209975117f 100644 --- a/pkg/plugins/update_checker.go +++ b/pkg/plugins/update_checker.go @@ -112,17 +112,16 @@ func (pm *PluginManager) checkForUpdates() { } if strings.Contains(setting.BuildVersion, "-") { - GrafanaLatestVersion = githubLatest.Testing - GrafanaHasUpdate = !strings.HasPrefix(setting.BuildVersion, githubLatest.Testing) + pm.GrafanaLatestVersion = githubLatest.Testing + pm.GrafanaHasUpdate = !strings.HasPrefix(setting.BuildVersion, githubLatest.Testing) } else { - GrafanaLatestVersion = githubLatest.Stable - GrafanaHasUpdate = githubLatest.Stable != setting.BuildVersion + pm.GrafanaLatestVersion = githubLatest.Stable + pm.GrafanaHasUpdate = githubLatest.Stable != setting.BuildVersion } currVersion, err1 := version.NewVersion(setting.BuildVersion) - latestVersion, err2 := version.NewVersion(GrafanaLatestVersion) - + latestVersion, err2 := version.NewVersion(pm.GrafanaLatestVersion) if err1 == nil && err2 == nil { - GrafanaHasUpdate = currVersion.LessThan(latestVersion) + pm.GrafanaHasUpdate = currVersion.LessThan(latestVersion) } } diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 0e01807b035..724b019b0e6 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -67,7 +67,6 @@ var ( // Paths HomePath string - PluginsPath string CustomInitPath = "conf/custom.ini" // HTTP server options @@ -215,6 +214,7 @@ type Cfg struct { ProvisioningPath string DataPath string LogsPath string + PluginsPath string BundledPluginsPath string // SMTP email settings @@ -765,7 +765,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error { cfg.Env = Env InstanceName = valueAsString(iniFile.Section(""), "instance_name", "unknown_instance_name") plugins := valueAsString(iniFile.Section("paths"), "plugins", "") - PluginsPath = makeAbsolute(plugins, HomePath) + cfg.PluginsPath = makeAbsolute(plugins, HomePath) cfg.BundledPluginsPath = makeAbsolute("plugins-bundled", HomePath) provisioning := valueAsString(iniFile.Section("paths"), "provisioning", "") cfg.ProvisioningPath = makeAbsolute(provisioning, HomePath) @@ -969,7 +969,7 @@ func (cfg *Cfg) LogConfigSources() { cfg.Logger.Info("Path Home", "path", HomePath) cfg.Logger.Info("Path Data", "path", cfg.DataPath) cfg.Logger.Info("Path Logs", "path", cfg.LogsPath) - cfg.Logger.Info("Path Plugins", "path", PluginsPath) + cfg.Logger.Info("Path Plugins", "path", cfg.PluginsPath) cfg.Logger.Info("Path Provisioning", "path", cfg.ProvisioningPath) cfg.Logger.Info("App mode " + cfg.Env) }