diff --git a/pkg/api/plugin_resource_test.go b/pkg/api/plugin_resource_test.go index b0218997446..f6ceff36c0b 100644 --- a/pkg/api/plugin_resource_test.go +++ b/pkg/api/plugin_resource_test.go @@ -23,6 +23,7 @@ import ( "github.com/grafana/grafana/pkg/plugins/manager/fakes" "github.com/grafana/grafana/pkg/plugins/manager/loader" "github.com/grafana/grafana/pkg/plugins/manager/loader/assetpath" + "github.com/grafana/grafana/pkg/plugins/manager/loader/finder" "github.com/grafana/grafana/pkg/plugins/manager/registry" "github.com/grafana/grafana/pkg/plugins/manager/signature" "github.com/grafana/grafana/pkg/plugins/manager/sources" @@ -60,7 +61,7 @@ func TestCallResource(t *testing.T) { reg := registry.ProvideService() cdn := pluginscdn.ProvideService(pCfg) l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg), - reg, provider.ProvideService(coreRegistry), fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn)) + reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(), fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn)) srcs := sources.ProvideService(cfg, pCfg) ps, err := store.ProvideService(reg, srcs, l) require.NoError(t, err) diff --git a/pkg/plugins/ifaces.go b/pkg/plugins/ifaces.go index 0f17544da52..a9786c9c80d 100644 --- a/pkg/plugins/ifaces.go +++ b/pkg/plugins/ifaces.go @@ -24,9 +24,10 @@ type Installer interface { Remove(ctx context.Context, pluginID string) error } -type PluginSource struct { - Class Class - Paths []string +type PluginSource interface { + PluginClass(ctx context.Context) Class + PluginURIs(ctx context.Context) []string + DefaultSignature(ctx context.Context) (Signature, bool) } type CompatOpts struct { diff --git a/pkg/plugins/localfiles.go b/pkg/plugins/localfiles.go index 805e62bcb4d..a805ae5d43f 100644 --- a/pkg/plugins/localfiles.go +++ b/pkg/plugins/localfiles.go @@ -1,6 +1,7 @@ package plugins import ( + "errors" "io/fs" "os" "path/filepath" @@ -40,7 +41,14 @@ func (f LocalFS) Open(name string) (fs.File, error) { if kv.f != nil { return kv.f, nil } - return os.Open(kv.path) + file, err := os.Open(kv.path) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return nil, ErrFileNotExist + } + return nil, ErrPluginFileRead + } + return file, nil } return nil, ErrFileNotExist } @@ -70,14 +78,24 @@ type LocalFile struct { } func (p *LocalFile) Stat() (fs.FileInfo, error) { - return os.Stat(p.path) + fi, err := os.Stat(p.path) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return nil, ErrFileNotExist + } + return nil, ErrPluginFileRead + } + return fi, nil } func (p *LocalFile) Read(bytes []byte) (int, error) { var err error p.f, err = os.Open(p.path) if err != nil { - return 0, err + if errors.Is(err, fs.ErrNotExist) { + return 0, ErrFileNotExist + } + return 0, ErrPluginFileRead } return p.f.Read(bytes) } diff --git a/pkg/plugins/manager/fakes/fakes.go b/pkg/plugins/manager/fakes/fakes.go index e1d765dd4b6..a10a36bedc7 100644 --- a/pkg/plugins/manager/fakes/fakes.go +++ b/pkg/plugins/manager/fakes/fakes.go @@ -37,13 +37,13 @@ func (i *FakePluginInstaller) Remove(ctx context.Context, pluginID string) error } type FakeLoader struct { - LoadFunc func(_ context.Context, _ plugins.Class, paths []string) ([]*plugins.Plugin, error) + LoadFunc func(_ context.Context, _ plugins.PluginSource) ([]*plugins.Plugin, error) UnloadFunc func(_ context.Context, _ string) error } -func (l *FakeLoader) Load(ctx context.Context, class plugins.Class, paths []string) ([]*plugins.Plugin, error) { +func (l *FakeLoader) Load(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) { if l.LoadFunc != nil { - return l.LoadFunc(ctx, class, paths) + return l.LoadFunc(ctx, src) } return nil, nil } @@ -381,13 +381,40 @@ func (f *FakePluginFiles) Files() []string { return []string{} } -type FakeSources struct { +type FakeSourceRegistry struct { ListFunc func(_ context.Context) []plugins.PluginSource } -func (s *FakeSources) List(ctx context.Context) []plugins.PluginSource { +func (s *FakeSourceRegistry) List(ctx context.Context) []plugins.PluginSource { if s.ListFunc != nil { return s.ListFunc(ctx) } return []plugins.PluginSource{} } + +type FakePluginSource struct { + PluginClassFunc func(ctx context.Context) plugins.Class + PluginURIsFunc func(ctx context.Context) []string + DefaultSignatureFunc func(ctx context.Context) (plugins.Signature, bool) +} + +func (s *FakePluginSource) PluginClass(ctx context.Context) plugins.Class { + if s.PluginClassFunc != nil { + return s.PluginClassFunc(ctx) + } + return "" +} + +func (s *FakePluginSource) PluginURIs(ctx context.Context) []string { + if s.PluginURIsFunc != nil { + return s.PluginURIsFunc(ctx) + } + return []string{} +} + +func (s *FakePluginSource) DefaultSignature(ctx context.Context) (plugins.Signature, bool) { + if s.DefaultSignatureFunc != nil { + return s.DefaultSignatureFunc(ctx) + } + return plugins.Signature{}, false +} diff --git a/pkg/plugins/manager/installer.go b/pkg/plugins/manager/installer.go index a5076aa4f9b..d0bc465f175 100644 --- a/pkg/plugins/manager/installer.go +++ b/pkg/plugins/manager/installer.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana/pkg/plugins/log" "github.com/grafana/grafana/pkg/plugins/manager/loader" "github.com/grafana/grafana/pkg/plugins/manager/registry" + "github.com/grafana/grafana/pkg/plugins/manager/sources" "github.com/grafana/grafana/pkg/plugins/repo" "github.com/grafana/grafana/pkg/plugins/storage" ) @@ -118,7 +119,7 @@ func (m *PluginInstaller) Add(ctx context.Context, pluginID, version string, opt pathsToScan = append(pathsToScan, depArchive.Path) } - _, err = m.pluginLoader.Load(ctx, plugins.External, pathsToScan) + _, err = m.pluginLoader.Load(ctx, sources.NewLocalSource(plugins.External, pathsToScan)) if err != nil { m.log.Error("Could not load plugins", "paths", pathsToScan, "err", err) return err diff --git a/pkg/plugins/manager/installer_test.go b/pkg/plugins/manager/installer_test.go index 0b768eac7f8..d9dec824530 100644 --- a/pkg/plugins/manager/installer_test.go +++ b/pkg/plugins/manager/installer_test.go @@ -34,9 +34,9 @@ func TestPluginManager_Add_Remove(t *testing.T) { var loadedPaths []string loader := &fakes.FakeLoader{ - LoadFunc: func(_ context.Context, _ plugins.Class, paths []string) ([]*plugins.Plugin, error) { - loadedPaths = append(loadedPaths, paths...) - require.Equal(t, []string{zipNameV1}, paths) + LoadFunc: func(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) { + loadedPaths = append(loadedPaths, src.PluginURIs(ctx)...) + require.Equal(t, []string{zipNameV1}, src.PluginURIs(ctx)) return []*plugins.Plugin{pluginV1}, nil }, } @@ -96,9 +96,9 @@ func TestPluginManager_Add_Remove(t *testing.T) { mockZipV2 := &zip.ReadCloser{Reader: zip.Reader{File: []*zip.File{{ FileHeader: zip.FileHeader{Name: zipNameV2}, }}}} - loader.LoadFunc = func(_ context.Context, class plugins.Class, paths []string) ([]*plugins.Plugin, error) { - require.Equal(t, plugins.External, class) - require.Equal(t, []string{zipNameV2}, paths) + loader.LoadFunc = func(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) { + require.Equal(t, plugins.External, src.PluginClass(ctx)) + require.Equal(t, []string{zipNameV2}, src.PluginURIs(ctx)) return []*plugins.Plugin{pluginV2}, nil } pluginRepo.GetPluginDownloadOptionsFunc = func(_ context.Context, pluginID, version string, _ repo.CompatOpts) (*repo.PluginDownloadOptions, error) { diff --git a/pkg/plugins/manager/loader/finder/finder.go b/pkg/plugins/manager/loader/finder/finder.go deleted file mode 100644 index 6697e0437c8..00000000000 --- a/pkg/plugins/manager/loader/finder/finder.go +++ /dev/null @@ -1,44 +0,0 @@ -package finder - -import ( - "context" - - "github.com/grafana/grafana/pkg/plugins" - "github.com/grafana/grafana/pkg/plugins/log" -) - -type Service struct { - local *FS - log log.Logger -} - -func NewService() *Service { - logger := log.New("plugin.finder") - return &Service{ - local: newFS(logger), - log: logger, - } -} - -func (f *Service) Find(ctx context.Context, pluginPaths ...string) ([]*plugins.FoundBundle, error) { - if len(pluginPaths) == 0 { - return []*plugins.FoundBundle{}, nil - } - - fbs := make(map[string][]*plugins.FoundBundle) - for _, path := range pluginPaths { - local, err := f.local.Find(ctx, path) - if err != nil { - f.log.Warn("Error occurred when trying to find plugin", "path", path) - continue - } - fbs[path] = local - } - - var found []*plugins.FoundBundle - for _, fb := range fbs { - found = append(found, fb...) - } - - return found, nil -} diff --git a/pkg/plugins/manager/loader/finder/ifaces.go b/pkg/plugins/manager/loader/finder/ifaces.go index cddbb7ecc91..288c907a532 100644 --- a/pkg/plugins/manager/loader/finder/ifaces.go +++ b/pkg/plugins/manager/loader/finder/ifaces.go @@ -7,5 +7,5 @@ import ( ) type Finder interface { - Find(ctx context.Context, uris ...string) ([]*plugins.FoundBundle, error) + Find(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error) } diff --git a/pkg/plugins/manager/loader/finder/fs.go b/pkg/plugins/manager/loader/finder/local.go similarity index 71% rename from pkg/plugins/manager/loader/finder/fs.go rename to pkg/plugins/manager/loader/finder/local.go index 629ddbbcbe9..30752497e09 100644 --- a/pkg/plugins/manager/loader/finder/fs.go +++ b/pkg/plugins/manager/loader/finder/local.go @@ -2,9 +2,9 @@ package finder import ( "context" - "encoding/json" "errors" "fmt" + "io" "os" "path/filepath" "runtime" @@ -13,7 +13,6 @@ import ( "github.com/grafana/grafana/pkg/infra/fs" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/log" - "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/util" ) @@ -24,32 +23,34 @@ var ( ErrInvalidPluginJSONFilePath = errors.New("invalid plugin.json filepath was provided") ) -type FS struct { +type Local struct { log log.Logger } -func newFS(logger log.Logger) *FS { - return &FS{log: logger.New("fs")} +func NewLocalFinder() *Local { + return &Local{ + log: log.New("local.finder"), + } } -func (f *FS) Find(_ context.Context, pluginPaths ...string) ([]*plugins.FoundBundle, error) { - if len(pluginPaths) == 0 { +func (l *Local) Find(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error) { + if len(src.PluginURIs(ctx)) == 0 { return []*plugins.FoundBundle{}, nil } var pluginJSONPaths []string - for _, path := range pluginPaths { + for _, path := range src.PluginURIs(ctx) { exists, err := fs.Exists(path) if err != nil { - f.log.Warn("Skipping finding plugins as an error occurred", "path", path, "err", err) + l.log.Warn("Skipping finding plugins as an error occurred", "path", path, "err", err) continue } if !exists { - f.log.Warn("Skipping finding plugins as directory does not exist", "path", path) + l.log.Warn("Skipping finding plugins as directory does not exist", "path", path) continue } - paths, err := f.getAbsPluginJSONPaths(path) + paths, err := l.getAbsPluginJSONPaths(path) if err != nil { return nil, err } @@ -59,20 +60,20 @@ func (f *FS) Find(_ context.Context, pluginPaths ...string) ([]*plugins.FoundBun // load plugin.json files and map directory to JSON data foundPlugins := make(map[string]plugins.JSONData) for _, pluginJSONPath := range pluginJSONPaths { - plugin, err := f.readPluginJSON(pluginJSONPath) + plugin, err := l.readPluginJSON(pluginJSONPath) if err != nil { - f.log.Warn("Skipping plugin loading as its plugin.json could not be read", "path", pluginJSONPath, "err", err) + l.log.Warn("Skipping plugin loading as its plugin.json could not be read", "path", pluginJSONPath, "err", err) continue } pluginJSONAbsPath, err := filepath.Abs(pluginJSONPath) if err != nil { - f.log.Warn("Skipping plugin loading as absolute plugin.json path could not be calculated", "pluginID", plugin.ID, "err", err) + l.log.Warn("Skipping plugin loading as absolute plugin.json path could not be calculated", "pluginID", plugin.ID, "err", err) continue } if _, dupe := foundPlugins[filepath.Dir(pluginJSONAbsPath)]; dupe { - f.log.Warn("Skipping plugin loading as it's a duplicate", "pluginID", plugin.ID) + l.log.Warn("Skipping plugin loading as it's a duplicate", "pluginID", plugin.ID) continue } foundPlugins[filepath.Dir(pluginJSONAbsPath)] = plugin @@ -121,7 +122,30 @@ func (f *FS) Find(_ context.Context, pluginPaths ...string) ([]*plugins.FoundBun return result, nil } -func (f *FS) getAbsPluginJSONPaths(path string) ([]string, error) { +func (l *Local) readPluginJSON(pluginJSONPath string) (plugins.JSONData, error) { + reader, err := l.readFile(pluginJSONPath) + defer func() { + if reader == nil { + return + } + if err = reader.Close(); err != nil { + l.log.Warn("Failed to close plugin JSON file", "path", pluginJSONPath, "err", err) + } + }() + if err != nil { + l.log.Warn("Skipping plugin loading as its plugin.json could not be read", "path", pluginJSONPath, "err", err) + return plugins.JSONData{}, err + } + plugin, err := ReadPluginJSON(reader) + if err != nil { + l.log.Warn("Skipping plugin loading as its plugin.json could not be read", "path", pluginJSONPath, "err", err) + return plugins.JSONData{}, err + } + + return plugin, nil +} + +func (l *Local) getAbsPluginJSONPaths(path string) ([]string, error) { var pluginJSONPaths []string var err error @@ -134,11 +158,11 @@ func (f *FS) getAbsPluginJSONPaths(path string) ([]string, error) { func(currentPath string, fi os.FileInfo, err error) error { if err != nil { if errors.Is(err, os.ErrNotExist) { - f.log.Error("Couldn't scan directory since it doesn't exist", "pluginDir", path, "err", err) + l.log.Error("Couldn't scan directory since it doesn't exist", "pluginDir", path, "err", err) return nil } if errors.Is(err, os.ErrPermission) { - f.log.Error("Couldn't scan directory due to lack of permissions", "pluginDir", path, "err", err) + l.log.Error("Couldn't scan directory due to lack of permissions", "pluginDir", path, "err", err) return nil } @@ -166,70 +190,6 @@ func (f *FS) getAbsPluginJSONPaths(path string) ([]string, error) { return pluginJSONPaths, nil } -func (f *FS) readPluginJSON(pluginJSONPath string) (plugins.JSONData, error) { - f.log.Debug("Loading plugin", "path", pluginJSONPath) - - if !strings.EqualFold(filepath.Ext(pluginJSONPath), ".json") { - return plugins.JSONData{}, ErrInvalidPluginJSONFilePath - } - - absPluginJSONPath, err := filepath.Abs(pluginJSONPath) - if err != nil { - return plugins.JSONData{}, err - } - - // Wrapping in filepath.Clean to properly handle - // gosec G304 Potential file inclusion via variable rule. - reader, err := os.Open(filepath.Clean(absPluginJSONPath)) - if err != nil { - return plugins.JSONData{}, err - } - defer func() { - if reader == nil { - return - } - if err = reader.Close(); err != nil { - f.log.Warn("Failed to close JSON file", "path", pluginJSONPath, "err", err) - } - }() - - plugin := plugins.JSONData{} - if err = json.NewDecoder(reader).Decode(&plugin); err != nil { - return plugins.JSONData{}, err - } - - if err = validatePluginJSON(plugin); err != nil { - return plugins.JSONData{}, err - } - - if plugin.ID == "grafana-piechart-panel" { - plugin.Name = "Pie Chart (old)" - } - - if len(plugin.Dependencies.Plugins) == 0 { - plugin.Dependencies.Plugins = []plugins.Dependency{} - } - - if plugin.Dependencies.GrafanaVersion == "" { - plugin.Dependencies.GrafanaVersion = "*" - } - - for _, include := range plugin.Includes { - if include.Role == "" { - include.Role = org.RoleViewer - } - } - - return plugin, nil -} - -func validatePluginJSON(data plugins.JSONData) error { - if data.ID == "" || !data.Type.IsValid() { - return ErrInvalidPluginJSON - } - return nil -} - func collectFilesWithin(dir string) (map[string]struct{}, error) { files := map[string]struct{}{} err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { @@ -284,3 +244,20 @@ func collectFilesWithin(dir string) (map[string]struct{}, error) { return files, err } + +func (l *Local) readFile(pluginJSONPath string) (io.ReadCloser, error) { + l.log.Debug("Loading plugin", "path", pluginJSONPath) + + if !strings.EqualFold(filepath.Ext(pluginJSONPath), ".json") { + return nil, ErrInvalidPluginJSONFilePath + } + + absPluginJSONPath, err := filepath.Abs(pluginJSONPath) + if err != nil { + return nil, err + } + + // Wrapping in filepath.Clean to properly handle + // gosec G304 Potential file inclusion via variable rule. + return os.Open(filepath.Clean(absPluginJSONPath)) +} diff --git a/pkg/plugins/manager/loader/finder/fs_test.go b/pkg/plugins/manager/loader/finder/local_test.go similarity index 95% rename from pkg/plugins/manager/loader/finder/fs_test.go rename to pkg/plugins/manager/loader/finder/local_test.go index 1954d41c146..f1d240da749 100644 --- a/pkg/plugins/manager/loader/finder/fs_test.go +++ b/pkg/plugins/manager/loader/finder/local_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/plugins" - "github.com/grafana/grafana/pkg/plugins/log" + "github.com/grafana/grafana/pkg/plugins/manager/fakes" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/util" ) @@ -278,8 +278,12 @@ func TestFinder_Find(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - f := newFS(log.NewTestLogger()) - pluginBundles, err := f.Find(context.Background(), tc.pluginDirs...) + f := NewLocalFinder() + pluginBundles, err := f.Find(context.Background(), &fakes.FakePluginSource{ + PluginURIsFunc: func(ctx context.Context) []string { + return tc.pluginDirs + }, + }) if (err != nil) && !errors.Is(err, tc.err) { t.Errorf("Find() error = %v, expected error %v", err, tc.err) return @@ -307,7 +311,7 @@ func TestFinder_getAbsPluginJSONPaths(t *testing.T) { walk = origWalk }) - finder := newFS(log.NewTestLogger()) + finder := NewLocalFinder() paths, err := finder.getAbsPluginJSONPaths("test") require.NoError(t, err) require.Empty(t, paths) @@ -322,7 +326,7 @@ func TestFinder_getAbsPluginJSONPaths(t *testing.T) { walk = origWalk }) - finder := newFS(log.NewTestLogger()) + finder := NewLocalFinder() paths, err := finder.getAbsPluginJSONPaths("test") require.NoError(t, err) require.Empty(t, paths) @@ -337,7 +341,7 @@ func TestFinder_getAbsPluginJSONPaths(t *testing.T) { walk = origWalk }) - finder := newFS(log.NewTestLogger()) + finder := NewLocalFinder() paths, err := finder.getAbsPluginJSONPaths("test") require.Error(t, err) require.Empty(t, paths) @@ -396,7 +400,7 @@ func TestFinder_readPluginJSON(t *testing.T) { name string pluginPath string expected plugins.JSONData - failed bool + err error }{ { name: "Valid plugin", @@ -444,27 +448,23 @@ func TestFinder_readPluginJSON(t *testing.T) { }, { name: "Invalid plugin JSON", - pluginPath: "../testdata/invalid-plugin-json/plugin.json", - failed: true, - }, - { - name: "Non-existing JSON file", - pluginPath: "nonExistingFile.json", - failed: true, + pluginPath: "../../testdata/invalid-plugin-json/plugin.json", + err: ErrInvalidPluginJSON, }, } - f := newFS(log.NewTestLogger()) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := f.readPluginJSON(tt.pluginPath) - if (err != nil) && !tt.failed { - t.Errorf("readPluginJSON() error = %v, failed %v", err, tt.failed) - return + reader, err := os.Open(tt.pluginPath) + require.NoError(t, err) + got, err := ReadPluginJSON(reader) + if tt.err != nil { + require.ErrorIs(t, err, tt.err) } if !cmp.Equal(got, tt.expected) { t.Errorf("Unexpected pluginJSONData: %v", cmp.Diff(got, tt.expected)) } + require.NoError(t, reader.Close()) }) } } diff --git a/pkg/plugins/manager/loader/finder/util.go b/pkg/plugins/manager/loader/finder/util.go new file mode 100644 index 00000000000..9502a408be2 --- /dev/null +++ b/pkg/plugins/manager/loader/finder/util.go @@ -0,0 +1,47 @@ +package finder + +import ( + "encoding/json" + "io" + + "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/services/org" +) + +func ReadPluginJSON(reader io.Reader) (plugins.JSONData, error) { + plugin := plugins.JSONData{} + if err := json.NewDecoder(reader).Decode(&plugin); err != nil { + return plugins.JSONData{}, err + } + + if err := validatePluginJSON(plugin); err != nil { + return plugins.JSONData{}, err + } + + if plugin.ID == "grafana-piechart-panel" { + plugin.Name = "Pie Chart (old)" + } + + if len(plugin.Dependencies.Plugins) == 0 { + plugin.Dependencies.Plugins = []plugins.Dependency{} + } + + if plugin.Dependencies.GrafanaVersion == "" { + plugin.Dependencies.GrafanaVersion = "*" + } + + for _, include := range plugin.Includes { + if include.Role == "" { + include.Role = org.RoleViewer + } + } + + return plugin, nil +} + +func validatePluginJSON(data plugins.JSONData) error { + if data.ID == "" || !data.Type.IsValid() { + return ErrInvalidPluginJSON + } + return nil +} diff --git a/pkg/plugins/manager/loader/ifaces.go b/pkg/plugins/manager/loader/ifaces.go index fde77628e31..c07609ed722 100644 --- a/pkg/plugins/manager/loader/ifaces.go +++ b/pkg/plugins/manager/loader/ifaces.go @@ -9,7 +9,7 @@ import ( // Service is responsible for loading plugins from the file system. type Service interface { // Load will return a list of plugins found in the provided file system paths. - Load(ctx context.Context, class plugins.Class, paths []string) ([]*plugins.Plugin, error) + Load(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) // Unload will unload a specified plugin from the file system. Unload(ctx context.Context, pluginID string) error } diff --git a/pkg/plugins/manager/loader/loader.go b/pkg/plugins/manager/loader/loader.go index 937091955a6..adfa11d1742 100644 --- a/pkg/plugins/manager/loader/loader.go +++ b/pkg/plugins/manager/loader/loader.go @@ -42,18 +42,19 @@ type Loader struct { } func ProvideService(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer, - pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider, + pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider, pluginFinder finder.Finder, roleRegistry plugins.RoleRegistry, pluginsCDNService *pluginscdn.Service, assetPath *assetpath.Service) *Loader { return New(cfg, license, authorizer, pluginRegistry, backendProvider, process.NewManager(pluginRegistry), - storage.FileSystem(log.NewPrettyLogger("loader.fs"), cfg.PluginsPath), roleRegistry, pluginsCDNService, assetPath) + storage.FileSystem(log.NewPrettyLogger("loader.fs"), cfg.PluginsPath), roleRegistry, pluginsCDNService, + assetPath, pluginFinder) } func New(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer, pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider, processManager process.Service, pluginStorage storage.Manager, roleRegistry plugins.RoleRegistry, - pluginsCDNService *pluginscdn.Service, assetPath *assetpath.Service) *Loader { + pluginsCDNService *pluginscdn.Service, assetPath *assetpath.Service, pluginFinder finder.Finder) *Loader { return &Loader{ - pluginFinder: finder.NewService(), + pluginFinder: pluginFinder, pluginRegistry: pluginRegistry, pluginInitializer: initializer.New(cfg, backendProvider, license), signatureValidator: signature.NewValidator(authorizer), @@ -68,16 +69,16 @@ func New(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLo } } -func (l *Loader) Load(ctx context.Context, class plugins.Class, paths []string) ([]*plugins.Plugin, error) { - found, err := l.pluginFinder.Find(ctx, paths...) +func (l *Loader) Load(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) { + found, err := l.pluginFinder.Find(ctx, src) if err != nil { return nil, err } - return l.loadPlugins(ctx, class, found) + return l.loadPlugins(ctx, src, found) } -func (l *Loader) loadPlugins(ctx context.Context, class plugins.Class, found []*plugins.FoundBundle) ([]*plugins.Plugin, error) { +func (l *Loader) loadPlugins(ctx context.Context, src plugins.PluginSource, found []*plugins.FoundBundle) ([]*plugins.Plugin, error) { var loadedPlugins []*plugins.Plugin for _, p := range found { if _, exists := l.pluginRegistry.Plugin(ctx, p.Primary.JSONData.ID); exists { @@ -91,12 +92,13 @@ func (l *Loader) loadPlugins(ctx context.Context, class plugins.Class, found []* sig = plugins.Signature{Status: plugins.SignatureValid} } else { var err error - sig, err = signature.Calculate(l.log, class, p.Primary) + sig, err = signature.Calculate(ctx, l.log, src, p.Primary) if err != nil { l.log.Warn("Could not calculate plugin signature state", "pluginID", p.Primary.JSONData.ID, "err", err) continue } } + class := src.PluginClass(ctx) plugin, err := l.createPluginBase(p.Primary.JSONData, class, p.Primary.FS) if err != nil { l.log.Error("Could not create primary plugin base", "pluginID", p.Primary.JSONData.ID, "err", err) diff --git a/pkg/plugins/manager/loader/loader_test.go b/pkg/plugins/manager/loader/loader_test.go index 887b381bcba..9fbaf13f295 100644 --- a/pkg/plugins/manager/loader/loader_test.go +++ b/pkg/plugins/manager/loader/loader_test.go @@ -7,9 +7,6 @@ import ( "sort" "testing" - "github.com/grafana/grafana/pkg/plugins/manager/loader/assetpath" - "github.com/grafana/grafana/pkg/plugins/pluginscdn" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" @@ -18,8 +15,12 @@ import ( "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/log" "github.com/grafana/grafana/pkg/plugins/manager/fakes" + "github.com/grafana/grafana/pkg/plugins/manager/loader/assetpath" + "github.com/grafana/grafana/pkg/plugins/manager/loader/finder" "github.com/grafana/grafana/pkg/plugins/manager/loader/initializer" "github.com/grafana/grafana/pkg/plugins/manager/signature" + "github.com/grafana/grafana/pkg/plugins/manager/sources" + "github.com/grafana/grafana/pkg/plugins/pluginscdn" "github.com/grafana/grafana/pkg/setting" ) @@ -29,6 +30,7 @@ var localFSComparer = cmp.Comparer(func(fs1 plugins.LocalFS, fs2 plugins.LocalFS fs1Files := fs1.Files() fs2Files := fs2.Files() + finder.NewLocalFinder() sort.SliceStable(fs1Files, func(i, j int) bool { return fs1Files[i] < fs1Files[j] }) @@ -516,7 +518,7 @@ func TestLoader_Load(t *testing.T) { }) t.Run(tt.name, func(t *testing.T) { - got, err := l.Load(context.Background(), tt.class, tt.pluginPaths) + got, err := l.Load(context.Background(), sources.NewLocalSource(tt.class, tt.pluginPaths)) require.NoError(t, err) if !cmp.Equal(got, tt.want, compareOpts...) { t.Fatalf("Result mismatch (-want +got):\n%s", cmp.Diff(got, tt.want, compareOpts...)) @@ -679,7 +681,14 @@ func TestLoader_Load_MultiplePlugins(t *testing.T) { }) setting.AppUrl = tt.appURL - got, err := l.Load(context.Background(), plugins.External, tt.pluginPaths) + got, err := l.Load(context.Background(), &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + PluginURIsFunc: func(ctx context.Context) []string { + return tt.pluginPaths + }, + }) require.NoError(t, err) sort.SliceStable(got, func(i, j int) bool { return got[i].ID < got[j].ID @@ -792,7 +801,14 @@ func TestLoader_Load_RBACReady(t *testing.T) { l.pluginInitializer = initializer.New(tt.cfg, procPrvdr, fakes.NewFakeLicensingService()) }) - got, err := l.Load(context.Background(), plugins.External, tt.pluginPaths) + got, err := l.Load(context.Background(), &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + PluginURIsFunc: func(ctx context.Context) []string { + return tt.pluginPaths + }, + }) require.NoError(t, err) if !cmp.Equal(got, tt.want, compareOpts...) { @@ -868,7 +884,14 @@ func TestLoader_Load_Signature_RootURL(t *testing.T) { l.processManager = procMgr l.pluginInitializer = initializer.New(&config.Cfg{}, procPrvdr, fakes.NewFakeLicensingService()) }) - got, err := l.Load(context.Background(), plugins.External, paths) + got, err := l.Load(context.Background(), &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + PluginURIsFunc: func(ctx context.Context) []string { + return paths + }, + }) require.NoError(t, err) if !cmp.Equal(got, expected, compareOpts...) { @@ -947,7 +970,14 @@ func TestLoader_Load_DuplicatePlugins(t *testing.T) { l.processManager = procMgr l.pluginInitializer = initializer.New(&config.Cfg{}, procPrvdr, fakes.NewFakeLicensingService()) }) - got, err := l.Load(context.Background(), plugins.External, []string{pluginDir, pluginDir}) + got, err := l.Load(context.Background(), &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + PluginURIsFunc: func(ctx context.Context) []string { + return []string{pluginDir, pluginDir} + }, + }) require.NoError(t, err) if !cmp.Equal(got, expected, compareOpts...) { @@ -1046,7 +1076,14 @@ func TestLoader_Load_NestedPlugins(t *testing.T) { l.pluginInitializer = initializer.New(&config.Cfg{}, procPrvdr, fakes.NewFakeLicensingService()) }) - got, err := l.Load(context.Background(), plugins.External, []string{"../testdata/nested-plugins"}) + got, err := l.Load(context.Background(), &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + PluginURIsFunc: func(ctx context.Context) []string { + return []string{"../testdata/nested-plugins"} + }, + }) require.NoError(t, err) // to ensure we can compare with expected @@ -1062,7 +1099,14 @@ func TestLoader_Load_NestedPlugins(t *testing.T) { verifyState(t, expected, reg, procPrvdr, storage, procMgr) t.Run("Load will exclude plugins that already exist", func(t *testing.T) { - got, err := l.Load(context.Background(), plugins.External, []string{"../testdata/nested-plugins"}) + got, err := l.Load(context.Background(), &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + PluginURIsFunc: func(ctx context.Context) []string { + return []string{"../testdata/nested-plugins"} + }, + }) require.NoError(t, err) // to ensure we can compare with expected @@ -1213,7 +1257,14 @@ func TestLoader_Load_NestedPlugins(t *testing.T) { l.processManager = procMgr l.pluginInitializer = initializer.New(&config.Cfg{}, procPrvdr, fakes.NewFakeLicensingService()) }) - got, err := l.Load(context.Background(), plugins.External, []string{"../testdata/app-with-child"}) + got, err := l.Load(context.Background(), &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + PluginURIsFunc: func(ctx context.Context) []string { + return []string{"../testdata/app-with-child"} + }, + }) require.NoError(t, err) // to ensure we can compare with expected @@ -1256,7 +1307,7 @@ func newLoader(cfg *config.Cfg, cbs ...func(loader *Loader)) *Loader { cdn := pluginscdn.ProvideService(cfg) l := New(cfg, &fakes.FakeLicensingService{}, signature.NewUnsignedAuthorizer(cfg), fakes.NewFakePluginRegistry(), fakes.NewFakeBackendProcessProvider(), fakes.NewFakeProcessManager(), fakes.NewFakePluginStorage(), - fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn)) + fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn), finder.NewLocalFinder()) for _, cb := range cbs { cb(l) diff --git a/pkg/plugins/manager/manager_integration_test.go b/pkg/plugins/manager/manager_integration_test.go index 37280ffc030..f33e0deb596 100644 --- a/pkg/plugins/manager/manager_integration_test.go +++ b/pkg/plugins/manager/manager_integration_test.go @@ -24,6 +24,7 @@ import ( "github.com/grafana/grafana/pkg/plugins/manager/fakes" "github.com/grafana/grafana/pkg/plugins/manager/loader" "github.com/grafana/grafana/pkg/plugins/manager/loader/assetpath" + "github.com/grafana/grafana/pkg/plugins/manager/loader/finder" "github.com/grafana/grafana/pkg/plugins/manager/registry" "github.com/grafana/grafana/pkg/plugins/manager/signature" "github.com/grafana/grafana/pkg/plugins/manager/sources" @@ -116,7 +117,7 @@ func TestIntegrationPluginManager(t *testing.T) { lic := plicensing.ProvideLicensing(cfg, &licensing.OSSLicensingService{Cfg: cfg}) l := loader.ProvideService(pCfg, lic, signature.NewUnsignedAuthorizer(pCfg), - reg, provider.ProvideService(coreRegistry), fakes.NewFakeRoleRegistry(), + reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(), fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn)) srcs := sources.ProvideService(cfg, pCfg) ps, err := store.ProvideService(reg, srcs, l) diff --git a/pkg/plugins/manager/signature/manifest.go b/pkg/plugins/manager/signature/manifest.go index 82061863827..1bd03488aae 100644 --- a/pkg/plugins/manager/signature/manifest.go +++ b/pkg/plugins/manager/signature/manifest.go @@ -2,6 +2,7 @@ package signature import ( "bytes" + "context" "crypto/sha256" "encoding/hex" "encoding/json" @@ -76,7 +77,7 @@ func (m *PluginManifest) isV2() bool { return strings.HasPrefix(m.ManifestVersion, "2.") } -// readPluginManifest attempts to read and verify the plugin manifest +// ReadPluginManifest attempts to read and verify the plugin manifest // if any error occurs or the manifest is not valid, this will return an error func ReadPluginManifest(body []byte) (*PluginManifest, error) { block, _ := clearsign.Decode(body) @@ -98,11 +99,9 @@ func ReadPluginManifest(body []byte) (*PluginManifest, error) { return &manifest, nil } -func Calculate(mlog log.Logger, class plugins.Class, plugin plugins.FoundPlugin) (plugins.Signature, error) { - if class == plugins.Core { - return plugins.Signature{ - Status: plugins.SignatureInternal, - }, nil +func Calculate(ctx context.Context, mlog log.Logger, src plugins.PluginSource, plugin plugins.FoundPlugin) (plugins.Signature, error) { + if defaultSignature, exists := src.DefaultSignature(ctx); exists { + return defaultSignature, nil } if len(plugin.FS.Files()) == 0 { diff --git a/pkg/plugins/manager/signature/manifest_test.go b/pkg/plugins/manager/signature/manifest_test.go index de257b59ed5..6683523762a 100644 --- a/pkg/plugins/manager/signature/manifest_test.go +++ b/pkg/plugins/manager/signature/manifest_test.go @@ -1,16 +1,19 @@ package signature import ( + "context" "path/filepath" "sort" "strings" "testing" - "github.com/grafana/grafana/pkg/plugins" - "github.com/grafana/grafana/pkg/plugins/log" - "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/plugins/log" + "github.com/grafana/grafana/pkg/plugins/manager/fakes" + "github.com/grafana/grafana/pkg/setting" ) func TestReadPluginManifest(t *testing.T) { @@ -152,7 +155,11 @@ func TestCalculate(t *testing.T) { setting.AppUrl = tc.appURL basePath := filepath.Join(parentDir, "testdata/non-pvt-with-root-url/plugin") - sig, err := Calculate(log.NewTestLogger(), plugins.External, plugins.FoundPlugin{ + sig, err := Calculate(context.Background(), log.NewTestLogger(), &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + }, plugins.FoundPlugin{ JSONData: plugins.JSONData{ ID: "test-datasource", Info: plugins.Info{ @@ -178,7 +185,11 @@ func TestCalculate(t *testing.T) { basePath := "../testdata/renderer-added-file/plugin" runningWindows = true - sig, err := Calculate(log.NewTestLogger(), plugins.External, plugins.FoundPlugin{ + sig, err := Calculate(context.Background(), log.NewTestLogger(), &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + }, plugins.FoundPlugin{ JSONData: plugins.JSONData{ ID: "test-renderer", Type: plugins.Renderer, diff --git a/pkg/plugins/manager/sources/ifaces.go b/pkg/plugins/manager/sources/ifaces.go index 129e0160c2b..7d370d5a480 100644 --- a/pkg/plugins/manager/sources/ifaces.go +++ b/pkg/plugins/manager/sources/ifaces.go @@ -6,6 +6,6 @@ import ( "github.com/grafana/grafana/pkg/plugins" ) -type Resolver interface { +type Registry interface { List(context.Context) []plugins.PluginSource } diff --git a/pkg/plugins/manager/sources/source_local_disk.go b/pkg/plugins/manager/sources/source_local_disk.go new file mode 100644 index 00000000000..f5eec550702 --- /dev/null +++ b/pkg/plugins/manager/sources/source_local_disk.go @@ -0,0 +1,38 @@ +package sources + +import ( + "context" + + "github.com/grafana/grafana/pkg/plugins" +) + +type LocalSource struct { + paths []string + class plugins.Class +} + +func NewLocalSource(class plugins.Class, paths []string) *LocalSource { + return &LocalSource{ + class: class, + paths: paths, + } +} + +func (s *LocalSource) PluginClass(_ context.Context) plugins.Class { + return s.class +} + +func (s *LocalSource) PluginURIs(_ context.Context) []string { + return s.paths +} + +func (s *LocalSource) DefaultSignature(_ context.Context) (plugins.Signature, bool) { + switch s.class { + case plugins.Core: + return plugins.Signature{ + Status: plugins.SignatureInternal, + }, true + default: + return plugins.Signature{}, false + } +} diff --git a/pkg/plugins/manager/sources/sources.go b/pkg/plugins/manager/sources/sources.go index f4c6d37a2c0..e10acc47cb7 100644 --- a/pkg/plugins/manager/sources/sources.go +++ b/pkg/plugins/manager/sources/sources.go @@ -26,9 +26,9 @@ func ProvideService(gCfg *setting.Cfg, cfg *config.Cfg) *Service { 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)...)}, + NewLocalSource(plugins.Core, corePluginPaths(s.gCfg.StaticRootPath)), + NewLocalSource(plugins.Bundled, []string{s.gCfg.BundledPluginsPath}), + NewLocalSource(plugins.External, append([]string{s.cfg.PluginsPath}, pluginFSPaths(s.cfg.PluginSettings)...)), } } diff --git a/pkg/plugins/manager/sources/sources_test.go b/pkg/plugins/manager/sources/sources_test.go index 1dc9f00fa08..5202e1432e7 100644 --- a/pkg/plugins/manager/sources/sources_test.go +++ b/pkg/plugins/manager/sources/sources_test.go @@ -12,7 +12,7 @@ import ( ) func TestSources_List(t *testing.T) { - t.Run("Plugin sources are added in order", func(t *testing.T) { + t.Run("Plugin sources are populated by default and listed in specific order", func(t *testing.T) { cfg := &setting.Cfg{ BundledPluginsPath: "path1", } @@ -31,11 +31,28 @@ func TestSources_List(t *testing.T) { 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) + ctx := context.Background() + + require.Len(t, srcs, 3) + + require.Equal(t, srcs[0].PluginClass(ctx), plugins.Core) + require.Equal(t, srcs[0].PluginURIs(ctx), []string{"app/plugins/datasource", "app/plugins/panel"}) + sig, exists := srcs[0].DefaultSignature(ctx) + require.True(t, exists) + require.Equal(t, plugins.SignatureInternal, sig.Status) + require.Equal(t, plugins.SignatureType(""), sig.Type) + require.Equal(t, "", sig.SigningOrg) + + require.Equal(t, srcs[1].PluginClass(ctx), plugins.Bundled) + require.Equal(t, srcs[1].PluginURIs(ctx), []string{"path1"}) + sig, exists = srcs[1].DefaultSignature(ctx) + require.False(t, exists) + require.Equal(t, plugins.Signature{}, sig) + + require.Equal(t, srcs[2].PluginClass(ctx), plugins.External) + require.Equal(t, srcs[2].PluginURIs(ctx), []string{"path2", "path3"}) + sig, exists = srcs[2].DefaultSignature(ctx) + require.False(t, exists) + require.Equal(t, plugins.Signature{}, sig) }) } diff --git a/pkg/plugins/manager/store/store.go b/pkg/plugins/manager/store/store.go index e4f5f6bb58e..b78aa28e046 100644 --- a/pkg/plugins/manager/store/store.go +++ b/pkg/plugins/manager/store/store.go @@ -16,11 +16,11 @@ type Service struct { pluginRegistry registry.Service } -func ProvideService(pluginRegistry registry.Service, pluginSources sources.Resolver, +func ProvideService(pluginRegistry registry.Service, pluginSources sources.Registry, pluginLoader loader.Service) (*Service, error) { ctx := context.Background() for _, ps := range pluginSources.List(ctx) { - if _, err := pluginLoader.Load(ctx, ps.Class, ps.Paths); err != nil { + if _, err := pluginLoader.Load(ctx, ps); err != nil { return nil, err } } diff --git a/pkg/plugins/manager/store/store_test.go b/pkg/plugins/manager/store/store_test.go index f992b0b4e46..5deebb175e6 100644 --- a/pkg/plugins/manager/store/store_test.go +++ b/pkg/plugins/manager/store/store_test.go @@ -15,21 +15,29 @@ func TestStore_ProvideService(t *testing.T) { t.Run("Plugin sources are added in order", func(t *testing.T) { var addedPaths []string l := &fakes.FakeLoader{ - LoadFunc: func(ctx context.Context, class plugins.Class, paths []string) ([]*plugins.Plugin, error) { - addedPaths = append(addedPaths, paths...) + LoadFunc: func(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) { + addedPaths = append(addedPaths, src.PluginURIs(ctx)...) return nil, nil }, } - srcs := &fakes.FakeSources{ListFunc: func(_ context.Context) []plugins.PluginSource { + srcs := &fakes.FakeSourceRegistry{ListFunc: func(_ context.Context) []plugins.PluginSource { return []plugins.PluginSource{ - { - Class: plugins.Bundled, - Paths: []string{"path1"}, + &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.Bundled + }, + PluginURIsFunc: func(ctx context.Context) []string { + return []string{"path1"} + }, }, - { - Class: plugins.External, - Paths: []string{"path2", "path3"}, + &fakes.FakePluginSource{ + PluginClassFunc: func(ctx context.Context) plugins.Class { + return plugins.External + }, + PluginURIsFunc: func(ctx context.Context) []string { + return []string{"path2", "path3"} + }, }, } }} diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index cb6310a3851..495128b349a 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -20,7 +20,10 @@ import ( "github.com/grafana/grafana/pkg/util" ) -var ErrFileNotExist = errors.New("file does not exist") +var ( + ErrFileNotExist = errors.New("file does not exist") + ErrPluginFileRead = errors.New("file could not be read") +) type Plugin struct { JSONData @@ -427,6 +430,10 @@ const ( External Class = "external" ) +func (c Class) String() string { + return string(c) +} + var PluginTypes = []Type{ DataSource, Panel, diff --git a/pkg/services/pluginsintegration/pluginsintegration.go b/pkg/services/pluginsintegration/pluginsintegration.go index 7dda1f942f4..d0807781e6b 100644 --- a/pkg/services/pluginsintegration/pluginsintegration.go +++ b/pkg/services/pluginsintegration/pluginsintegration.go @@ -2,6 +2,7 @@ package pluginsintegration import ( "github.com/google/wire" + "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin/provider" @@ -11,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/plugins/manager/client" "github.com/grafana/grafana/pkg/plugins/manager/loader" "github.com/grafana/grafana/pkg/plugins/manager/loader/assetpath" + "github.com/grafana/grafana/pkg/plugins/manager/loader/finder" "github.com/grafana/grafana/pkg/plugins/manager/process" "github.com/grafana/grafana/pkg/plugins/manager/registry" "github.com/grafana/grafana/pkg/plugins/manager/signature" @@ -53,7 +55,7 @@ var WireSet = wire.NewSet( plugincontext.ProvideService, licensing.ProvideLicensing, wire.Bind(new(plugins.Licensing), new(*licensing.Service)), - wire.Bind(new(sources.Resolver), new(*sources.Service)), + wire.Bind(new(sources.Registry), new(*sources.Service)), sources.ProvideService, pluginSettings.ProvideService, wire.Bind(new(pluginsettings.Service), new(*pluginSettings.Service)), @@ -66,6 +68,8 @@ var WireExtensionSet = wire.NewSet( wire.Bind(new(plugins.BackendFactoryProvider), new(*provider.Service)), signature.ProvideOSSAuthorizer, wire.Bind(new(plugins.PluginLoaderAuthorizer), new(*signature.UnsignedPluginAuthorizer)), + wire.Bind(new(finder.Finder), new(*finder.Local)), + finder.NewLocalFinder, ) func ProvideClientDecorator(cfg *setting.Cfg, pCfg *config.Cfg,