Commit b99127be by Arve Knudsen Committed by GitHub

PluginManager: Remove some global state (#31081)

* PluginManager: Remove global state

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
parent cff6f5fe
......@@ -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(),
},
......
......@@ -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
......
......@@ -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",
......
......@@ -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 {
......
......@@ -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,
......
......@@ -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()
......
......@@ -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)
}
}
......@@ -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)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment