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

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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"},
},
}

View File

@@ -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}
}

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)
}

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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 {