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:
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user