Plugins: Refactor creation of plugin context to dedicated service (#66451)
* first pass * fix tests * return errs * change signature * tidy * delete unnecessary fields from test * tidy * fix tests * simplify * separate error check in API * apply nits
This commit is contained in:
+8
-21
@@ -20,7 +20,7 @@ import (
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/datasources/permissions"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/adapters"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@@ -811,23 +811,16 @@ func (hs *HTTPServer) CheckDatasourceHealth(c *contextmodel.ReqContext) response
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) checkDatasourceHealth(c *contextmodel.ReqContext, ds *datasources.DataSource) response.Response {
|
||||
plugin, exists := hs.pluginStore.Plugin(c.Req.Context(), ds.Type)
|
||||
if !exists {
|
||||
return response.Error(http.StatusInternalServerError, "Unable to find datasource plugin", nil)
|
||||
}
|
||||
|
||||
dsInstanceSettings, err := adapters.ModelToInstanceSettings(ds, hs.decryptSecureJsonDataFn(c.Req.Context()))
|
||||
pCtx, err := hs.pluginContextProvider.GetWithDataSource(c.Req.Context(), ds.Type, c.SignedInUser, ds)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Unable to get datasource model", err)
|
||||
if errors.Is(err, plugincontext.ErrPluginNotFound) {
|
||||
return response.Error(http.StatusNotFound, "Unable to find datasource plugin", nil)
|
||||
}
|
||||
return response.Error(http.StatusInternalServerError, "Unable to get plugin context", err)
|
||||
}
|
||||
req := &backend.CheckHealthRequest{
|
||||
PluginContext: backend.PluginContext{
|
||||
User: adapters.BackendUserFromSignedInUser(c.SignedInUser),
|
||||
OrgID: c.OrgID,
|
||||
PluginID: plugin.ID,
|
||||
DataSourceInstanceSettings: dsInstanceSettings,
|
||||
},
|
||||
Headers: map[string]string{},
|
||||
PluginContext: pCtx,
|
||||
Headers: map[string]string{},
|
||||
}
|
||||
|
||||
var dsURL string
|
||||
@@ -868,12 +861,6 @@ func (hs *HTTPServer) checkDatasourceHealth(c *contextmodel.ReqContext, ds *data
|
||||
return response.JSON(http.StatusOK, payload)
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) decryptSecureJsonDataFn(ctx context.Context) func(ds *datasources.DataSource) (map[string]string, error) {
|
||||
return func(ds *datasources.DataSource) (map[string]string, error) {
|
||||
return hs.DataSourcesService.DecryptedValues(ctx, ds)
|
||||
}
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) filterDatasourcesByQueryPermission(ctx context.Context, user *user.SignedInUser, ds []*datasources.DataSource) ([]*datasources.DataSource, error) {
|
||||
query := datasources.DatasourcesPermissionFilterQuery{
|
||||
User: user,
|
||||
|
||||
@@ -111,7 +111,7 @@ type HTTPServer struct {
|
||||
namedMiddlewares []routing.RegisterNamedMiddleware
|
||||
bus bus.Bus
|
||||
|
||||
PluginContextProvider *plugincontext.Provider
|
||||
pluginContextProvider *plugincontext.Provider
|
||||
RouteRegister routing.RouteRegister
|
||||
RenderService rendering.Service
|
||||
Cfg *setting.Cfg
|
||||
@@ -291,7 +291,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
||||
SearchService: searchService,
|
||||
Live: live,
|
||||
LivePushGateway: livePushGateway,
|
||||
PluginContextProvider: plugCtxProvider,
|
||||
pluginContextProvider: plugCtxProvider,
|
||||
ContextHandler: contextHandler,
|
||||
LoggerMiddleware: loggerMiddleware,
|
||||
AlertNG: alertNG,
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
@@ -22,6 +23,9 @@ func (hs *HTTPServer) handleQueryMetricsError(err error) *response.NormalRespons
|
||||
if errors.Is(err, datasources.ErrDataSourceNotFound) {
|
||||
return response.Error(http.StatusNotFound, "Data source not found", err)
|
||||
}
|
||||
if errors.Is(err, plugincontext.ErrPluginNotFound) {
|
||||
return response.Error(http.StatusNotFound, "Plugin not found", err)
|
||||
}
|
||||
|
||||
var secretsPlugin datasources.ErrDatasourceSecretsPluginUserFriendly
|
||||
if errors.As(err, &secretsPlugin) {
|
||||
|
||||
+40
-3
@@ -14,6 +14,8 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db/dbtest"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
@@ -22,8 +24,12 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
||||
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
|
||||
"github.com/grafana/grafana/pkg/services/query"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
secretstest "github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
@@ -50,7 +56,6 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
&fakePluginRequestValidator{},
|
||||
&fakeDatasources.FakeDataSourceService{},
|
||||
&fakePluginClient{
|
||||
QueryDataHandlerFunc: func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
resp := backend.Responses{
|
||||
@@ -61,6 +66,17 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
|
||||
return &backend.QueryDataResponse{Responses: resp}, nil
|
||||
},
|
||||
},
|
||||
plugincontext.ProvideService(localcache.ProvideService(), &plugins.FakePluginStore{
|
||||
PluginList: []plugins.PluginDTO{
|
||||
{
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "grafana",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, &fakeDatasources.FakeDataSourceService{}, pluginSettings.ProvideService(dbtest.NewFakeDB(),
|
||||
secretstest.NewFakeSecretsService()),
|
||||
),
|
||||
)
|
||||
serverFeatureEnabled := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.queryDataService = qds
|
||||
@@ -93,12 +109,25 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAPIEndpoint_Metrics_PluginDecryptionFailure(t *testing.T) {
|
||||
ds := &fakeDatasources.FakeDataSourceService{SimulatePluginFailure: true}
|
||||
db := &dbtest.FakeDB{ExpectedError: pluginsettings.ErrPluginSettingNotFound}
|
||||
pcp := plugincontext.ProvideService(localcache.ProvideService(),
|
||||
&plugins.FakePluginStore{
|
||||
PluginList: []plugins.PluginDTO{
|
||||
{
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "grafana",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ds, pluginSettings.ProvideService(db, secretstest.NewFakeSecretsService()),
|
||||
)
|
||||
qds := query.ProvideService(
|
||||
setting.NewCfg(),
|
||||
nil,
|
||||
nil,
|
||||
&fakePluginRequestValidator{},
|
||||
&fakeDatasources.FakeDataSourceService{SimulatePluginFailure: true},
|
||||
&fakePluginClient{
|
||||
QueryDataHandlerFunc: func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
resp := backend.Responses{
|
||||
@@ -109,10 +138,12 @@ func TestAPIEndpoint_Metrics_PluginDecryptionFailure(t *testing.T) {
|
||||
return &backend.QueryDataResponse{Responses: resp}, nil
|
||||
},
|
||||
},
|
||||
pcp,
|
||||
)
|
||||
httpServer := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.queryDataService = qds
|
||||
hs.QuotaService = quotatest.New(false, nil)
|
||||
hs.pluginContextProvider = pcp
|
||||
})
|
||||
|
||||
t.Run("Status code is 500 and a secrets plugin error is returned if there is a problem getting secrets from the remote plugin", func(t *testing.T) {
|
||||
@@ -255,13 +286,19 @@ func TestDataSourceQueryError(t *testing.T) {
|
||||
r := registry.NewInMemory()
|
||||
err := r.Add(context.Background(), p)
|
||||
require.NoError(t, err)
|
||||
ds := &fakeDatasources.FakeDataSourceService{}
|
||||
hs.queryDataService = query.ProvideService(
|
||||
setting.NewCfg(),
|
||||
&fakeDatasources.FakeCacheService{},
|
||||
nil,
|
||||
&fakePluginRequestValidator{},
|
||||
&fakeDatasources.FakeDataSourceService{},
|
||||
pluginClient.ProvideService(r, &config.Cfg{}),
|
||||
plugincontext.ProvideService(localcache.ProvideService(), &plugins.FakePluginStore{
|
||||
PluginList: []plugins.PluginDTO{p.ToDTO()},
|
||||
},
|
||||
ds, pluginSettings.ProvideService(dbtest.NewFakeDB(),
|
||||
secretstest.NewFakeSecretsService()),
|
||||
),
|
||||
)
|
||||
hs.QuotaService = quotatest.New(false, nil)
|
||||
})
|
||||
|
||||
+11
-10
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/plugins/httpresponsesender"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/util/proxyutil"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
@@ -25,15 +26,15 @@ func (hs *HTTPServer) CallResource(c *contextmodel.ReqContext) {
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) callPluginResource(c *contextmodel.ReqContext, pluginID string) {
|
||||
pCtx, found, err := hs.PluginContextProvider.Get(c.Req.Context(), pluginID, c.SignedInUser)
|
||||
pCtx, err := hs.pluginContextProvider.Get(c.Req.Context(), pluginID, c.SignedInUser)
|
||||
if err != nil {
|
||||
if errors.Is(err, plugincontext.ErrPluginNotFound) {
|
||||
c.JsonApiErr(404, "Plugin not found", nil)
|
||||
return
|
||||
}
|
||||
c.JsonApiErr(500, "Failed to get plugin settings", err)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
c.JsonApiErr(404, "Plugin not found", nil)
|
||||
return
|
||||
}
|
||||
|
||||
req, err := hs.pluginResourceRequest(c)
|
||||
if err != nil {
|
||||
@@ -47,15 +48,15 @@ func (hs *HTTPServer) callPluginResource(c *contextmodel.ReqContext, pluginID st
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) callPluginResourceWithDataSource(c *contextmodel.ReqContext, pluginID string, ds *datasources.DataSource) {
|
||||
pCtx, found, err := hs.PluginContextProvider.GetWithDataSource(c.Req.Context(), pluginID, c.SignedInUser, ds)
|
||||
pCtx, err := hs.pluginContextProvider.GetWithDataSource(c.Req.Context(), pluginID, c.SignedInUser, ds)
|
||||
if err != nil {
|
||||
if errors.Is(err, plugincontext.ErrPluginNotFound) {
|
||||
c.JsonApiErr(404, "Plugin not found", nil)
|
||||
return
|
||||
}
|
||||
c.JsonApiErr(500, "Failed to get plugin settings", err)
|
||||
return
|
||||
}
|
||||
if !found {
|
||||
c.JsonApiErr(404, "Plugin not found", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var dsURL string
|
||||
if pCtx.DataSourceInstanceSettings != nil {
|
||||
|
||||
@@ -42,6 +42,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
fakeSecrets "github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/cloudwatch"
|
||||
@@ -74,11 +75,12 @@ func TestCallResource(t *testing.T) {
|
||||
ps, err := store.ProvideService(reg, srcs, l)
|
||||
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.FakeDataSourceService{},
|
||||
pluginSettings.ProvideService(db.InitTestDB(t), fakeSecrets.NewFakeSecretsService()))
|
||||
|
||||
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = cfg
|
||||
hs.PluginContextProvider = pcp
|
||||
hs.pluginContextProvider = pcp
|
||||
hs.QuotaService = quotatest.New(false, nil)
|
||||
hs.pluginStore = ps
|
||||
hs.pluginClient = pluginClient.ProvideService(reg, pCfg)
|
||||
@@ -117,7 +119,7 @@ func TestCallResource(t *testing.T) {
|
||||
|
||||
srv = SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = cfg
|
||||
hs.PluginContextProvider = pcp
|
||||
hs.pluginContextProvider = pcp
|
||||
hs.QuotaService = quotatest.New(false, nil)
|
||||
hs.pluginStore = ps
|
||||
hs.pluginClient = pc
|
||||
|
||||
+6
-7
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@@ -259,7 +260,7 @@ func (hs *HTTPServer) UpdatePluginSetting(c *contextmodel.ReqContext) response.R
|
||||
return response.Error(500, "Failed to update plugin setting", err)
|
||||
}
|
||||
|
||||
hs.PluginContextProvider.InvalidateSettingsCache(c.Req.Context(), pluginID)
|
||||
hs.pluginContextProvider.InvalidateSettingsCache(c.Req.Context(), pluginID)
|
||||
|
||||
return response.Success("Plugin settings updated")
|
||||
}
|
||||
@@ -392,15 +393,13 @@ func (hs *HTTPServer) redirectCDNPluginAsset(c *contextmodel.ReqContext, plugin
|
||||
// /api/plugins/:pluginId/health
|
||||
func (hs *HTTPServer) CheckHealth(c *contextmodel.ReqContext) response.Response {
|
||||
pluginID := web.Params(c.Req)[":pluginId"]
|
||||
|
||||
pCtx, found, err := hs.PluginContextProvider.Get(c.Req.Context(), pluginID, c.SignedInUser)
|
||||
pCtx, err := hs.pluginContextProvider.Get(c.Req.Context(), pluginID, c.SignedInUser)
|
||||
if err != nil {
|
||||
if errors.Is(err, plugincontext.ErrPluginNotFound) {
|
||||
return response.Error(404, "Plugin not found", nil)
|
||||
}
|
||||
return response.Error(500, "Failed to get plugin settings", err)
|
||||
}
|
||||
if !found {
|
||||
return response.Error(404, "Plugin not found", nil)
|
||||
}
|
||||
|
||||
resp, err := hs.pluginClient.CheckHealth(c.Req.Context(), &backend.CheckHealthRequest{
|
||||
PluginContext: pCtx,
|
||||
Headers: map[string]string{},
|
||||
|
||||
Reference in New Issue
Block a user