PluginManager: Make Plugins, Renderer and DataSources non-global (#31866)

* PluginManager: Make Plugins and DataSources non-global

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix integration tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Replace outdated command

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* DashboardService: Ensure it gets constructed with necessary parameters

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix build

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* DashboardService: Ensure it gets constructed with necessary parameters

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Remove dead code

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix test

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix test

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Remove FocusConvey

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix test

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Remove dead code

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Undo interface changes

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Backend: Move tsdbifaces.RequestHandler to plugins.DataRequestHandler

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Rename to DataSourceCount

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Consolidate dashboard interfaces into one

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix test

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix dashboard integration tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
Arve Knudsen
2021-03-17 16:06:10 +01:00
committed by GitHub
parent f1df32ac03
commit 87c3a2b790
95 changed files with 2455 additions and 2426 deletions
+67 -30
View File
@@ -21,19 +21,17 @@ import (
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/errutil"
)
var (
DataSources map[string]*plugins.DataSourcePlugin
Panels map[string]*plugins.PanelPlugin
StaticRoutes []*plugins.PluginStaticRoute
Apps map[string]*plugins.AppPlugin
Plugins map[string]*plugins.PluginBase
PluginTypes map[string]interface{}
Renderer *plugins.RendererPlugin
plog log.Logger
)
@@ -54,30 +52,36 @@ type PluginScanner struct {
type PluginManager struct {
BackendPluginManager backendplugin.Manager `inject:""`
Cfg *setting.Cfg `inject:""`
SQLStore *sqlstore.SQLStore `inject:""`
log log.Logger
scanningErrors []error
// 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
grafanaLatestVersion string
grafanaHasUpdate bool
pluginScanningErrors map[string]plugins.PluginError
renderer *plugins.RendererPlugin
dataSources map[string]*plugins.DataSourcePlugin
plugins map[string]*plugins.PluginBase
}
func init() {
registry.RegisterService(&PluginManager{})
registry.RegisterService(&PluginManager{
dataSources: map[string]*plugins.DataSourcePlugin{},
})
}
func (pm *PluginManager) Init() error {
pm.log = log.New("plugins")
plog = log.New("plugins")
DataSources = map[string]*plugins.DataSourcePlugin{}
StaticRoutes = []*plugins.PluginStaticRoute{}
Panels = map[string]*plugins.PanelPlugin{}
Apps = map[string]*plugins.AppPlugin{}
Plugins = map[string]*plugins.PluginBase{}
pm.plugins = map[string]*plugins.PluginBase{}
PluginTypes = map[string]interface{}{
"panel": plugins.PanelPlugin{},
"datasource": plugins.DataSourcePlugin{},
@@ -134,22 +138,22 @@ func (pm *PluginManager) Init() error {
StaticRoutes = append(StaticRoutes, staticRoutes...)
}
for _, ds := range DataSources {
for _, ds := range pm.dataSources {
staticRoutes := ds.InitFrontendPlugin(pm.Cfg)
StaticRoutes = append(StaticRoutes, staticRoutes...)
}
for _, app := range Apps {
staticRoutes := app.InitApp(Panels, DataSources, pm.Cfg)
staticRoutes := app.InitApp(Panels, pm.dataSources, pm.Cfg)
StaticRoutes = append(StaticRoutes, staticRoutes...)
}
if Renderer != nil {
staticRoutes := Renderer.InitFrontendPlugin(pm.Cfg)
if pm.renderer != nil {
staticRoutes := pm.renderer.InitFrontendPlugin(pm.Cfg)
StaticRoutes = append(StaticRoutes, staticRoutes...)
}
for _, p := range Plugins {
for _, p := range pm.plugins {
if p.IsCorePlugin {
p.Signature = plugins.PluginSignatureInternal
} else {
@@ -178,6 +182,48 @@ func (pm *PluginManager) Run(ctx context.Context) error {
return ctx.Err()
}
func (pm *PluginManager) Renderer() *plugins.RendererPlugin {
return pm.renderer
}
func (pm *PluginManager) GetDataSource(id string) *plugins.DataSourcePlugin {
return pm.dataSources[id]
}
func (pm *PluginManager) DataSources() []*plugins.DataSourcePlugin {
var rslt []*plugins.DataSourcePlugin
for _, ds := range pm.dataSources {
rslt = append(rslt, ds)
}
return rslt
}
func (pm *PluginManager) DataSourceCount() int {
return len(pm.dataSources)
}
func (pm *PluginManager) Plugins() []*plugins.PluginBase {
var rslt []*plugins.PluginBase
for _, p := range pm.plugins {
rslt = append(rslt, p)
}
return rslt
}
func (pm *PluginManager) GetPlugin(id string) *plugins.PluginBase {
return pm.plugins[id]
}
func (pm *PluginManager) GrafanaLatestVersion() string {
return pm.grafanaLatestVersion
}
func (pm *PluginManager) GrafanaHasUpdate() bool {
return pm.grafanaHasUpdate
}
// scanPluginPaths scans configured plugin paths.
func (pm *PluginManager) scanPluginPaths() error {
for pluginID, settings := range pm.Cfg.PluginSettings {
@@ -315,13 +361,13 @@ func (pm *PluginManager) loadPlugin(jsonParser *json.Decoder, pluginBase *plugin
var pb *plugins.PluginBase
switch p := plug.(type) {
case *plugins.DataSourcePlugin:
DataSources[p.Id] = p
pm.dataSources[p.Id] = p
pb = &p.PluginBase
case *plugins.PanelPlugin:
Panels[p.Id] = p
pb = &p.PluginBase
case *plugins.RendererPlugin:
Renderer = p
pm.renderer = p
pb = &p.PluginBase
case *plugins.AppPlugin:
Apps[p.Id] = p
@@ -330,7 +376,7 @@ func (pm *PluginManager) loadPlugin(jsonParser *json.Decoder, pluginBase *plugin
panic(fmt.Sprintf("Unrecognized plugin type %T", plug))
}
if p, exists := Plugins[pb.Id]; exists {
if p, exists := pm.plugins[pb.Id]; exists {
pm.log.Warn("Plugin is duplicate", "id", pb.Id)
scanner.errors = append(scanner.errors, plugins.DuplicatePluginError{Plugin: pb, ExistingPlugin: p})
return nil
@@ -360,20 +406,11 @@ func (pm *PluginManager) loadPlugin(jsonParser *json.Decoder, pluginBase *plugin
pb.SignatureType = pluginBase.SignatureType
pb.SignatureOrg = pluginBase.SignatureOrg
Plugins[pb.Id] = pb
pm.plugins[pb.Id] = pb
pm.log.Debug("Successfully added plugin", "id", pb.Id)
return nil
}
// GetDatasource returns a datasource based on passed pluginID if it exists
//
// This function fetches the datasource from the global variable DataSources in this package.
// Rather then refactor all dependencies on the global variable we can use this as an transition.
func (pm *PluginManager) GetDatasource(pluginID string) (*plugins.DataSourcePlugin, bool) {
ds, exists := DataSources[pluginID]
return ds, exists
}
func (s *PluginScanner) walker(currentPath string, f os.FileInfo, err error) error {
// We scan all the subfolders for plugin.json (with some exceptions) so that we also load embedded plugins, for
// example https://github.com/raintank/worldping-app/tree/master/dist/grafana-worldmap-panel worldmap panel plugin
@@ -545,7 +582,7 @@ func (pm *PluginManager) ScanningErrors() []plugins.PluginError {
}
func (pm *PluginManager) GetPluginMarkdown(pluginId string, name string) ([]byte, error) {
plug, exists := Plugins[pluginId]
plug, exists := pm.plugins[pluginId]
if !exists {
return nil, plugins.PluginNotFoundError{PluginID: pluginId}
}
@@ -600,14 +637,14 @@ func collectPluginFilesWithin(rootDir string) ([]string, error) {
}
// GetDataPlugin gets a DataPlugin with a certain name. If none is found, nil is returned.
func (pm *PluginManager) GetDataPlugin(pluginID string) plugins.DataPlugin {
if p, exists := DataSources[pluginID]; exists && p.CanHandleDataQueries() {
func (pm *PluginManager) GetDataPlugin(id string) plugins.DataPlugin {
if p, exists := pm.dataSources[id]; exists && p.CanHandleDataQueries() {
return p
}
// XXX: Might other plugins implement DataPlugin?
p := pm.BackendPluginManager.GetDataPlugin(pluginID)
p := pm.BackendPluginManager.GetDataPlugin(id)
if p != nil {
return p.(plugins.DataPlugin)
}