mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
@@ -3,10 +3,55 @@ package plugins
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
// Manager is the plugin manager service interface.
|
||||
type Manager interface {
|
||||
// Renderer gets the renderer plugin.
|
||||
Renderer() *RendererPlugin
|
||||
// GetDataSource gets a data source plugin with a certain ID.
|
||||
GetDataSource(id string) *DataSourcePlugin
|
||||
// GetDataPlugin gets a data plugin with a certain ID.
|
||||
GetDataPlugin(id string) DataPlugin
|
||||
// GetPlugin gets a plugin with a certain ID.
|
||||
GetPlugin(id string) *PluginBase
|
||||
// DataSourceCount gets the number of data sources.
|
||||
DataSourceCount() int
|
||||
// DataSources gets all data sources.
|
||||
DataSources() []*DataSourcePlugin
|
||||
// GetEnabledPlugins gets enabled plugins.
|
||||
GetEnabledPlugins(orgID int64) (*EnabledPlugins, error)
|
||||
// GrafanaLatestVersion gets the latest Grafana version.
|
||||
GrafanaLatestVersion() string
|
||||
// GrafanaHasUpdate returns whether Grafana has an update.
|
||||
GrafanaHasUpdate() bool
|
||||
// Plugins gets all plugins.
|
||||
Plugins() []*PluginBase
|
||||
// GetPluginSettings gets settings for a certain plugin.
|
||||
GetPluginSettings(orgID int64) (map[string]*models.PluginSettingInfoDTO, error)
|
||||
// GetPluginDashboards gets dashboards for a certain org/plugin.
|
||||
GetPluginDashboards(orgID int64, pluginID string) ([]*PluginDashboardInfoDTO, error)
|
||||
// GetPluginMarkdown gets markdown for a certain plugin/name.
|
||||
GetPluginMarkdown(pluginID string, name string) ([]byte, error)
|
||||
// ImportDashboard imports a dashboard.
|
||||
ImportDashboard(pluginID, path string, orgID, folderID int64, dashboardModel *simplejson.Json,
|
||||
overwrite bool, inputs []ImportDashboardInput, user *models.SignedInUser,
|
||||
requestHandler DataRequestHandler) (PluginDashboardInfoDTO, error)
|
||||
// ScanningErrors returns plugin scanning errors encountered.
|
||||
ScanningErrors() []PluginError
|
||||
}
|
||||
|
||||
type ImportDashboardInput struct {
|
||||
Type string `json:"type"`
|
||||
PluginId string `json:"pluginId"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// DataRequestHandler is a data request handler interface.
|
||||
type DataRequestHandler interface {
|
||||
// HandleRequest handles a data request.
|
||||
HandleRequest(context.Context, *models.DataSource, DataQuery) (DataResponse, error)
|
||||
}
|
||||
|
||||
@@ -13,13 +13,6 @@ import (
|
||||
|
||||
var varRegex = regexp.MustCompile(`(\$\{.+?\})`)
|
||||
|
||||
type ImportDashboardInput struct {
|
||||
Type string `json:"type"`
|
||||
PluginId string `json:"pluginId"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type DashboardInputMissingError struct {
|
||||
VariableName string
|
||||
}
|
||||
@@ -29,7 +22,7 @@ func (e DashboardInputMissingError) Error() string {
|
||||
}
|
||||
|
||||
func (pm *PluginManager) ImportDashboard(pluginID, path string, orgID, folderID int64, dashboardModel *simplejson.Json,
|
||||
overwrite bool, inputs []ImportDashboardInput, user *models.SignedInUser,
|
||||
overwrite bool, inputs []plugins.ImportDashboardInput, user *models.SignedInUser,
|
||||
requestHandler plugins.DataRequestHandler) (plugins.PluginDashboardInfoDTO, error) {
|
||||
var dashboard *models.Dashboard
|
||||
if pluginID != "" {
|
||||
@@ -67,7 +60,7 @@ func (pm *PluginManager) ImportDashboard(pluginID, path string, orgID, folderID
|
||||
User: user,
|
||||
}
|
||||
|
||||
savedDash, err := dashboards.NewService().ImportDashboard(dto)
|
||||
savedDash, err := dashboards.NewService(pm.SQLStore).ImportDashboard(dto)
|
||||
if err != nil {
|
||||
return plugins.PluginDashboardInfoDTO{}, err
|
||||
}
|
||||
@@ -89,12 +82,12 @@ func (pm *PluginManager) ImportDashboard(pluginID, path string, orgID, folderID
|
||||
|
||||
type DashTemplateEvaluator struct {
|
||||
template *simplejson.Json
|
||||
inputs []ImportDashboardInput
|
||||
inputs []plugins.ImportDashboardInput
|
||||
variables map[string]string
|
||||
result *simplejson.Json
|
||||
}
|
||||
|
||||
func (e *DashTemplateEvaluator) findInput(varName string, varType string) *ImportDashboardInput {
|
||||
func (e *DashTemplateEvaluator) findInput(varName string, varType string) *plugins.ImportDashboardInput {
|
||||
for _, input := range e.inputs {
|
||||
if varType == input.Type && (input.Name == varName || input.Name == "*") {
|
||||
return &input
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -21,7 +22,7 @@ func TestDashboardImport(t *testing.T) {
|
||||
dashboards.MockDashboardService(mock)
|
||||
|
||||
info, err := pm.ImportDashboard("test-app", "dashboards/connections.json", 1, 0, nil, false,
|
||||
[]ImportDashboardInput{
|
||||
[]plugins.ImportDashboardInput{
|
||||
{Name: "*", Type: "datasource", Value: "graphite"},
|
||||
}, &models.SignedInUser{UserId: 1, OrgRole: models.ROLE_ADMIN}, nil)
|
||||
require.NoError(t, err)
|
||||
@@ -58,7 +59,7 @@ func TestDashboardImport(t *testing.T) {
|
||||
|
||||
evaluator := &DashTemplateEvaluator{
|
||||
template: template,
|
||||
inputs: []ImportDashboardInput{
|
||||
inputs: []plugins.ImportDashboardInput{
|
||||
{Name: "*", Type: "datasource", Value: "my-server"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func (pm *PluginManager) GetPluginDashboards(orgId int64, pluginId string) ([]*plugins.PluginDashboardInfoDTO, error) {
|
||||
plugin, exists := Plugins[pluginId]
|
||||
plugin, exists := pm.plugins[pluginId]
|
||||
if !exists {
|
||||
return nil, plugins.PluginNotFoundError{PluginID: pluginId}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func (pm *PluginManager) GetPluginDashboards(orgId int64, pluginId string) ([]*p
|
||||
}
|
||||
|
||||
func (pm *PluginManager) LoadPluginDashboard(pluginId, path string) (*models.Dashboard, error) {
|
||||
plugin, exists := Plugins[pluginId]
|
||||
plugin, exists := pm.plugins[pluginId]
|
||||
if !exists {
|
||||
return nil, plugins.PluginNotFoundError{PluginID: pluginId}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ func TestPluginManager_Init(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Empty(t, pm.scanningErrors)
|
||||
assert.Greater(t, len(DataSources), 1)
|
||||
assert.Greater(t, len(pm.dataSources), 1)
|
||||
assert.Greater(t, len(Panels), 1)
|
||||
assert.Equal(t, "app/plugins/datasource/graphite/module", DataSources["graphite"].Module)
|
||||
assert.Equal(t, "app/plugins/datasource/graphite/module", pm.dataSources["graphite"].Module)
|
||||
assert.NotEmpty(t, Apps)
|
||||
assert.Equal(t, "public/plugins/test-app/img/logo_large.png", Apps["test-app"].Info.Logos.Large)
|
||||
assert.Equal(t, "public/plugins/test-app/img/screenshot2.png", Apps["test-app"].Info.Screenshots[1].Path)
|
||||
@@ -114,15 +114,15 @@ func TestPluginManager_Init(t *testing.T) {
|
||||
require.Empty(t, pm.scanningErrors)
|
||||
|
||||
const pluginID = "test"
|
||||
assert.NotNil(t, Plugins[pluginID])
|
||||
assert.Equal(t, "datasource", Plugins[pluginID].Type)
|
||||
assert.Equal(t, "Test", Plugins[pluginID].Name)
|
||||
assert.Equal(t, pluginID, Plugins[pluginID].Id)
|
||||
assert.Equal(t, "1.0.0", Plugins[pluginID].Info.Version)
|
||||
assert.Equal(t, plugins.PluginSignatureValid, Plugins[pluginID].Signature)
|
||||
assert.Equal(t, plugins.GrafanaType, Plugins[pluginID].SignatureType)
|
||||
assert.Equal(t, "Grafana Labs", Plugins[pluginID].SignatureOrg)
|
||||
assert.False(t, Plugins[pluginID].IsCorePlugin)
|
||||
assert.NotNil(t, pm.plugins[pluginID])
|
||||
assert.Equal(t, "datasource", pm.plugins[pluginID].Type)
|
||||
assert.Equal(t, "Test", pm.plugins[pluginID].Name)
|
||||
assert.Equal(t, pluginID, pm.plugins[pluginID].Id)
|
||||
assert.Equal(t, "1.0.0", pm.plugins[pluginID].Info.Version)
|
||||
assert.Equal(t, plugins.PluginSignatureValid, pm.plugins[pluginID].Signature)
|
||||
assert.Equal(t, plugins.GrafanaType, pm.plugins[pluginID].SignatureType)
|
||||
assert.Equal(t, "Grafana Labs", pm.plugins[pluginID].SignatureOrg)
|
||||
assert.False(t, pm.plugins[pluginID].IsCorePlugin)
|
||||
})
|
||||
|
||||
t.Run("With back-end plugin with invalid v2 private signature (mismatched root URL)", func(t *testing.T) {
|
||||
@@ -139,7 +139,7 @@ func TestPluginManager_Init(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, []error{fmt.Errorf(`plugin "test" has an invalid signature`)}, pm.scanningErrors)
|
||||
assert.Nil(t, Plugins[("test")])
|
||||
assert.Nil(t, pm.plugins[("test")])
|
||||
})
|
||||
|
||||
t.Run("With back-end plugin with valid v2 private signature", func(t *testing.T) {
|
||||
@@ -157,15 +157,15 @@ func TestPluginManager_Init(t *testing.T) {
|
||||
require.Empty(t, pm.scanningErrors)
|
||||
|
||||
const pluginID = "test"
|
||||
assert.NotNil(t, Plugins[pluginID])
|
||||
assert.Equal(t, "datasource", Plugins[pluginID].Type)
|
||||
assert.Equal(t, "Test", Plugins[pluginID].Name)
|
||||
assert.Equal(t, pluginID, Plugins[pluginID].Id)
|
||||
assert.Equal(t, "1.0.0", Plugins[pluginID].Info.Version)
|
||||
assert.Equal(t, plugins.PluginSignatureValid, Plugins[pluginID].Signature)
|
||||
assert.Equal(t, plugins.PrivateType, Plugins[pluginID].SignatureType)
|
||||
assert.Equal(t, "Will Browne", Plugins[pluginID].SignatureOrg)
|
||||
assert.False(t, Plugins[pluginID].IsCorePlugin)
|
||||
assert.NotNil(t, pm.plugins[pluginID])
|
||||
assert.Equal(t, "datasource", pm.plugins[pluginID].Type)
|
||||
assert.Equal(t, "Test", pm.plugins[pluginID].Name)
|
||||
assert.Equal(t, pluginID, pm.plugins[pluginID].Id)
|
||||
assert.Equal(t, "1.0.0", pm.plugins[pluginID].Info.Version)
|
||||
assert.Equal(t, plugins.PluginSignatureValid, pm.plugins[pluginID].Signature)
|
||||
assert.Equal(t, plugins.PrivateType, pm.plugins[pluginID].SignatureType)
|
||||
assert.Equal(t, "Will Browne", pm.plugins[pluginID].SignatureOrg)
|
||||
assert.False(t, pm.plugins[pluginID].IsCorePlugin)
|
||||
})
|
||||
|
||||
t.Run("With back-end plugin with modified v2 signature (missing file from plugin dir)", func(t *testing.T) {
|
||||
@@ -181,7 +181,7 @@ func TestPluginManager_Init(t *testing.T) {
|
||||
err := pm.Init()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []error{fmt.Errorf(`plugin "test"'s signature has been modified`)}, pm.scanningErrors)
|
||||
assert.Nil(t, Plugins[("test")])
|
||||
assert.Nil(t, pm.plugins[("test")])
|
||||
})
|
||||
|
||||
t.Run("With back-end plugin with modified v2 signature (unaccounted file in plugin dir)", func(t *testing.T) {
|
||||
@@ -197,7 +197,7 @@ func TestPluginManager_Init(t *testing.T) {
|
||||
err := pm.Init()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []error{fmt.Errorf(`plugin "test"'s signature has been modified`)}, pm.scanningErrors)
|
||||
assert.Nil(t, Plugins[("test")])
|
||||
assert.Nil(t, pm.plugins[("test")])
|
||||
})
|
||||
}
|
||||
|
||||
@@ -260,6 +260,7 @@ func createManager(t *testing.T, cbs ...func(*PluginManager)) *PluginManager {
|
||||
StaticRootPath: staticRootPath,
|
||||
},
|
||||
BackendPluginManager: &fakeBackendPluginManager{},
|
||||
dataSources: map[string]*plugins.DataSourcePlugin{},
|
||||
}
|
||||
for _, cb := range cbs {
|
||||
cb(pm)
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
)
|
||||
|
||||
func (pm *PluginManager) GetPluginSettings(orgId int64) (map[string]*models.PluginSettingInfoDTO, error) {
|
||||
query := models.GetPluginSettingsQuery{OrgId: orgId}
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
func (pm *PluginManager) GetPluginSettings(orgID int64) (map[string]*models.PluginSettingInfoDTO, error) {
|
||||
pluginSettings, err := pm.SQLStore.GetPluginSettings(orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pluginMap := make(map[string]*models.PluginSettingInfoDTO)
|
||||
for _, plug := range query.Result {
|
||||
for _, plug := range pluginSettings {
|
||||
pluginMap[plug.PluginId] = plug
|
||||
}
|
||||
|
||||
for _, pluginDef := range Plugins {
|
||||
for _, pluginDef := range pm.plugins {
|
||||
// ignore entries that exists
|
||||
if _, ok := pluginMap[pluginDef.Id]; ok {
|
||||
continue
|
||||
@@ -26,7 +25,7 @@ func (pm *PluginManager) GetPluginSettings(orgId int64) (map[string]*models.Plug
|
||||
// default to enabled true
|
||||
opt := &models.PluginSettingInfoDTO{
|
||||
PluginId: pluginDef.Id,
|
||||
OrgId: orgId,
|
||||
OrgId: orgID,
|
||||
Enabled: true,
|
||||
}
|
||||
|
||||
@@ -72,7 +71,7 @@ func (pm *PluginManager) GetEnabledPlugins(orgID int64) (*plugins.EnabledPlugins
|
||||
}
|
||||
|
||||
// add all plugins that are not part of an App.
|
||||
for dsID, ds := range DataSources {
|
||||
for dsID, ds := range pm.dataSources {
|
||||
if _, exists := pluginSettingMap[ds.Id]; exists {
|
||||
enabledPlugins.DataSources[dsID] = ds
|
||||
}
|
||||
|
||||
@@ -16,19 +16,19 @@ var (
|
||||
httpClient = http.Client{Timeout: 10 * time.Second}
|
||||
)
|
||||
|
||||
type GrafanaNetPlugin struct {
|
||||
type grafanaNetPlugin struct {
|
||||
Slug string `json:"slug"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type GithubLatest struct {
|
||||
type gitHubLatest struct {
|
||||
Stable string `json:"stable"`
|
||||
Testing string `json:"testing"`
|
||||
}
|
||||
|
||||
func getAllExternalPluginSlugs() string {
|
||||
func (pm *PluginManager) getAllExternalPluginSlugs() string {
|
||||
var result []string
|
||||
for _, plug := range Plugins {
|
||||
for _, plug := range pm.plugins {
|
||||
if plug.IsCorePlugin {
|
||||
continue
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func (pm *PluginManager) checkForUpdates() {
|
||||
|
||||
pm.log.Debug("Checking for updates")
|
||||
|
||||
pluginSlugs := getAllExternalPluginSlugs()
|
||||
pluginSlugs := pm.getAllExternalPluginSlugs()
|
||||
resp, err := httpClient.Get("https://grafana.com/api/plugins/versioncheck?slugIn=" + pluginSlugs + "&grafanaVersion=" + setting.BuildVersion)
|
||||
if err != nil {
|
||||
log.Tracef("Failed to get plugins repo from grafana.com, %v", err.Error())
|
||||
@@ -64,14 +64,14 @@ func (pm *PluginManager) checkForUpdates() {
|
||||
return
|
||||
}
|
||||
|
||||
gNetPlugins := []GrafanaNetPlugin{}
|
||||
gNetPlugins := []grafanaNetPlugin{}
|
||||
err = json.Unmarshal(body, &gNetPlugins)
|
||||
if err != nil {
|
||||
log.Tracef("Failed to unmarshal plugin repo, reading response from grafana.com, %v", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, plug := range Plugins {
|
||||
for _, plug := range pm.plugins {
|
||||
for _, gplug := range gNetPlugins {
|
||||
if gplug.Slug == plug.Id {
|
||||
plug.GrafanaNetVersion = gplug.Version
|
||||
@@ -104,24 +104,24 @@ func (pm *PluginManager) checkForUpdates() {
|
||||
return
|
||||
}
|
||||
|
||||
var githubLatest GithubLatest
|
||||
err = json.Unmarshal(body, &githubLatest)
|
||||
var latest gitHubLatest
|
||||
err = json.Unmarshal(body, &latest)
|
||||
if err != nil {
|
||||
log.Tracef("Failed to unmarshal github.com latest, reading response from github.com: %v", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(setting.BuildVersion, "-") {
|
||||
pm.GrafanaLatestVersion = githubLatest.Testing
|
||||
pm.GrafanaHasUpdate = !strings.HasPrefix(setting.BuildVersion, githubLatest.Testing)
|
||||
pm.grafanaLatestVersion = latest.Testing
|
||||
pm.grafanaHasUpdate = !strings.HasPrefix(setting.BuildVersion, latest.Testing)
|
||||
} else {
|
||||
pm.GrafanaLatestVersion = githubLatest.Stable
|
||||
pm.GrafanaHasUpdate = githubLatest.Stable != setting.BuildVersion
|
||||
pm.grafanaLatestVersion = latest.Stable
|
||||
pm.grafanaHasUpdate = latest.Stable != setting.BuildVersion
|
||||
}
|
||||
|
||||
currVersion, err1 := version.NewVersion(setting.BuildVersion)
|
||||
latestVersion, err2 := version.NewVersion(pm.GrafanaLatestVersion)
|
||||
latestVersion, err2 := version.NewVersion(pm.grafanaLatestVersion)
|
||||
if err1 == nil && err2 == nil {
|
||||
pm.GrafanaHasUpdate = currVersion.LessThan(latestVersion)
|
||||
pm.grafanaHasUpdate = currVersion.LessThan(latestVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
|
||||
@@ -22,6 +23,7 @@ func init() {
|
||||
type Service struct {
|
||||
DataService *tsdb.Service `inject:""`
|
||||
PluginManager *manager.PluginManager `inject:""`
|
||||
SQLStore *sqlstore.SQLStore `inject:""`
|
||||
|
||||
logger log.Logger
|
||||
}
|
||||
@@ -40,19 +42,19 @@ func (s *Service) Run(ctx context.Context) error {
|
||||
func (s *Service) updateAppDashboards() {
|
||||
s.logger.Debug("Looking for app dashboard updates")
|
||||
|
||||
query := models.GetPluginSettingsQuery{OrgId: 0}
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
pluginSettings, err := s.SQLStore.GetPluginSettings(0)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get all plugin settings", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, pluginSetting := range query.Result {
|
||||
for _, pluginSetting := range pluginSettings {
|
||||
// ignore disabled plugins
|
||||
if !pluginSetting.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
if pluginDef, exists := manager.Plugins[pluginSetting.PluginId]; exists {
|
||||
if pluginDef := s.PluginManager.GetPlugin(pluginSetting.PluginId); pluginDef != nil {
|
||||
if pluginDef.Info.Version != pluginSetting.PluginVersion {
|
||||
s.syncPluginDashboards(pluginDef, pluginSetting.OrgId)
|
||||
}
|
||||
@@ -117,7 +119,7 @@ func (s *Service) handlePluginStateChanged(event *models.PluginStateChangedEvent
|
||||
s.logger.Info("Plugin state changed", "pluginId", event.PluginId, "enabled", event.Enabled)
|
||||
|
||||
if event.Enabled {
|
||||
s.syncPluginDashboards(manager.Plugins[event.PluginId], event.OrgId)
|
||||
s.syncPluginDashboards(s.PluginManager.GetPlugin(event.PluginId), event.OrgId)
|
||||
} else {
|
||||
query := models.GetDashboardsByPluginIdQuery{PluginId: event.PluginId, OrgId: event.OrgId}
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user