mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 05:51:51 +08:00
Plugins: Add simple plugin sources service (#63814)
add simple plugin sources svc
This commit is contained in:
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins/manager/loader/assetpath"
|
"github.com/grafana/grafana/pkg/plugins/manager/loader/assetpath"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/signature"
|
"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/manager/store"
|
||||||
"github.com/grafana/grafana/pkg/plugins/plugincontext"
|
"github.com/grafana/grafana/pkg/plugins/plugincontext"
|
||||||
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
||||||
@ -60,7 +61,8 @@ func TestCallResource(t *testing.T) {
|
|||||||
cdn := pluginscdn.ProvideService(pCfg)
|
cdn := pluginscdn.ProvideService(pCfg)
|
||||||
l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg),
|
l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg),
|
||||||
reg, provider.ProvideService(coreRegistry), fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn))
|
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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pcp := plugincontext.ProvideService(localcache.ProvideService(), ps, &datasources.FakeCacheService{}, &datasources.FakeDataSourceService{}, pluginSettings.ProvideService(db.InitTestDB(t), nil))
|
pcp := plugincontext.ProvideService(localcache.ProvideService(), ps, &datasources.FakeCacheService{}, &datasources.FakeDataSourceService{}, pluginSettings.ProvideService(db.InitTestDB(t), nil))
|
||||||
|
@ -350,3 +350,14 @@ func NewFakeRoleRegistry() *FakeRoleRegistry {
|
|||||||
func (f *FakeRoleRegistry) DeclarePluginRoles(_ context.Context, _ string, _ string, _ []plugins.RoleRegistration) error {
|
func (f *FakeRoleRegistry) DeclarePluginRoles(_ context.Context, _ string, _ string, _ []plugins.RoleRegistration) error {
|
||||||
return f.ExpectedErr
|
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{}
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins/manager/loader"
|
"github.com/grafana/grafana/pkg/plugins/manager/loader"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/signature"
|
"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/manager/store"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/licensing"
|
"github.com/grafana/grafana/pkg/services/licensing"
|
||||||
@ -119,7 +120,8 @@ func TestIntegrationPluginManager(t *testing.T) {
|
|||||||
l := loader.ProvideService(pCfg, lic, signature.NewUnsignedAuthorizer(pCfg),
|
l := loader.ProvideService(pCfg, lic, signature.NewUnsignedAuthorizer(pCfg),
|
||||||
reg, provider.ProvideService(coreRegistry), fakes.NewFakeRoleRegistry(),
|
reg, provider.ProvideService(coreRegistry), fakes.NewFakeRoleRegistry(),
|
||||||
cdn, assetpath.ProvideService(cdn))
|
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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
11
pkg/plugins/manager/sources/ifaces.go
Normal file
11
pkg/plugins/manager/sources/ifaces.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package sources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Resolver interface {
|
||||||
|
List(context.Context) []plugins.PluginSource
|
||||||
|
}
|
53
pkg/plugins/manager/sources/sources.go
Normal file
53
pkg/plugins/manager/sources/sources.go
Normal file
@ -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
|
||||||
|
}
|
41
pkg/plugins/manager/sources/sources_test.go
Normal file
41
pkg/plugins/manager/sources/sources_test.go
Normal file
@ -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)
|
||||||
|
})
|
||||||
|
}
|
@ -2,14 +2,12 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"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/loader"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
"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)
|
var _ plugins.Store = (*Service)(nil)
|
||||||
@ -18,9 +16,9 @@ type Service struct {
|
|||||||
pluginRegistry registry.Service
|
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) {
|
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 {
|
if _, err := pluginLoader.Load(context.Background(), ps.Class, ps.Paths); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -119,31 +117,3 @@ func (s *Service) Routes() []*plugins.StaticRoute {
|
|||||||
}
|
}
|
||||||
return staticRoutes
|
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
|
|
||||||
}
|
|
||||||
|
@ -8,9 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
"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/plugins/manager/fakes"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStore_ProvideService(t *testing.T) {
|
func TestStore_ProvideService(t *testing.T) {
|
||||||
@ -22,21 +20,23 @@ func TestStore_ProvideService(t *testing.T) {
|
|||||||
return nil, nil
|
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.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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins/manager/process"
|
"github.com/grafana/grafana/pkg/plugins/manager/process"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/signature"
|
"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/manager/store"
|
||||||
"github.com/grafana/grafana/pkg/plugins/plugincontext"
|
"github.com/grafana/grafana/pkg/plugins/plugincontext"
|
||||||
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
|
||||||
@ -50,6 +51,8 @@ var WireSet = wire.NewSet(
|
|||||||
plugincontext.ProvideService,
|
plugincontext.ProvideService,
|
||||||
licensing.ProvideLicensing,
|
licensing.ProvideLicensing,
|
||||||
wire.Bind(new(plugins.Licensing), new(*licensing.Service)),
|
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
|
// WireExtensionSet provides a wire.ProviderSet of plugin providers that can be
|
||||||
|
Reference in New Issue
Block a user