mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Plugins: Add inititialization stage to plugin loader pipeline (#72667)
* first pass * migrate tests * simplify * fix comments * fix linter * nil checks * remove comment
This commit is contained in:
parent
77e7ae2a1b
commit
ad2705fa0b
@ -73,11 +73,12 @@ func TestCallResource(t *testing.T) {
|
|||||||
|
|
||||||
discovery := pipeline.ProvideDiscoveryStage(pCfg, finder.NewLocalFinder(pCfg.DevMode), reg)
|
discovery := pipeline.ProvideDiscoveryStage(pCfg, finder.NewLocalFinder(pCfg.DevMode), reg)
|
||||||
bootstrap := pipeline.ProvideBootstrapStage(pCfg, signature.ProvideService(pCfg, statickey.New()), assetpath.ProvideService(pluginscdn.ProvideService(pCfg)))
|
bootstrap := pipeline.ProvideBootstrapStage(pCfg, signature.ProvideService(pCfg, statickey.New()), assetpath.ProvideService(pluginscdn.ProvideService(pCfg)))
|
||||||
|
initialize := pipeline.ProvideInitializationStage(pCfg, reg, fakes.NewFakeLicensingService(), provider.ProvideService(coreRegistry))
|
||||||
|
|
||||||
l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg),
|
l := loader.ProvideService(pCfg, signature.NewUnsignedAuthorizer(pCfg),
|
||||||
reg, provider.ProvideService(coreRegistry), fakes.NewFakeRoleRegistry(),
|
reg, fakes.NewFakeRoleRegistry(),
|
||||||
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)),
|
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)),
|
||||||
angularInspector, &fakes.FakeOauthService{}, discovery, bootstrap)
|
angularInspector, &fakes.FakeOauthService{}, discovery, bootstrap, initialize)
|
||||||
srcs := sources.ProvideService(cfg, pCfg)
|
srcs := sources.ProvideService(cfg, pCfg)
|
||||||
ps, err := store.ProvideService(reg, srcs, l)
|
ps, err := store.ProvideService(reg, srcs, l)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -463,3 +463,36 @@ func (pr *FakePluginStore) Plugins(_ context.Context, pluginTypes ...plugins.Typ
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FakeDiscoverer struct {
|
||||||
|
DiscoverFunc func(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeDiscoverer) Discover(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error) {
|
||||||
|
if f.DiscoverFunc != nil {
|
||||||
|
return f.DiscoverFunc(ctx, src)
|
||||||
|
}
|
||||||
|
return []*plugins.FoundBundle{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type FakeBootstrapper struct {
|
||||||
|
BootstrapFunc func(ctx context.Context, src plugins.PluginSource, bundles []*plugins.FoundBundle) ([]*plugins.Plugin, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeBootstrapper) Bootstrap(ctx context.Context, src plugins.PluginSource, bundles []*plugins.FoundBundle) ([]*plugins.Plugin, error) {
|
||||||
|
if f.BootstrapFunc != nil {
|
||||||
|
return f.BootstrapFunc(ctx, src, bundles)
|
||||||
|
}
|
||||||
|
return []*plugins.Plugin{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type FakeInitializer struct {
|
||||||
|
IntializeFunc func(ctx context.Context, ps []*plugins.Plugin) ([]*plugins.Plugin, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeInitializer) Initialize(ctx context.Context, ps []*plugins.Plugin) ([]*plugins.Plugin, error) {
|
||||||
|
if f.IntializeFunc != nil {
|
||||||
|
return f.IntializeFunc(ctx, ps)
|
||||||
|
}
|
||||||
|
return []*plugins.Plugin{}, nil
|
||||||
|
}
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
package initializer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/config"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/envvars"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Initializer struct {
|
|
||||||
envVarProvider envvars.Provider
|
|
||||||
backendProvider plugins.BackendFactoryProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(cfg *config.Cfg, backendProvider plugins.BackendFactoryProvider, license plugins.Licensing) Initializer {
|
|
||||||
return Initializer{
|
|
||||||
envVarProvider: envvars.NewProvider(cfg, license),
|
|
||||||
backendProvider: backendProvider,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Initializer) Initialize(ctx context.Context, p *plugins.Plugin) error {
|
|
||||||
if p.Backend {
|
|
||||||
backendFactory := i.backendProvider.BackendFactory(ctx, p)
|
|
||||||
if backendFactory == nil {
|
|
||||||
return errors.New("could not find backend factory for plugin")
|
|
||||||
}
|
|
||||||
|
|
||||||
env, err := i.envVarProvider.Get(ctx, p)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if backendClient, err := backendFactory(p.ID, p.Logger(), env); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
p.RegisterClient(backendClient)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -11,9 +11,9 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins/log"
|
"github.com/grafana/grafana/pkg/plugins/log"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angularinspector"
|
"github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angularinspector"
|
||||||
"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/loader/initializer"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap"
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery"
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization"
|
||||||
"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"
|
||||||
@ -24,13 +24,13 @@ import (
|
|||||||
var _ plugins.ErrorResolver = (*Loader)(nil)
|
var _ plugins.ErrorResolver = (*Loader)(nil)
|
||||||
|
|
||||||
type Loader struct {
|
type Loader struct {
|
||||||
discovery discovery.Discoverer
|
discovery discovery.Discoverer
|
||||||
bootstrap bootstrap.Bootstrapper
|
bootstrap bootstrap.Bootstrapper
|
||||||
|
initializer initialization.Initializer
|
||||||
|
|
||||||
processManager process.Service
|
processManager process.Service
|
||||||
pluginRegistry registry.Service
|
pluginRegistry registry.Service
|
||||||
roleRegistry plugins.RoleRegistry
|
roleRegistry plugins.RoleRegistry
|
||||||
pluginInitializer initializer.Initializer
|
|
||||||
signatureValidator signature.Validator
|
signatureValidator signature.Validator
|
||||||
externalServiceRegistry oauth.ExternalServiceRegistry
|
externalServiceRegistry oauth.ExternalServiceRegistry
|
||||||
assetPath *assetpath.Service
|
assetPath *assetpath.Service
|
||||||
@ -42,23 +42,20 @@ type Loader struct {
|
|||||||
errs map[string]*plugins.SignatureError
|
errs map[string]*plugins.SignatureError
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer,
|
func ProvideService(cfg *config.Cfg, authorizer plugins.PluginLoaderAuthorizer,
|
||||||
pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider,
|
pluginRegistry registry.Service, roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service,
|
||||||
roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service,
|
|
||||||
angularInspector angularinspector.Inspector, externalServiceRegistry oauth.ExternalServiceRegistry,
|
angularInspector angularinspector.Inspector, externalServiceRegistry oauth.ExternalServiceRegistry,
|
||||||
discovery discovery.Discoverer, bootstrap bootstrap.Bootstrapper) *Loader {
|
discovery discovery.Discoverer, bootstrap bootstrap.Bootstrapper, initializer initialization.Initializer) *Loader {
|
||||||
return New(cfg, license, authorizer, pluginRegistry, backendProvider, process.NewManager(pluginRegistry),
|
return New(cfg, authorizer, pluginRegistry, process.NewManager(pluginRegistry), roleRegistry, assetPath,
|
||||||
roleRegistry, assetPath, angularInspector, externalServiceRegistry, discovery, bootstrap)
|
angularInspector, externalServiceRegistry, discovery, bootstrap, initializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer,
|
func New(cfg *config.Cfg, authorizer plugins.PluginLoaderAuthorizer, pluginRegistry registry.Service,
|
||||||
pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider,
|
|
||||||
processManager process.Service, roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service,
|
processManager process.Service, roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service,
|
||||||
angularInspector angularinspector.Inspector, externalServiceRegistry oauth.ExternalServiceRegistry,
|
angularInspector angularinspector.Inspector, externalServiceRegistry oauth.ExternalServiceRegistry,
|
||||||
discovery discovery.Discoverer, bootstrap bootstrap.Bootstrapper) *Loader {
|
discovery discovery.Discoverer, bootstrap bootstrap.Bootstrapper, initializer initialization.Initializer) *Loader {
|
||||||
return &Loader{
|
return &Loader{
|
||||||
pluginRegistry: pluginRegistry,
|
pluginRegistry: pluginRegistry,
|
||||||
pluginInitializer: initializer.New(cfg, backendProvider, license),
|
|
||||||
signatureValidator: signature.NewValidator(authorizer),
|
signatureValidator: signature.NewValidator(authorizer),
|
||||||
processManager: processManager,
|
processManager: processManager,
|
||||||
errs: make(map[string]*plugins.SignatureError),
|
errs: make(map[string]*plugins.SignatureError),
|
||||||
@ -70,6 +67,7 @@ func New(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLo
|
|||||||
externalServiceRegistry: externalServiceRegistry,
|
externalServiceRegistry: externalServiceRegistry,
|
||||||
discovery: discovery,
|
discovery: discovery,
|
||||||
bootstrap: bootstrap,
|
bootstrap: bootstrap,
|
||||||
|
initializer: initializer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,24 +142,9 @@ func (l *Loader) Load(ctx context.Context, src plugins.PluginSource) ([]*plugins
|
|||||||
// </VERIFICATION STAGE>
|
// </VERIFICATION STAGE>
|
||||||
|
|
||||||
// <INITIALIZATION STAGE>
|
// <INITIALIZATION STAGE>
|
||||||
initializedPlugins := make([]*plugins.Plugin, 0, len(verifiedPlugins))
|
initializedPlugins, err := l.initializer.Initialize(ctx, verifiedPlugins)
|
||||||
for _, p := range verifiedPlugins {
|
if err != nil {
|
||||||
err = l.pluginInitializer.Initialize(ctx, p)
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
l.log.Error("Could not initialize plugin", "pluginId", p.ID, "err", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = l.pluginRegistry.Add(ctx, p); err != nil {
|
|
||||||
l.log.Error("Could not start plugin", "pluginId", p.ID, "err", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !p.IsCorePlugin() {
|
|
||||||
l.log.Info("Plugin registered", "pluginID", p.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
initializedPlugins = append(initializedPlugins, p)
|
|
||||||
}
|
}
|
||||||
// </INITIALIZATION STAGE>
|
// </INITIALIZATION STAGE>
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -124,11 +124,11 @@ func TestIntegrationPluginManager(t *testing.T) {
|
|||||||
|
|
||||||
discovery := pipeline.ProvideDiscoveryStage(pCfg, finder.NewLocalFinder(pCfg.DevMode), reg)
|
discovery := pipeline.ProvideDiscoveryStage(pCfg, finder.NewLocalFinder(pCfg.DevMode), reg)
|
||||||
bootstrap := pipeline.ProvideBootstrapStage(pCfg, signature.ProvideService(pCfg, statickey.New()), assetpath.ProvideService(pluginscdn.ProvideService(pCfg)))
|
bootstrap := pipeline.ProvideBootstrapStage(pCfg, signature.ProvideService(pCfg, statickey.New()), assetpath.ProvideService(pluginscdn.ProvideService(pCfg)))
|
||||||
|
initialize := pipeline.ProvideInitializationStage(pCfg, reg, lic, provider.ProvideService(coreRegistry))
|
||||||
l := loader.ProvideService(pCfg, lic, signature.NewUnsignedAuthorizer(pCfg),
|
l := loader.ProvideService(pCfg, signature.NewUnsignedAuthorizer(pCfg),
|
||||||
reg, provider.ProvideService(coreRegistry), fakes.NewFakeRoleRegistry(),
|
reg, fakes.NewFakeRoleRegistry(),
|
||||||
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)),
|
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)),
|
||||||
angularInspector, &fakes.FakeOauthService{}, discovery, bootstrap)
|
angularInspector, &fakes.FakeOauthService{}, discovery, bootstrap, initialize)
|
||||||
srcs := sources.ProvideService(cfg, pCfg)
|
srcs := sources.ProvideService(cfg, pCfg)
|
||||||
ps, err := store.ProvideService(reg, srcs, l)
|
ps, err := store.ProvideService(reg, srcs, l)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -47,7 +47,7 @@ func New(cfg *config.Cfg, opts Opts) *Bootstrap {
|
|||||||
opts.ConstructFunc = DefaultConstructFunc(signature.DefaultCalculator(cfg), assetpath.DefaultService(cfg))
|
opts.ConstructFunc = DefaultConstructFunc(signature.DefaultCalculator(cfg), assetpath.DefaultService(cfg))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.DecorateFuncs) == 0 {
|
if opts.DecorateFuncs == nil {
|
||||||
opts.DecorateFuncs = DefaultDecorateFuncs
|
opts.DecorateFuncs = DefaultDecorateFuncs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ func New(cfg *config.Cfg, opts Opts) *Discovery {
|
|||||||
opts.FindFunc = DefaultFindFunc(cfg)
|
opts.FindFunc = DefaultFindFunc(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.FindFilterFuncs) == 0 {
|
if opts.FindFilterFuncs == nil {
|
||||||
opts.FindFilterFuncs = []FindFilterFunc{} // no filters by default
|
opts.FindFilterFuncs = []FindFilterFunc{} // no filters by default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
pkg/plugins/manager/pipeline/initialization/doc.go
Normal file
6
pkg/plugins/manager/pipeline/initialization/doc.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Package initialization defines the fourth stage of the plugin loader pipeline.
|
||||||
|
//
|
||||||
|
// The Initialization stage must implement the Initializer interface.
|
||||||
|
// - Initialize(ctx context.Context, ps []*plugins.Plugin) ([]*plugins.Plugin, error)
|
||||||
|
|
||||||
|
package initialization
|
@ -0,0 +1,67 @@
|
|||||||
|
package initialization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/config"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Initializer is responsible for the Initialization stage of the plugin loader pipeline.
|
||||||
|
type Initializer interface {
|
||||||
|
Initialize(ctx context.Context, ps []*plugins.Plugin) ([]*plugins.Plugin, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeFunc is the function used for the Initialize step of the Initialization stage.
|
||||||
|
type InitializeFunc func(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error)
|
||||||
|
|
||||||
|
type Initialize struct {
|
||||||
|
cfg *config.Cfg
|
||||||
|
initializeSteps []InitializeFunc
|
||||||
|
log log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type Opts struct {
|
||||||
|
InitializeFuncs []InitializeFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new Initialization stage.
|
||||||
|
func New(cfg *config.Cfg, opts Opts) *Initialize {
|
||||||
|
if opts.InitializeFuncs == nil {
|
||||||
|
opts.InitializeFuncs = []InitializeFunc{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Initialize{
|
||||||
|
cfg: cfg,
|
||||||
|
initializeSteps: opts.InitializeFuncs,
|
||||||
|
log: log.New("plugins.initialization"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize will execute the Initialize steps of the Initialization stage.
|
||||||
|
func (i *Initialize) Initialize(ctx context.Context, ps []*plugins.Plugin) ([]*plugins.Plugin, error) {
|
||||||
|
if len(i.initializeSteps) == 0 {
|
||||||
|
return ps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
initializedPlugins := make([]*plugins.Plugin, 0, len(ps))
|
||||||
|
for _, p := range ps {
|
||||||
|
var ip *plugins.Plugin
|
||||||
|
stepFailed := false
|
||||||
|
for _, init := range i.initializeSteps {
|
||||||
|
ip, err = init(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
stepFailed = true
|
||||||
|
i.log.Error("Could not initialize plugin", "pluginId", p.ID, "err", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !stepFailed {
|
||||||
|
initializedPlugins = append(initializedPlugins, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return initializedPlugins, nil
|
||||||
|
}
|
90
pkg/plugins/manager/pipeline/initialization/steps.go
Normal file
90
pkg/plugins/manager/pipeline/initialization/steps.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package initialization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/envvars"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/log"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BackendClientInit implements an InitializeFunc for initializing a backend plugin process.
|
||||||
|
//
|
||||||
|
// It uses the envvars.Provider to retrieve the environment variables required for the plugin and the plugins.BackendFactoryProvider
|
||||||
|
// to get fetch backend factory, which is used to form a connection to the backend plugin process.
|
||||||
|
//
|
||||||
|
// Note: This step does not start the backend plugin process.
|
||||||
|
type BackendClientInit struct {
|
||||||
|
envVarProvider envvars.Provider
|
||||||
|
backendProvider plugins.BackendFactoryProvider
|
||||||
|
log log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBackendClientInitStep returns a new InitializeFunc for registering a backend plugin process.
|
||||||
|
func NewBackendClientInitStep(envVarProvider envvars.Provider,
|
||||||
|
backendProvider plugins.BackendFactoryProvider) InitializeFunc {
|
||||||
|
return newBackendProcessRegistration(envVarProvider, backendProvider).Initialize
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBackendProcessRegistration(envVarProvider envvars.Provider,
|
||||||
|
backendProvider plugins.BackendFactoryProvider) *BackendClientInit {
|
||||||
|
return &BackendClientInit{
|
||||||
|
backendProvider: backendProvider,
|
||||||
|
envVarProvider: envVarProvider,
|
||||||
|
log: log.New("plugins.backend.registration"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize will initialize a backend plugin client, if the plugin is a backend plugin.
|
||||||
|
func (b *BackendClientInit) Initialize(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
|
||||||
|
if p.Backend {
|
||||||
|
backendFactory := b.backendProvider.BackendFactory(ctx, p)
|
||||||
|
if backendFactory == nil {
|
||||||
|
return nil, errors.New("could not find backend factory for plugin")
|
||||||
|
}
|
||||||
|
|
||||||
|
env, err := b.envVarProvider.Get(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if backendClient, err := backendFactory(p.ID, p.Logger(), env); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
p.RegisterClient(backendClient)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginRegistration implements an InitializeFunc for registering a plugin with the plugin registry.
|
||||||
|
type PluginRegistration struct {
|
||||||
|
pluginRegistry registry.Service
|
||||||
|
log log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPluginRegistrationStep returns a new InitializeFunc for registering a plugin with the plugin registry.
|
||||||
|
func NewPluginRegistrationStep(pluginRegistry registry.Service) InitializeFunc {
|
||||||
|
return newPluginRegistration(pluginRegistry).Initialize
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPluginRegistration(pluginRegistry registry.Service) *PluginRegistration {
|
||||||
|
return &PluginRegistration{
|
||||||
|
pluginRegistry: pluginRegistry,
|
||||||
|
log: log.New("plugins.registration"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize registers the plugin with the plugin registry.
|
||||||
|
func (r *PluginRegistration) Initialize(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
|
||||||
|
if err := r.pluginRegistry.Add(ctx, p); err != nil {
|
||||||
|
r.log.Error("Could not register plugin", "pluginID", p.ID, "err", err)
|
||||||
|
return nil, errors.New("could not register plugin")
|
||||||
|
}
|
||||||
|
if !p.IsCorePlugin() {
|
||||||
|
r.log.Info("Plugin registered", "pluginID", p.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
package initializer
|
package initialization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"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"
|
||||||
@ -28,19 +28,15 @@ func TestInitializer_Initialize(t *testing.T) {
|
|||||||
Class: plugins.ClassCore,
|
Class: plugins.ClassCore,
|
||||||
}
|
}
|
||||||
|
|
||||||
i := &Initializer{
|
stepFunc := NewBackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p})
|
||||||
backendProvider: &fakeBackendProvider{
|
|
||||||
plugin: p,
|
|
||||||
},
|
|
||||||
envVarProvider: &fakeEnvVarsProvider{},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := i.Initialize(context.Background(), p)
|
var err error
|
||||||
assert.NoError(t, err)
|
p, err = stepFunc(context.Background(), p)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
c, exists := p.Client()
|
c, exists := p.Client()
|
||||||
assert.True(t, exists)
|
require.True(t, exists)
|
||||||
assert.NotNil(t, c)
|
require.NotNil(t, c)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("renderer", func(t *testing.T) {
|
t.Run("renderer", func(t *testing.T) {
|
||||||
@ -56,19 +52,15 @@ func TestInitializer_Initialize(t *testing.T) {
|
|||||||
Class: plugins.ClassExternal,
|
Class: plugins.ClassExternal,
|
||||||
}
|
}
|
||||||
|
|
||||||
i := &Initializer{
|
stepFunc := NewBackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p})
|
||||||
backendProvider: &fakeBackendProvider{
|
|
||||||
plugin: p,
|
|
||||||
},
|
|
||||||
envVarProvider: &fakeEnvVarsProvider{},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := i.Initialize(context.Background(), p)
|
var err error
|
||||||
assert.NoError(t, err)
|
p, err = stepFunc(context.Background(), p)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
c, exists := p.Client()
|
c, exists := p.Client()
|
||||||
assert.True(t, exists)
|
require.True(t, exists)
|
||||||
assert.NotNil(t, c)
|
require.NotNil(t, c)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("secretsmanager", func(t *testing.T) {
|
t.Run("secretsmanager", func(t *testing.T) {
|
||||||
@ -84,19 +76,15 @@ func TestInitializer_Initialize(t *testing.T) {
|
|||||||
Class: plugins.ClassExternal,
|
Class: plugins.ClassExternal,
|
||||||
}
|
}
|
||||||
|
|
||||||
i := &Initializer{
|
stepFunc := NewBackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p})
|
||||||
backendProvider: &fakeBackendProvider{
|
|
||||||
plugin: p,
|
|
||||||
},
|
|
||||||
envVarProvider: &fakeEnvVarsProvider{},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := i.Initialize(context.Background(), p)
|
var err error
|
||||||
assert.NoError(t, err)
|
p, err = stepFunc(context.Background(), p)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
c, exists := p.Client()
|
c, exists := p.Client()
|
||||||
assert.True(t, exists)
|
require.True(t, exists)
|
||||||
assert.NotNil(t, c)
|
require.NotNil(t, c)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("non backend plugin app", func(t *testing.T) {
|
t.Run("non backend plugin app", func(t *testing.T) {
|
||||||
@ -106,19 +94,17 @@ func TestInitializer_Initialize(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
i := &Initializer{
|
i := NewBackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{
|
||||||
backendProvider: &fakeBackendProvider{
|
plugin: p,
|
||||||
plugin: p,
|
})
|
||||||
},
|
|
||||||
envVarProvider: &fakeEnvVarsProvider{},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := i.Initialize(context.Background(), p)
|
var err error
|
||||||
assert.NoError(t, err)
|
p, err = i(context.Background(), p)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
c, exists := p.Client()
|
c, exists := p.Client()
|
||||||
assert.False(t, exists)
|
require.False(t, exists)
|
||||||
assert.Nil(t, c)
|
require.Nil(t, c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
47
pkg/services/pluginsintegration/loader/loader.go
Normal file
47
pkg/services/pluginsintegration/loader/loader.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package loader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/config"
|
||||||
|
pluginsLoader "github.com/grafana/grafana/pkg/plugins/manager/loader"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angularinspector"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/loader/assetpath"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/process"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/oauth"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ plugins.ErrorResolver = (*Loader)(nil)
|
||||||
|
var _ pluginsLoader.Service = (*Loader)(nil)
|
||||||
|
|
||||||
|
type Loader struct {
|
||||||
|
loader *pluginsLoader.Loader
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProvideService(cfg *config.Cfg, authorizer plugins.PluginLoaderAuthorizer, processManager process.Service,
|
||||||
|
pluginRegistry registry.Service, roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service,
|
||||||
|
angularInspector angularinspector.Inspector, externalServiceRegistry oauth.ExternalServiceRegistry,
|
||||||
|
discovery discovery.Discoverer, bootstrap bootstrap.Bootstrapper, initializer initialization.Initializer,
|
||||||
|
) *Loader {
|
||||||
|
return &Loader{
|
||||||
|
loader: pluginsLoader.New(cfg, authorizer, pluginRegistry, processManager, roleRegistry, assetPath,
|
||||||
|
angularInspector, externalServiceRegistry, discovery, bootstrap, initializer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Loader) Load(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) {
|
||||||
|
return l.loader.Load(ctx, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Loader) Unload(ctx context.Context, pluginID string) error {
|
||||||
|
return l.loader.Unload(ctx, pluginID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Loader) PluginErrors() []*plugins.Error {
|
||||||
|
return l.loader.PluginErrors()
|
||||||
|
}
|
1382
pkg/services/pluginsintegration/loader/loader_test.go
Normal file
1382
pkg/services/pluginsintegration/loader/loader_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,33 +0,0 @@
|
|||||||
package pipeline
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/config"
|
|
||||||
"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/pipeline/bootstrap"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ProvideDiscoveryStage(cfg *config.Cfg, pluginFinder finder.Finder, pluginRegistry registry.Service) *discovery.Discovery {
|
|
||||||
return discovery.New(cfg, discovery.Opts{
|
|
||||||
FindFunc: func(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error) {
|
|
||||||
return pluginFinder.Find(ctx, src)
|
|
||||||
},
|
|
||||||
FindFilterFuncs: []discovery.FindFilterFunc{
|
|
||||||
func(ctx context.Context, _ plugins.Class, bundles []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) {
|
|
||||||
return discovery.NewDuplicatePluginFilterStep(pluginRegistry).Filter(ctx, bundles)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProvideBootstrapStage(cfg *config.Cfg, signatureCalculator plugins.SignatureCalculator, assetPath *assetpath.Service) *bootstrap.Bootstrap {
|
|
||||||
return bootstrap.New(cfg, bootstrap.Opts{
|
|
||||||
ConstructFunc: bootstrap.DefaultConstructFunc(signatureCalculator, assetPath),
|
|
||||||
DecorateFuncs: bootstrap.DefaultDecorateFuncs,
|
|
||||||
})
|
|
||||||
}
|
|
44
pkg/services/pluginsintegration/pipeline/pipeline.go
Normal file
44
pkg/services/pluginsintegration/pipeline/pipeline.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package pipeline
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/config"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/envvars"
|
||||||
|
"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/pipeline/bootstrap"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProvideDiscoveryStage(cfg *config.Cfg, pf finder.Finder, pr registry.Service) *discovery.Discovery {
|
||||||
|
return discovery.New(cfg, discovery.Opts{
|
||||||
|
FindFunc: func(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error) {
|
||||||
|
return pf.Find(ctx, src)
|
||||||
|
},
|
||||||
|
FindFilterFuncs: []discovery.FindFilterFunc{
|
||||||
|
func(ctx context.Context, _ plugins.Class, b []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) {
|
||||||
|
return discovery.NewDuplicatePluginFilterStep(pr).Filter(ctx, b)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProvideBootstrapStage(cfg *config.Cfg, sc plugins.SignatureCalculator, a *assetpath.Service) *bootstrap.Bootstrap {
|
||||||
|
return bootstrap.New(cfg, bootstrap.Opts{
|
||||||
|
ConstructFunc: bootstrap.DefaultConstructFunc(sc, a),
|
||||||
|
DecorateFuncs: bootstrap.DefaultDecorateFuncs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProvideInitializationStage(cfg *config.Cfg, pr registry.Service, l plugins.Licensing, bp plugins.BackendFactoryProvider) *initialization.Initialize {
|
||||||
|
return initialization.New(cfg, initialization.Opts{
|
||||||
|
InitializeFuncs: []initialization.InitializeFunc{
|
||||||
|
initialization.NewBackendClientInitStep(envvars.NewProvider(cfg, l), bp),
|
||||||
|
initialization.NewPluginRegistrationStep(pr),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
@ -11,12 +11,13 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins/manager"
|
"github.com/grafana/grafana/pkg/plugins/manager"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/client"
|
"github.com/grafana/grafana/pkg/plugins/manager/client"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/filestore"
|
"github.com/grafana/grafana/pkg/plugins/manager/filestore"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/loader"
|
pluginLoader "github.com/grafana/grafana/pkg/plugins/manager/loader"
|
||||||
pAngularInspector "github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angularinspector"
|
pAngularInspector "github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angularinspector"
|
||||||
"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/loader/finder"
|
"github.com/grafana/grafana/pkg/plugins/manager/loader/finder"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap"
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery"
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization"
|
||||||
"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"
|
||||||
@ -37,6 +38,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/keyretriever/dynamic"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/keyretriever/dynamic"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/keystore"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/keystore"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/licensing"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/licensing"
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/loader"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pipeline"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pipeline"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
||||||
@ -65,6 +67,8 @@ var WireSet = wire.NewSet(
|
|||||||
wire.Bind(new(discovery.Discoverer), new(*discovery.Discovery)),
|
wire.Bind(new(discovery.Discoverer), new(*discovery.Discovery)),
|
||||||
pipeline.ProvideBootstrapStage,
|
pipeline.ProvideBootstrapStage,
|
||||||
wire.Bind(new(bootstrap.Bootstrapper), new(*bootstrap.Bootstrap)),
|
wire.Bind(new(bootstrap.Bootstrapper), new(*bootstrap.Bootstrap)),
|
||||||
|
pipeline.ProvideInitializationStage,
|
||||||
|
wire.Bind(new(initialization.Initializer), new(*initialization.Initialize)),
|
||||||
|
|
||||||
angularpatternsstore.ProvideService,
|
angularpatternsstore.ProvideService,
|
||||||
angulardetectorsprovider.ProvideDynamic,
|
angulardetectorsprovider.ProvideDynamic,
|
||||||
@ -72,7 +76,7 @@ var WireSet = wire.NewSet(
|
|||||||
wire.Bind(new(pAngularInspector.Inspector), new(*angularinspector.Service)),
|
wire.Bind(new(pAngularInspector.Inspector), new(*angularinspector.Service)),
|
||||||
|
|
||||||
loader.ProvideService,
|
loader.ProvideService,
|
||||||
wire.Bind(new(loader.Service), new(*loader.Loader)),
|
wire.Bind(new(pluginLoader.Service), new(*loader.Loader)),
|
||||||
wire.Bind(new(plugins.ErrorResolver), new(*loader.Loader)),
|
wire.Bind(new(plugins.ErrorResolver), new(*loader.Loader)),
|
||||||
manager.ProvideInstaller,
|
manager.ProvideInstaller,
|
||||||
wire.Bind(new(plugins.Installer), new(*manager.PluginInstaller)),
|
wire.Bind(new(plugins.Installer), new(*manager.PluginInstaller)),
|
||||||
|
Loading…
Reference in New Issue
Block a user