diff --git a/pkg/api/plugin_resource_test.go b/pkg/api/plugin_resource_test.go index 5b5944c8d3f..90de2bcaebc 100644 --- a/pkg/api/plugin_resource_test.go +++ b/pkg/api/plugin_resource_test.go @@ -25,6 +25,7 @@ import ( "github.com/grafana/grafana/pkg/plugins/manager/loader/assetpath" "github.com/grafana/grafana/pkg/plugins/manager/registry" "github.com/grafana/grafana/pkg/plugins/manager/signature" + "github.com/grafana/grafana/pkg/plugins/manager/sources" "github.com/grafana/grafana/pkg/plugins/manager/store" "github.com/grafana/grafana/pkg/plugins/plugincontext" "github.com/grafana/grafana/pkg/plugins/pluginscdn" @@ -60,7 +61,8 @@ func TestCallResource(t *testing.T) { cdn := pluginscdn.ProvideService(pCfg) l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg), reg, provider.ProvideService(coreRegistry), fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn)) - ps, err := store.ProvideService(cfg, pCfg, reg, l) + srcs := sources.ProvideService(cfg, pCfg) + ps, err := store.ProvideService(reg, srcs, l) require.NoError(t, err) pcp := plugincontext.ProvideService(localcache.ProvideService(), ps, &datasources.FakeCacheService{}, &datasources.FakeDataSourceService{}, pluginSettings.ProvideService(db.InitTestDB(t), nil)) diff --git a/pkg/plugins/manager/fakes/fakes.go b/pkg/plugins/manager/fakes/fakes.go index a886938c1b2..c408c1aa63b 100644 --- a/pkg/plugins/manager/fakes/fakes.go +++ b/pkg/plugins/manager/fakes/fakes.go @@ -350,3 +350,14 @@ func NewFakeRoleRegistry() *FakeRoleRegistry { func (f *FakeRoleRegistry) DeclarePluginRoles(_ context.Context, _ string, _ string, _ []plugins.RoleRegistration) error { return f.ExpectedErr } + +type FakeSources struct { + ListFunc func(_ context.Context) []plugins.PluginSource +} + +func (s *FakeSources) List(ctx context.Context) []plugins.PluginSource { + if s.ListFunc != nil { + return s.ListFunc(ctx) + } + return []plugins.PluginSource{} +} diff --git a/pkg/plugins/manager/manager_integration_test.go b/pkg/plugins/manager/manager_integration_test.go index 96de51f2ca1..acd410f8568 100644 --- a/pkg/plugins/manager/manager_integration_test.go +++ b/pkg/plugins/manager/manager_integration_test.go @@ -29,6 +29,7 @@ import ( "github.com/grafana/grafana/pkg/plugins/manager/loader" "github.com/grafana/grafana/pkg/plugins/manager/registry" "github.com/grafana/grafana/pkg/plugins/manager/signature" + "github.com/grafana/grafana/pkg/plugins/manager/sources" "github.com/grafana/grafana/pkg/plugins/manager/store" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/licensing" @@ -119,7 +120,8 @@ func TestIntegrationPluginManager(t *testing.T) { l := loader.ProvideService(pCfg, lic, signature.NewUnsignedAuthorizer(pCfg), reg, provider.ProvideService(coreRegistry), fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn)) - ps, err := store.ProvideService(cfg, pCfg, reg, l) + srcs := sources.ProvideService(cfg, pCfg) + ps, err := store.ProvideService(reg, srcs, l) require.NoError(t, err) ctx := context.Background() diff --git a/pkg/plugins/manager/sources/ifaces.go b/pkg/plugins/manager/sources/ifaces.go new file mode 100644 index 00000000000..129e0160c2b --- /dev/null +++ b/pkg/plugins/manager/sources/ifaces.go @@ -0,0 +1,11 @@ +package sources + +import ( + "context" + + "github.com/grafana/grafana/pkg/plugins" +) + +type Resolver interface { + List(context.Context) []plugins.PluginSource +} diff --git a/pkg/plugins/manager/sources/sources.go b/pkg/plugins/manager/sources/sources.go new file mode 100644 index 00000000000..1e228ee45b0 --- /dev/null +++ b/pkg/plugins/manager/sources/sources.go @@ -0,0 +1,53 @@ +package sources + +import ( + "context" + "path/filepath" + + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/plugins/config" + "github.com/grafana/grafana/pkg/setting" +) + +type Service struct { + gCfg *setting.Cfg + cfg *config.Cfg + log log.Logger +} + +func ProvideService(gCfg *setting.Cfg, cfg *config.Cfg) *Service { + return &Service{ + gCfg: gCfg, + cfg: cfg, + log: log.New("plugin.sources"), + } +} + +func (s *Service) List(_ context.Context) []plugins.PluginSource { + return []plugins.PluginSource{ + {Class: plugins.Core, Paths: corePluginPaths(s.gCfg.StaticRootPath)}, + {Class: plugins.Bundled, Paths: []string{s.gCfg.BundledPluginsPath}}, + {Class: plugins.External, Paths: append([]string{s.cfg.PluginsPath}, pluginFSPaths(s.cfg.PluginSettings)...)}, + } +} + +// corePluginPaths provides a list of the Core plugin file system paths +func corePluginPaths(staticRootPath string) []string { + datasourcePaths := filepath.Join(staticRootPath, "app/plugins/datasource") + panelsPath := filepath.Join(staticRootPath, "app/plugins/panel") + return []string{datasourcePaths, panelsPath} +} + +// pluginSettingPaths provides plugin file system paths defined in cfg.PluginSettings +func pluginFSPaths(ps map[string]map[string]string) []string { + var pluginSettingDirs []string + for _, s := range ps { + path, exists := s["path"] + if !exists || path == "" { + continue + } + pluginSettingDirs = append(pluginSettingDirs, path) + } + return pluginSettingDirs +} diff --git a/pkg/plugins/manager/sources/sources_test.go b/pkg/plugins/manager/sources/sources_test.go new file mode 100644 index 00000000000..1dc9f00fa08 --- /dev/null +++ b/pkg/plugins/manager/sources/sources_test.go @@ -0,0 +1,41 @@ +package sources + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/plugins/config" + "github.com/grafana/grafana/pkg/setting" +) + +func TestSources_List(t *testing.T) { + t.Run("Plugin sources are added in order", func(t *testing.T) { + cfg := &setting.Cfg{ + BundledPluginsPath: "path1", + } + pCfg := &config.Cfg{ + PluginsPath: "path2", + PluginSettings: setting.PluginSettings{ + "foo": map[string]string{ + "path": "path3", + }, + "bar": map[string]string{ + "url": "https://grafana.plugin", + }, + }, + } + + s := ProvideService(cfg, pCfg) + srcs := s.List(context.Background()) + + expected := []plugins.PluginSource{ + {Class: plugins.Core, Paths: []string{"app/plugins/datasource", "app/plugins/panel"}}, + {Class: plugins.Bundled, Paths: []string{"path1"}}, + {Class: plugins.External, Paths: []string{"path2", "path3"}}, + } + require.Equal(t, expected, srcs) + }) +} diff --git a/pkg/plugins/manager/store/store.go b/pkg/plugins/manager/store/store.go index f253b5682e9..872a70a4866 100644 --- a/pkg/plugins/manager/store/store.go +++ b/pkg/plugins/manager/store/store.go @@ -2,14 +2,12 @@ package store import ( "context" - "path/filepath" "sort" "github.com/grafana/grafana/pkg/plugins" - "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/manager/loader" "github.com/grafana/grafana/pkg/plugins/manager/registry" - "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/plugins/manager/sources" ) var _ plugins.Store = (*Service)(nil) @@ -18,9 +16,9 @@ type Service struct { pluginRegistry registry.Service } -func ProvideService(gCfg *setting.Cfg, cfg *config.Cfg, pluginRegistry registry.Service, +func ProvideService(pluginRegistry registry.Service, pluginSources sources.Resolver, pluginLoader loader.Service) (*Service, error) { - for _, ps := range pluginSources(gCfg, cfg) { + for _, ps := range pluginSources.List(context.Background()) { if _, err := pluginLoader.Load(context.Background(), ps.Class, ps.Paths); err != nil { return nil, err } @@ -119,31 +117,3 @@ func (s *Service) Routes() []*plugins.StaticRoute { } return staticRoutes } - -func pluginSources(gCfg *setting.Cfg, cfg *config.Cfg) []plugins.PluginSource { - return []plugins.PluginSource{ - {Class: plugins.Core, Paths: corePluginPaths(gCfg.StaticRootPath)}, - {Class: plugins.Bundled, Paths: []string{gCfg.BundledPluginsPath}}, - {Class: plugins.External, Paths: append([]string{cfg.PluginsPath}, pluginSettingPaths(cfg.PluginSettings)...)}, - } -} - -// corePluginPaths provides a list of the Core plugin paths which need to be scanned on init() -func corePluginPaths(staticRootPath string) []string { - datasourcePaths := filepath.Join(staticRootPath, "app/plugins/datasource") - panelsPath := filepath.Join(staticRootPath, "app/plugins/panel") - return []string{datasourcePaths, panelsPath} -} - -// pluginSettingPaths provides a plugin paths defined in cfg.PluginSettings which need to be scanned on init() -func pluginSettingPaths(ps map[string]map[string]string) []string { - var pluginSettingDirs []string - for _, s := range ps { - path, exists := s["path"] - if !exists || path == "" { - continue - } - pluginSettingDirs = append(pluginSettingDirs, path) - } - return pluginSettingDirs -} diff --git a/pkg/plugins/manager/store/store_test.go b/pkg/plugins/manager/store/store_test.go index a0c2a36f1d8..906c7db7e68 100644 --- a/pkg/plugins/manager/store/store_test.go +++ b/pkg/plugins/manager/store/store_test.go @@ -8,9 +8,7 @@ import ( "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/backendplugin" - "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/manager/fakes" - "github.com/grafana/grafana/pkg/setting" ) func TestStore_ProvideService(t *testing.T) { @@ -22,21 +20,23 @@ func TestStore_ProvideService(t *testing.T) { return nil, nil }, } - cfg := &setting.Cfg{ - BundledPluginsPath: "path1", - } - pCfg := &config.Cfg{ - PluginsPath: "path2", - PluginSettings: setting.PluginSettings{ - "blah": map[string]string{ - "path": "path3", - }, - }, - } - _, err := ProvideService(cfg, pCfg, fakes.NewFakePluginRegistry(), l) + srcs := &fakes.FakeSources{ListFunc: func(_ context.Context) []plugins.PluginSource { + return []plugins.PluginSource{ + { + Class: plugins.Bundled, + Paths: []string{"path1"}, + }, + { + Class: plugins.External, + Paths: []string{"path2", "path3"}, + }, + } + }} + + _, err := ProvideService(fakes.NewFakePluginRegistry(), srcs, l) require.NoError(t, err) - require.Equal(t, []string{"app/plugins/datasource", "app/plugins/panel", "path1", "path2", "path3"}, addedPaths) + require.Equal(t, []string{"path1", "path2", "path3"}, addedPaths) }) } diff --git a/pkg/services/pluginsintegration/pluginsintegration.go b/pkg/services/pluginsintegration/pluginsintegration.go index ba9937438ab..fa1f53c2056 100644 --- a/pkg/services/pluginsintegration/pluginsintegration.go +++ b/pkg/services/pluginsintegration/pluginsintegration.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/plugins/manager/process" "github.com/grafana/grafana/pkg/plugins/manager/registry" "github.com/grafana/grafana/pkg/plugins/manager/signature" + "github.com/grafana/grafana/pkg/plugins/manager/sources" "github.com/grafana/grafana/pkg/plugins/manager/store" "github.com/grafana/grafana/pkg/plugins/plugincontext" "github.com/grafana/grafana/pkg/plugins/pluginscdn" @@ -50,6 +51,8 @@ var WireSet = wire.NewSet( plugincontext.ProvideService, licensing.ProvideLicensing, wire.Bind(new(plugins.Licensing), new(*licensing.Service)), + wire.Bind(new(sources.Resolver), new(*sources.Service)), + sources.ProvideService, ) // WireExtensionSet provides a wire.ProviderSet of plugin providers that can be