manager exposes renderer + secrets manager (#54629)

This commit is contained in:
Will Browne
2022-09-02 14:20:10 +02:00
committed by GitHub
parent 43987e7f8c
commit ecdcafb258
26 changed files with 126 additions and 122 deletions

View File

@ -54,7 +54,7 @@ func (hs *HTTPServer) AdminRollbackSecrets(c *models.ReqContext) response.Respon
// To migrate to the plugin, it must be installed and configured // To migrate to the plugin, it must be installed and configured
// so as not to lose access to migrated secrets // so as not to lose access to migrated secrets
func (hs *HTTPServer) AdminMigrateSecretsToPlugin(c *models.ReqContext) response.Response { func (hs *HTTPServer) AdminMigrateSecretsToPlugin(c *models.ReqContext) response.Response {
if skv.EvaluateRemoteSecretsPlugin(hs.secretsPluginManager, hs.Cfg) != nil { if skv.EvaluateRemoteSecretsPlugin(c.Req.Context(), hs.secretsPluginManager, hs.Cfg) != nil {
hs.log.Warn("Received secrets plugin migration request while plugin is not available") hs.log.Warn("Received secrets plugin migration request while plugin is not available")
return response.Respond(http.StatusBadRequest, "Secrets plugin is not available") return response.Respond(http.StatusBadRequest, "Secrets plugin is not available")
} }
@ -69,7 +69,7 @@ func (hs *HTTPServer) AdminMigrateSecretsToPlugin(c *models.ReqContext) response
// To migrate from the plugin, it must be installed only // To migrate from the plugin, it must be installed only
// as it is possible the user disabled it and then wants to migrate // as it is possible the user disabled it and then wants to migrate
func (hs *HTTPServer) AdminMigrateSecretsFromPlugin(c *models.ReqContext) response.Response { func (hs *HTTPServer) AdminMigrateSecretsFromPlugin(c *models.ReqContext) response.Response {
if hs.secretsPluginManager.SecretsManager() == nil { if hs.secretsPluginManager.SecretsManager(c.Req.Context()) == nil {
hs.log.Warn("Received secrets plugin migration request while plugin is not installed") hs.log.Warn("Received secrets plugin migration request while plugin is not installed")
return response.Respond(http.StatusBadRequest, "Secrets plugin is not installed") return response.Respond(http.StatusBadRequest, "Secrets plugin is not installed")
} }
@ -82,7 +82,7 @@ func (hs *HTTPServer) AdminMigrateSecretsFromPlugin(c *models.ReqContext) respon
} }
func (hs *HTTPServer) AdminDeleteAllSecretsManagerPluginSecrets(c *models.ReqContext) response.Response { func (hs *HTTPServer) AdminDeleteAllSecretsManagerPluginSecrets(c *models.ReqContext) response.Response {
if hs.secretsPluginManager.SecretsManager() == nil { if hs.secretsPluginManager.SecretsManager(c.Req.Context()) == nil {
hs.log.Warn("Received secrets plugin deletion request while plugin is not installed") hs.log.Warn("Received secrets plugin deletion request while plugin is not installed")
return response.Respond(http.StatusBadRequest, "Secrets plugin is not installed") return response.Respond(http.StatusBadRequest, "Secrets plugin is not installed")
} }

View File

@ -59,7 +59,7 @@ type fakeRendererManager struct {
plugins.RendererManager plugins.RendererManager
} }
func (ps *fakeRendererManager) Renderer() *plugins.Plugin { func (ps *fakeRendererManager) Renderer(_ context.Context) *plugins.Plugin {
return nil return nil
} }

View File

@ -88,7 +88,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
} }
hasAccess := accesscontrol.HasAccess(hs.AccessControl, c) hasAccess := accesscontrol.HasAccess(hs.AccessControl, c)
secretsManagerPluginEnabled := kvstore.EvaluateRemoteSecretsPlugin(hs.secretsPluginManager, hs.Cfg) == nil secretsManagerPluginEnabled := kvstore.EvaluateRemoteSecretsPlugin(c.Req.Context(), hs.secretsPluginManager, hs.Cfg) == nil
jsonObj := map[string]interface{}{ jsonObj := map[string]interface{}{
"defaultDatasource": defaultDS, "defaultDatasource": defaultDS,
@ -154,7 +154,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
"enabledFeatures": hs.License.EnabledFeatures(), "enabledFeatures": hs.License.EnabledFeatures(),
}, },
"featureToggles": hs.Features.GetEnabled(c.Req.Context()), "featureToggles": hs.Features.GetEnabled(c.Req.Context()),
"rendererAvailable": hs.RenderService.IsAvailable(), "rendererAvailable": hs.RenderService.IsAvailable(c.Req.Context()),
"rendererVersion": hs.RenderService.Version(), "rendererVersion": hs.RenderService.Version(),
"secretsManagerPluginEnabled": secretsManagerPluginEnabled, "secretsManagerPluginEnabled": secretsManagerPluginEnabled,
"http2Enabled": hs.Cfg.Protocol == setting.HTTP2Scheme, "http2Enabled": hs.Cfg.Protocol == setting.HTTP2Scheme,

View File

@ -181,12 +181,12 @@ var wireSet = wire.NewSet(
wire.Bind(new(repo.Service), new(*repo.Manager)), wire.Bind(new(repo.Service), new(*repo.Manager)),
manager.ProvideService, manager.ProvideService,
wire.Bind(new(plugins.Manager), new(*manager.PluginManager)), wire.Bind(new(plugins.Manager), new(*manager.PluginManager)),
wire.Bind(new(plugins.RendererManager), new(*manager.PluginManager)),
wire.Bind(new(plugins.SecretsPluginManager), new(*manager.PluginManager)),
client.ProvideService, client.ProvideService,
wire.Bind(new(plugins.Client), new(*client.Service)), wire.Bind(new(plugins.Client), new(*client.Service)),
managerStore.ProvideService, managerStore.ProvideService,
wire.Bind(new(plugins.Store), new(*managerStore.Service)), wire.Bind(new(plugins.Store), new(*managerStore.Service)),
wire.Bind(new(plugins.RendererManager), new(*managerStore.Service)),
wire.Bind(new(plugins.SecretsPluginManager), new(*managerStore.Service)),
wire.Bind(new(plugins.StaticRouteResolver), new(*managerStore.Service)), wire.Bind(new(plugins.StaticRouteResolver), new(*managerStore.Service)),
pluginDashboards.ProvideFileStoreManager, pluginDashboards.ProvideFileStoreManager,
wire.Bind(new(pluginDashboards.FileStore), new(*pluginDashboards.FileStoreManager)), wire.Bind(new(pluginDashboards.FileStore), new(*pluginDashboards.FileStoreManager)),

View File

@ -54,12 +54,12 @@ type BackendFactoryProvider interface {
type RendererManager interface { type RendererManager interface {
// Renderer returns a renderer plugin. // Renderer returns a renderer plugin.
Renderer() *Plugin Renderer(ctx context.Context) *Plugin
} }
type SecretsPluginManager interface { type SecretsPluginManager interface {
// SecretsManager returns a secretsmanager plugin // SecretsManager returns a secretsmanager plugin
SecretsManager() *Plugin SecretsManager(ctx context.Context) *Plugin
} }
type StaticRouteResolver interface { type StaticRouteResolver interface {

View File

@ -17,6 +17,8 @@ import (
) )
var _ plugins.Manager = (*PluginManager)(nil) var _ plugins.Manager = (*PluginManager)(nil)
var _ plugins.RendererManager = (*PluginManager)(nil)
var _ plugins.SecretsPluginManager = (*PluginManager)(nil)
type PluginManager struct { type PluginManager struct {
cfg *plugins.Cfg cfg *plugins.Cfg
@ -172,6 +174,24 @@ func (m *PluginManager) Remove(ctx context.Context, pluginID string) error {
return m.pluginStorage.Remove(ctx, plugin.ID) return m.pluginStorage.Remove(ctx, plugin.ID)
} }
func (m *PluginManager) Renderer(ctx context.Context) *plugins.Plugin {
for _, p := range m.pluginRegistry.Plugins(ctx) {
if p.IsRenderer() && !p.IsDecommissioned() {
return p
}
}
return nil
}
func (m *PluginManager) SecretsManager(ctx context.Context) *plugins.Plugin {
for _, p := range m.pluginRegistry.Plugins(ctx) {
if p.IsSecretsManager() && !p.IsDecommissioned() {
return p
}
}
return nil
}
// plugin finds a plugin with `pluginID` from the registry that is not decommissioned // plugin finds a plugin with `pluginID` from the registry that is not decommissioned
func (m *PluginManager) plugin(ctx context.Context, pluginID string) (*plugins.Plugin, bool) { func (m *PluginManager) plugin(ctx context.Context, pluginID string) (*plugins.Plugin, bool) {
p, exists := m.pluginRegistry.Plugin(ctx, pluginID) p, exists := m.pluginRegistry.Plugin(ctx, pluginID)

View File

@ -213,6 +213,52 @@ func TestPluginManager_Run(t *testing.T) {
}) })
} }
func TestManager_Renderer(t *testing.T) {
t.Run("Renderer returns a single (non-decommissioned) renderer plugin", func(t *testing.T) {
p1 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-renderer", Type: plugins.Renderer}}
p2 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-panel", Type: plugins.Panel}}
p3 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-app", Type: plugins.App}}
reg := &fakes.FakePluginRegistry{
Store: map[string]*plugins.Plugin{
p1.ID: p1,
p2.ID: p2,
p3.ID: p3,
},
}
pm := New(&plugins.Cfg{}, reg, []plugins.PluginSource{}, &fakes.FakeLoader{}, &fakes.FakePluginRepo{},
&fakes.FakePluginStorage{}, &fakes.FakeProcessManager{})
r := pm.Renderer(context.Background())
require.Equal(t, p1, r)
})
}
func TestManager_SecretsManager(t *testing.T) {
t.Run("Renderer returns a single (non-decommissioned) secrets manager plugin", func(t *testing.T) {
p1 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-renderer", Type: plugins.Renderer}}
p2 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-panel", Type: plugins.Panel}}
p3 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-secrets", Type: plugins.SecretsManager}}
p4 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-datasource", Type: plugins.DataSource}}
reg := &fakes.FakePluginRegistry{
Store: map[string]*plugins.Plugin{
p1.ID: p1,
p2.ID: p2,
p3.ID: p3,
p4.ID: p4,
},
}
pm := New(&plugins.Cfg{}, reg, []plugins.PluginSource{}, &fakes.FakeLoader{}, &fakes.FakePluginRepo{},
&fakes.FakePluginStorage{}, &fakes.FakeProcessManager{})
r := pm.SecretsManager(context.Background())
require.Equal(t, p3, r)
})
}
func createPlugin(t *testing.T, pluginID string, class plugins.Class, managed, backend bool, cbs ...func(*plugins.Plugin)) *plugins.Plugin { func createPlugin(t *testing.T, pluginID string, class plugins.Class, managed, backend bool, cbs ...func(*plugins.Plugin)) *plugins.Plugin {
t.Helper() t.Helper()

View File

@ -9,8 +9,6 @@ import (
) )
var _ plugins.Store = (*Service)(nil) var _ plugins.Store = (*Service)(nil)
var _ plugins.RendererManager = (*Service)(nil)
var _ plugins.SecretsPluginManager = (*Service)(nil)
type Service struct { type Service struct {
pluginRegistry registry.Service pluginRegistry registry.Service
@ -51,26 +49,6 @@ func (s *Service) Plugins(ctx context.Context, pluginTypes ...plugins.Type) []pl
return pluginsList return pluginsList
} }
func (s *Service) Renderer() *plugins.Plugin {
for _, p := range s.availablePlugins(context.TODO()) {
if p.IsRenderer() {
return p
}
}
return nil
}
func (s *Service) SecretsManager() *plugins.Plugin {
for _, p := range s.availablePlugins(context.TODO()) {
if p.IsSecretsManager() {
return p
}
}
return nil
}
// plugin finds a plugin with `pluginID` from the registry that is not decommissioned // plugin finds a plugin with `pluginID` from the registry that is not decommissioned
func (s *Service) plugin(ctx context.Context, pluginID string) (*plugins.Plugin, bool) { func (s *Service) plugin(ctx context.Context, pluginID string) (*plugins.Plugin, bool) {
p, exists := s.pluginRegistry.Plugin(ctx, pluginID) p, exists := s.pluginRegistry.Plugin(ctx, pluginID)

View File

@ -69,49 +69,6 @@ func TestStore_Plugins(t *testing.T) {
}) })
} }
func TestStore_Renderer(t *testing.T) {
t.Run("Renderer returns a single (non-decommissioned) renderer plugin", func(t *testing.T) {
p1 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-renderer", Type: plugins.Renderer}}
p2 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-panel", Type: plugins.Panel}}
p3 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-app", Type: plugins.App}}
p4 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-datasource", Type: plugins.DataSource}}
p4.RegisterClient(&DecommissionedPlugin{})
ps := ProvideService(
newFakePluginRegistry(map[string]*plugins.Plugin{
p1.ID: p1,
p2.ID: p2,
p3.ID: p3,
p4.ID: p4,
}),
)
r := ps.Renderer()
require.Equal(t, p1, r)
})
}
func TestStore_SecretsManager(t *testing.T) {
t.Run("Renderer returns a single (non-decommissioned) secrets manager plugin", func(t *testing.T) {
p1 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-renderer", Type: plugins.Renderer}}
p2 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-panel", Type: plugins.Panel}}
p3 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-secrets", Type: plugins.SecretsManager}}
p4 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "test-datasource", Type: plugins.DataSource}}
ps := ProvideService(
newFakePluginRegistry(map[string]*plugins.Plugin{
p1.ID: p1,
p2.ID: p2,
p3.ID: p3,
p4.ID: p4,
}),
)
r := ps.SecretsManager()
require.Equal(t, p3, r)
})
}
func TestStore_Routes(t *testing.T) { func TestStore_Routes(t *testing.T) {
t.Run("Routes returns all static routes for non-decommissioned plugins", func(t *testing.T) { t.Run("Routes returns all static routes for non-decommissioned plugins", func(t *testing.T) {
p1 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "a-test-renderer", Type: plugins.Renderer}, PluginDir: "/some/dir"} p1 := &plugins.Plugin{JSONData: plugins.JSONData{ID: "a-test-renderer", Type: plugins.Renderer}, PluginDir: "/some/dir"}

View File

@ -176,12 +176,12 @@ var wireBasicSet = wire.NewSet(
wire.Bind(new(repo.Service), new(*repo.Manager)), wire.Bind(new(repo.Service), new(*repo.Manager)),
manager.ProvideService, manager.ProvideService,
wire.Bind(new(plugins.Manager), new(*manager.PluginManager)), wire.Bind(new(plugins.Manager), new(*manager.PluginManager)),
wire.Bind(new(plugins.RendererManager), new(*manager.PluginManager)),
wire.Bind(new(plugins.SecretsPluginManager), new(*manager.PluginManager)),
client.ProvideService, client.ProvideService,
wire.Bind(new(plugins.Client), new(*client.Service)), wire.Bind(new(plugins.Client), new(*client.Service)),
managerStore.ProvideService, managerStore.ProvideService,
wire.Bind(new(plugins.Store), new(*managerStore.Service)), wire.Bind(new(plugins.Store), new(*managerStore.Service)),
wire.Bind(new(plugins.RendererManager), new(*managerStore.Service)),
wire.Bind(new(plugins.SecretsPluginManager), new(*managerStore.Service)),
wire.Bind(new(plugins.StaticRouteResolver), new(*managerStore.Service)), wire.Bind(new(plugins.StaticRouteResolver), new(*managerStore.Service)),
pluginDashboards.ProvideFileStoreManager, pluginDashboards.ProvideFileStoreManager,
wire.Bind(new(pluginDashboards.FileStore), new(*pluginDashboards.FileStoreManager)), wire.Bind(new(pluginDashboards.FileStore), new(*pluginDashboards.FileStoreManager)),

View File

@ -243,7 +243,7 @@ func notificationServiceScenario(t *testing.T, name string, evalCtx *EvalContext
scenarioCtx.rendererAvailable = true scenarioCtx.rendererAvailable = true
renderService := &testRenderService{ renderService := &testRenderService{
isAvailableProvider: func() bool { isAvailableProvider: func(ctx context.Context) bool {
return scenarioCtx.rendererAvailable return scenarioCtx.rendererAvailable
}, },
renderProvider: func(ctx context.Context, opts rendering.Opts) (*rendering.RenderResult, error) { renderProvider: func(ctx context.Context, opts rendering.Opts) (*rendering.RenderResult, error) {
@ -334,7 +334,7 @@ func (n *testNotifier) GetFrequency() time.Duration {
var _ Notifier = &testNotifier{} var _ Notifier = &testNotifier{}
type testRenderService struct { type testRenderService struct {
isAvailableProvider func() bool isAvailableProvider func(ctx context.Context) bool
renderProvider func(ctx context.Context, opts rendering.Opts) (*rendering.RenderResult, error) renderProvider func(ctx context.Context, opts rendering.Opts) (*rendering.RenderResult, error)
renderErrorImageProvider func(error error) (*rendering.RenderResult, error) renderErrorImageProvider func(error error) (*rendering.RenderResult, error)
} }
@ -343,13 +343,13 @@ func (s *testRenderService) SanitizeSVG(ctx context.Context, req *rendering.Sani
return &rendering.SanitizeSVGResponse{Sanitized: req.Content}, nil return &rendering.SanitizeSVGResponse{Sanitized: req.Content}, nil
} }
func (s *testRenderService) HasCapability(feature rendering.CapabilityName) (rendering.CapabilitySupportRequestResult, error) { func (s *testRenderService) HasCapability(_ context.Context, feature rendering.CapabilityName) (rendering.CapabilitySupportRequestResult, error) {
return rendering.CapabilitySupportRequestResult{}, nil return rendering.CapabilitySupportRequestResult{}, nil
} }
func (s *testRenderService) IsAvailable() bool { func (s *testRenderService) IsAvailable(ctx context.Context) bool {
if s.isAvailableProvider != nil { if s.isAvailableProvider != nil {
return s.isAvailableProvider() return s.isAvailableProvider(ctx)
} }
return true return true

View File

@ -1,6 +1,7 @@
package rendering package rendering
import ( import (
"context"
"errors" "errors"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
@ -22,8 +23,8 @@ const (
var ErrUnknownCapability = errors.New("unknown capability") var ErrUnknownCapability = errors.New("unknown capability")
var ErrInvalidPluginVersion = errors.New("invalid plugin version") var ErrInvalidPluginVersion = errors.New("invalid plugin version")
func (rs *RenderingService) HasCapability(capability CapabilityName) (CapabilitySupportRequestResult, error) { func (rs *RenderingService) HasCapability(ctx context.Context, capability CapabilityName) (CapabilitySupportRequestResult, error) {
if !rs.IsAvailable() { if !rs.IsAvailable(ctx) {
return CapabilitySupportRequestResult{IsSupported: false, SemverConstraint: ""}, ErrRenderUnavailable return CapabilitySupportRequestResult{IsSupported: false, SemverConstraint: ""}, ErrRenderUnavailable
} }

View File

@ -1,6 +1,7 @@
package rendering package rendering
import ( import (
"context"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -12,7 +13,7 @@ import (
type dummyPluginManager struct{} type dummyPluginManager struct{}
func (d *dummyPluginManager) Renderer() *plugins.Plugin { func (d *dummyPluginManager) Renderer(_ context.Context) *plugins.Plugin {
return nil return nil
} }
@ -123,7 +124,7 @@ func TestCapabilities(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
rs.Cfg.RendererUrl = tt.rendererUrl rs.Cfg.RendererUrl = tt.rendererUrl
rs.version = tt.rendererVersion rs.version = tt.rendererVersion
res, err := rs.HasCapability(tt.capabilityName) res, err := rs.HasCapability(context.Background(), tt.capabilityName)
if tt.expectedError == nil { if tt.expectedError == nil {
require.NoError(t, err) require.NoError(t, err)

View File

@ -117,13 +117,13 @@ type CapabilitySupportRequestResult struct {
//go:generate mockgen -destination=mock.go -package=rendering github.com/grafana/grafana/pkg/services/rendering Service //go:generate mockgen -destination=mock.go -package=rendering github.com/grafana/grafana/pkg/services/rendering Service
type Service interface { type Service interface {
IsAvailable() bool IsAvailable(ctx context.Context) bool
Version() string Version() string
Render(ctx context.Context, opts Opts, session Session) (*RenderResult, error) Render(ctx context.Context, opts Opts, session Session) (*RenderResult, error)
RenderCSV(ctx context.Context, opts CSVOpts, session Session) (*RenderCSVResult, error) RenderCSV(ctx context.Context, opts CSVOpts, session Session) (*RenderCSVResult, error)
RenderErrorImage(theme models.Theme, error error) (*RenderResult, error) RenderErrorImage(theme models.Theme, error error) (*RenderResult, error)
GetRenderUser(ctx context.Context, key string) (*RenderUser, bool) GetRenderUser(ctx context.Context, key string) (*RenderUser, bool)
HasCapability(capability CapabilityName) (CapabilitySupportRequestResult, error) HasCapability(ctx context.Context, capability CapabilityName) (CapabilitySupportRequestResult, error)
CreateRenderingSession(ctx context.Context, authOpts AuthOpts, sessionOpts SessionOpts) (Session, error) CreateRenderingSession(ctx context.Context, authOpts AuthOpts, sessionOpts SessionOpts) (Session, error)
SanitizeSVG(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error) SanitizeSVG(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error)
} }

View File

@ -66,32 +66,32 @@ func (mr *MockServiceMockRecorder) GetRenderUser(arg0, arg1 interface{}) *gomock
} }
// HasCapability mocks base method. // HasCapability mocks base method.
func (m *MockService) HasCapability(arg0 CapabilityName) (CapabilitySupportRequestResult, error) { func (m *MockService) HasCapability(arg0 context.Context, arg1 CapabilityName) (CapabilitySupportRequestResult, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HasCapability", arg0) ret := m.ctrl.Call(m, "HasCapability", arg0, arg1)
ret0, _ := ret[0].(CapabilitySupportRequestResult) ret0, _ := ret[0].(CapabilitySupportRequestResult)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// HasCapability indicates an expected call of HasCapability. // HasCapability indicates an expected call of HasCapability.
func (mr *MockServiceMockRecorder) HasCapability(arg0 interface{}) *gomock.Call { func (mr *MockServiceMockRecorder) HasCapability(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasCapability", reflect.TypeOf((*MockService)(nil).HasCapability), arg0) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasCapability", reflect.TypeOf((*MockService)(nil).HasCapability), arg0, arg1)
} }
// IsAvailable mocks base method. // IsAvailable mocks base method.
func (m *MockService) IsAvailable() bool { func (m *MockService) IsAvailable(arg0 context.Context) bool {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsAvailable") ret := m.ctrl.Call(m, "IsAvailable", arg0)
ret0, _ := ret[0].(bool) ret0, _ := ret[0].(bool)
return ret0 return ret0
} }
// IsAvailable indicates an expected call of IsAvailable. // IsAvailable indicates an expected call of IsAvailable.
func (mr *MockServiceMockRecorder) IsAvailable() *gomock.Call { func (mr *MockServiceMockRecorder) IsAvailable(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAvailable", reflect.TypeOf((*MockService)(nil).IsAvailable)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAvailable", reflect.TypeOf((*MockService)(nil).IsAvailable), arg0)
} }
// Render mocks base method. // Render mocks base method.

View File

@ -156,9 +156,9 @@ func (rs *RenderingService) Run(ctx context.Context) error {
} }
} }
if rs.pluginAvailable() { if rs.pluginAvailable(ctx) {
rs.log = rs.log.New("renderer", "plugin") rs.log = rs.log.New("renderer", "plugin")
rs.pluginInfo = rs.RendererPluginManager.Renderer() rs.pluginInfo = rs.RendererPluginManager.Renderer(ctx)
if err := rs.startPlugin(ctx); err != nil { if err := rs.startPlugin(ctx); err != nil {
return err return err
@ -191,16 +191,16 @@ func (rs *RenderingService) Run(ctx context.Context) error {
return nil return nil
} }
func (rs *RenderingService) pluginAvailable() bool { func (rs *RenderingService) pluginAvailable(ctx context.Context) bool {
return rs.RendererPluginManager.Renderer() != nil return rs.RendererPluginManager.Renderer(ctx) != nil
} }
func (rs *RenderingService) remoteAvailable() bool { func (rs *RenderingService) remoteAvailable() bool {
return rs.Cfg.RendererUrl != "" return rs.Cfg.RendererUrl != ""
} }
func (rs *RenderingService) IsAvailable() bool { func (rs *RenderingService) IsAvailable(ctx context.Context) bool {
return rs.remoteAvailable() || rs.pluginAvailable() return rs.remoteAvailable() || rs.pluginAvailable(ctx)
} }
func (rs *RenderingService) Version() string { func (rs *RenderingService) Version() string {
@ -271,7 +271,7 @@ func (rs *RenderingService) render(ctx context.Context, opts Opts, renderKeyProv
}, nil }, nil
} }
if !rs.IsAvailable() { if !rs.IsAvailable(ctx) {
rs.log.Warn("Could not render image, no image renderer found/installed. " + rs.log.Warn("Could not render image, no image renderer found/installed. " +
"For image rendering support please install the grafana-image-renderer plugin. " + "For image rendering support please install the grafana-image-renderer plugin. " +
"Read more at https://grafana.com/docs/grafana/latest/administration/image_rendering/") "Read more at https://grafana.com/docs/grafana/latest/administration/image_rendering/")
@ -316,7 +316,7 @@ func (rs *RenderingService) RenderCSV(ctx context.Context, opts CSVOpts, session
} }
func (rs *RenderingService) SanitizeSVG(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error) { func (rs *RenderingService) SanitizeSVG(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error) {
capability, err := rs.HasCapability(SvgSanitization) capability, err := rs.HasCapability(ctx, SvgSanitization)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -338,7 +338,7 @@ func (rs *RenderingService) renderCSV(ctx context.Context, opts CSVOpts, renderK
return nil, ErrConcurrentLimitReached return nil, ErrConcurrentLimitReached
} }
if !rs.IsAvailable() { if !rs.IsAvailable(ctx) {
return nil, ErrRenderUnavailable return nil, ErrRenderUnavailable
} }

View File

@ -105,7 +105,7 @@ func TestRenderErrorImage(t *testing.T) {
type unavailableRendererManager struct{} type unavailableRendererManager struct{}
func (m unavailableRendererManager) Renderer() *plugins.Plugin { return nil } func (m unavailableRendererManager) Renderer(_ context.Context) *plugins.Plugin { return nil }
func TestRenderUnavailableError(t *testing.T) { func TestRenderUnavailableError(t *testing.T) {
rs := RenderingService{ rs := RenderingService{

View File

@ -29,18 +29,19 @@ func ProvideService(
) (SecretsKVStore, error) { ) (SecretsKVStore, error) {
var logger = log.New("secrets.kvstore") var logger = log.New("secrets.kvstore")
var store SecretsKVStore var store SecretsKVStore
ctx := context.Background()
store = NewSQLSecretsKVStore(sqlStore, secretsService, logger) store = NewSQLSecretsKVStore(sqlStore, secretsService, logger)
err := EvaluateRemoteSecretsPlugin(pluginsManager, cfg) err := EvaluateRemoteSecretsPlugin(ctx, pluginsManager, cfg)
if err != nil { if err != nil {
logger.Debug("secrets manager evaluator returned false", "reason", err.Error()) logger.Debug("secrets manager evaluator returned false", "reason", err.Error())
} else { } else {
// Attempt to start the plugin // Attempt to start the plugin
var secretsPlugin secretsmanagerplugin.SecretsManagerPlugin var secretsPlugin secretsmanagerplugin.SecretsManagerPlugin
secretsPlugin, err = StartAndReturnPlugin(pluginsManager, context.Background()) secretsPlugin, err = StartAndReturnPlugin(pluginsManager, ctx)
namespacedKVStore := GetNamespacedKVStore(kvstore) namespacedKVStore := GetNamespacedKVStore(kvstore)
if err != nil || secretsPlugin == nil { if err != nil || secretsPlugin == nil {
logger.Error("failed to start remote secrets management plugin", "msg", err.Error()) logger.Error("failed to start remote secrets management plugin", "msg", err.Error())
if isFatal, readErr := IsPluginStartupErrorFatal(context.Background(), namespacedKVStore); isFatal || readErr != nil { if isFatal, readErr := IsPluginStartupErrorFatal(ctx, namespacedKVStore); isFatal || readErr != nil {
// plugin error was fatal or there was an error determining if the error was fatal // plugin error was fatal or there was an error determining if the error was fatal
logger.Error("secrets management plugin is required to start -- exiting app") logger.Error("secrets management plugin is required to start -- exiting app")
if readErr != nil { if readErr != nil {

View File

@ -96,7 +96,7 @@ func (s *MigrateFromPluginService) Migrate(ctx context.Context) error {
logger.Debug("Shutting down secrets plugin now that migration is complete") logger.Debug("Shutting down secrets plugin now that migration is complete")
// if `use_plugin` wasn't set, stop the plugin after migration // if `use_plugin` wasn't set, stop the plugin after migration
if !s.cfg.SectionWithEnvOverrides("secrets").Key("use_plugin").MustBool(false) { if !s.cfg.SectionWithEnvOverrides("secrets").Key("use_plugin").MustBool(false) {
err := s.manager.SecretsManager().Stop(ctx) err := s.manager.SecretsManager(ctx).Stop(ctx)
if err != nil { if err != nil {
// Log a warning but don't throw an error // Log a warning but don't throw an error
logger.Error("Error stopping secrets plugin after migration", "error", err.Error()) logger.Error("Error stopping secrets plugin after migration", "error", err.Error())

View File

@ -57,7 +57,7 @@ func setupTestMigrateFromPluginService(t *testing.T) (*MigrateFromPluginService,
secretsSql := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger")) secretsSql := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
return migratorService, manager.SecretsManager().SecretsManager, secretsSql return migratorService, manager.SecretsManager(context.Background()).SecretsManager, secretsSql
} }
func addSecretToPluginStore(t *testing.T, plugin secretsmanagerplugin.SecretsManagerPlugin, ctx context.Context, orgId int64, namespace string, typ string, value string) { func addSecretToPluginStore(t *testing.T, plugin secretsmanagerplugin.SecretsManagerPlugin, ctx context.Context, orgId int64, namespace string, typ string, value string) {

View File

@ -43,7 +43,7 @@ func ProvideMigrateToPluginService(
} }
func (s *MigrateToPluginService) Migrate(ctx context.Context) error { func (s *MigrateToPluginService) Migrate(ctx context.Context) error {
if err := secretskvs.EvaluateRemoteSecretsPlugin(s.manager, s.cfg); err == nil { if err := secretskvs.EvaluateRemoteSecretsPlugin(ctx, s.manager, s.cfg); err == nil {
logger.Debug("starting migration of unified secrets to the plugin") logger.Debug("starting migration of unified secrets to the plugin")
// we need to get the fallback store since in this scenario the secrets store would be the plugin. // we need to get the fallback store since in this scenario the secrets store would be the plugin.
fallbackStore := s.secretsStore.Fallback() fallbackStore := s.secretsStore.Fallback()

View File

@ -225,12 +225,12 @@ func SetPluginStartupErrorFatal(ctx context.Context, kvstore *kvstore.Namespaced
return kvstore.Set(ctx, QuitOnPluginStartupFailureKey, "true") return kvstore.Set(ctx, QuitOnPluginStartupFailureKey, "true")
} }
func EvaluateRemoteSecretsPlugin(mg plugins.SecretsPluginManager, cfg *setting.Cfg) error { func EvaluateRemoteSecretsPlugin(ctx context.Context, mg plugins.SecretsPluginManager, cfg *setting.Cfg) error {
usePlugin := cfg.SectionWithEnvOverrides("secrets").Key("use_plugin").MustBool() usePlugin := cfg.SectionWithEnvOverrides("secrets").Key("use_plugin").MustBool()
if !usePlugin { if !usePlugin {
return errPluginDisabledByConfig return errPluginDisabledByConfig
} }
pluginInstalled := mg.SecretsManager() != nil pluginInstalled := mg.SecretsManager(ctx) != nil
if !pluginInstalled { if !pluginInstalled {
return errPluginNotInstalled return errPluginNotInstalled
} }
@ -240,10 +240,10 @@ func EvaluateRemoteSecretsPlugin(mg plugins.SecretsPluginManager, cfg *setting.C
func StartAndReturnPlugin(mg plugins.SecretsPluginManager, ctx context.Context) (smp.SecretsManagerPlugin, error) { func StartAndReturnPlugin(mg plugins.SecretsPluginManager, ctx context.Context) (smp.SecretsManagerPlugin, error) {
var err error var err error
startupOnce.Do(func() { startupOnce.Do(func() {
err = mg.SecretsManager().Start(ctx) err = mg.SecretsManager(ctx).Start(ctx)
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
return mg.SecretsManager().SecretsManager, nil return mg.SecretsManager(ctx).SecretsManager, nil
} }

View File

@ -52,7 +52,7 @@ func TestFatalPluginErr_FatalFlagGetsUnSetWithBackwardsCompatEnabled(t *testing.
require.NotNil(t, p.SecretsKVStore) require.NotNil(t, p.SecretsKVStore)
// setup - store secret and manually bypassing the remote plugin impl // setup - store secret and manually bypassing the remote plugin impl
_, err = p.PluginManager.SecretsManager().SecretsManager.SetSecret(context.Background(), &secretsmanagerplugin.SetSecretRequest{ _, err = p.PluginManager.SecretsManager(context.Background()).SecretsManager.SetSecret(context.Background(), &secretsmanagerplugin.SetSecretRequest{
KeyDescriptor: &secretsmanagerplugin.Key{ KeyDescriptor: &secretsmanagerplugin.Key{
OrgId: 0, OrgId: 0,
Namespace: "postgres", Namespace: "postgres",

View File

@ -196,7 +196,7 @@ type fakePluginManager struct {
plugin *plugins.Plugin plugin *plugins.Plugin
} }
func (mg *fakePluginManager) SecretsManager() *plugins.Plugin { func (mg *fakePluginManager) SecretsManager(_ context.Context) *plugins.Plugin {
if mg.plugin != nil { if mg.plugin != nil {
return mg.plugin return mg.plugin
} }

View File

@ -123,7 +123,7 @@ func (d byOrgId) Less(i, j int) bool { return d[i].OrgId > d[j].OrgId }
func (d byOrgId) Swap(i, j int) { d[i], d[j] = d[j], d[i] } func (d byOrgId) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (r *simpleCrawler) Run(ctx context.Context, auth CrawlerAuth, mode CrawlerMode, theme models.Theme, thumbnailKind models.ThumbnailKind) error { func (r *simpleCrawler) Run(ctx context.Context, auth CrawlerAuth, mode CrawlerMode, theme models.Theme, thumbnailKind models.ThumbnailKind) error {
res, err := r.renderService.HasCapability(rendering.ScalingDownImages) res, err := r.renderService.HasCapability(ctx, rendering.ScalingDownImages)
if err != nil { if err != nil {
return err return err
} }

View File

@ -317,7 +317,7 @@ func (hs *thumbService) GetDashboardPreviewsSetupSettings(c *models.ReqContext)
} }
func (hs *thumbService) getDashboardPreviewsSetupSettings(ctx context.Context) dashboardPreviewsSetupConfig { func (hs *thumbService) getDashboardPreviewsSetupSettings(ctx context.Context) dashboardPreviewsSetupConfig {
systemRequirements := hs.getSystemRequirements() systemRequirements := hs.getSystemRequirements(ctx)
thumbnailsExist, err := hs.thumbnailRepo.doThumbnailsExist(ctx) thumbnailsExist, err := hs.thumbnailRepo.doThumbnailsExist(ctx)
if err != nil { if err != nil {
@ -333,8 +333,8 @@ func (hs *thumbService) getDashboardPreviewsSetupSettings(ctx context.Context) d
} }
} }
func (hs *thumbService) getSystemRequirements() dashboardPreviewsSystemRequirements { func (hs *thumbService) getSystemRequirements(ctx context.Context) dashboardPreviewsSystemRequirements {
res, err := hs.renderingService.HasCapability(rendering.ScalingDownImages) res, err := hs.renderingService.HasCapability(ctx, rendering.ScalingDownImages)
if err != nil { if err != nil {
hs.log.Error("Error when verifying dashboard previews system requirements thumbnail", "err", err.Error()) hs.log.Error("Error when verifying dashboard previews system requirements thumbnail", "err", err.Error())
return dashboardPreviewsSystemRequirements{ return dashboardPreviewsSystemRequirements{