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:
Will Browne
2023-08-02 16:29:12 +00:00
committed by GitHub
parent 77e7ae2a1b
commit ad2705fa0b
17 changed files with 1809 additions and 1166 deletions
@@ -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
}
@@ -1,146 +0,0 @@
package initializer
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/log"
)
func TestInitializer_Initialize(t *testing.T) {
t.Run("core backend datasource", func(t *testing.T) {
p := &plugins.Plugin{
JSONData: plugins.JSONData{
ID: "test",
Type: plugins.TypeDataSource,
Includes: []*plugins.Includes{
{
Name: "Example dashboard",
Type: plugins.TypeDashboard,
},
},
Backend: true,
},
Class: plugins.ClassCore,
}
i := &Initializer{
backendProvider: &fakeBackendProvider{
plugin: p,
},
envVarProvider: &fakeEnvVarsProvider{},
}
err := i.Initialize(context.Background(), p)
assert.NoError(t, err)
c, exists := p.Client()
assert.True(t, exists)
assert.NotNil(t, c)
})
t.Run("renderer", func(t *testing.T) {
p := &plugins.Plugin{
JSONData: plugins.JSONData{
ID: "test",
Type: plugins.TypeRenderer,
Dependencies: plugins.Dependencies{
GrafanaVersion: ">=8.x",
},
Backend: true,
},
Class: plugins.ClassExternal,
}
i := &Initializer{
backendProvider: &fakeBackendProvider{
plugin: p,
},
envVarProvider: &fakeEnvVarsProvider{},
}
err := i.Initialize(context.Background(), p)
assert.NoError(t, err)
c, exists := p.Client()
assert.True(t, exists)
assert.NotNil(t, c)
})
t.Run("secretsmanager", func(t *testing.T) {
p := &plugins.Plugin{
JSONData: plugins.JSONData{
ID: "test",
Type: plugins.TypeSecretsManager,
Dependencies: plugins.Dependencies{
GrafanaVersion: ">=8.x",
},
Backend: true,
},
Class: plugins.ClassExternal,
}
i := &Initializer{
backendProvider: &fakeBackendProvider{
plugin: p,
},
envVarProvider: &fakeEnvVarsProvider{},
}
err := i.Initialize(context.Background(), p)
assert.NoError(t, err)
c, exists := p.Client()
assert.True(t, exists)
assert.NotNil(t, c)
})
t.Run("non backend plugin app", func(t *testing.T) {
p := &plugins.Plugin{
JSONData: plugins.JSONData{
Backend: false,
},
}
i := &Initializer{
backendProvider: &fakeBackendProvider{
plugin: p,
},
envVarProvider: &fakeEnvVarsProvider{},
}
err := i.Initialize(context.Background(), p)
assert.NoError(t, err)
c, exists := p.Client()
assert.False(t, exists)
assert.Nil(t, c)
})
}
type fakeBackendProvider struct {
plugins.BackendFactoryProvider
plugin *plugins.Plugin
}
func (f *fakeBackendProvider) BackendFactory(_ context.Context, _ *plugins.Plugin) backendplugin.PluginFactoryFunc {
return func(_ string, _ log.Logger, _ []string) (backendplugin.Plugin, error) {
return f.plugin, nil
}
}
type fakeEnvVarsProvider struct {
GetFunc func(ctx context.Context, p *plugins.Plugin) []string
}
func (f *fakeEnvVarsProvider) Get(ctx context.Context, p *plugins.Plugin) ([]string, error) {
if f.GetFunc != nil {
return f.GetFunc(ctx, p), nil
}
return nil, nil
}
+15 -32
View File
@@ -11,9 +11,9 @@ import (
"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/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/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/manager/signature"
@@ -24,13 +24,13 @@ import (
var _ plugins.ErrorResolver = (*Loader)(nil)
type Loader struct {
discovery discovery.Discoverer
bootstrap bootstrap.Bootstrapper
discovery discovery.Discoverer
bootstrap bootstrap.Bootstrapper
initializer initialization.Initializer
processManager process.Service
pluginRegistry registry.Service
roleRegistry plugins.RoleRegistry
pluginInitializer initializer.Initializer
signatureValidator signature.Validator
externalServiceRegistry oauth.ExternalServiceRegistry
assetPath *assetpath.Service
@@ -42,23 +42,20 @@ type Loader struct {
errs map[string]*plugins.SignatureError
}
func ProvideService(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer,
pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider,
roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service,
func ProvideService(cfg *config.Cfg, authorizer plugins.PluginLoaderAuthorizer,
pluginRegistry registry.Service, roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service,
angularInspector angularinspector.Inspector, externalServiceRegistry oauth.ExternalServiceRegistry,
discovery discovery.Discoverer, bootstrap bootstrap.Bootstrapper) *Loader {
return New(cfg, license, authorizer, pluginRegistry, backendProvider, process.NewManager(pluginRegistry),
roleRegistry, assetPath, angularInspector, externalServiceRegistry, discovery, bootstrap)
discovery discovery.Discoverer, bootstrap bootstrap.Bootstrapper, initializer initialization.Initializer) *Loader {
return New(cfg, authorizer, pluginRegistry, process.NewManager(pluginRegistry), roleRegistry, assetPath,
angularInspector, externalServiceRegistry, discovery, bootstrap, initializer)
}
func New(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLoaderAuthorizer,
pluginRegistry registry.Service, backendProvider plugins.BackendFactoryProvider,
func New(cfg *config.Cfg, authorizer plugins.PluginLoaderAuthorizer, pluginRegistry registry.Service,
processManager process.Service, roleRegistry plugins.RoleRegistry, assetPath *assetpath.Service,
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{
pluginRegistry: pluginRegistry,
pluginInitializer: initializer.New(cfg, backendProvider, license),
signatureValidator: signature.NewValidator(authorizer),
processManager: processManager,
errs: make(map[string]*plugins.SignatureError),
@@ -70,6 +67,7 @@ func New(cfg *config.Cfg, license plugins.Licensing, authorizer plugins.PluginLo
externalServiceRegistry: externalServiceRegistry,
discovery: discovery,
bootstrap: bootstrap,
initializer: initializer,
}
}
@@ -144,24 +142,9 @@ func (l *Loader) Load(ctx context.Context, src plugins.PluginSource) ([]*plugins
// </VERIFICATION STAGE>
// <INITIALIZATION STAGE>
initializedPlugins := make([]*plugins.Plugin, 0, len(verifiedPlugins))
for _, p := range verifiedPlugins {
err = l.pluginInitializer.Initialize(ctx, p)
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)
initializedPlugins, err := l.initializer.Initialize(ctx, verifiedPlugins)
if err != nil {
return nil, err
}
// </INITIALIZATION STAGE>
File diff suppressed because it is too large Load Diff