From 6a776c78d40d49e0de151939a72d9eb9bb6ae2e1 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Fri, 11 Feb 2022 15:52:14 +0100 Subject: [PATCH] Datasource: Fixes storing of secureJSONData when creating/updating datasource (#45290) Fixes an issue introduced by #44987 where bus dispatch was replaced by calling sqlstore directly instead of the datasource service. Fixes #45273 --- pkg/api/datasources.go | 26 ++-- pkg/api/datasources_test.go | 80 +++++++++--- pkg/api/http_server.go | 4 +- pkg/api/pluginproxy/ds_proxy.go | 11 +- pkg/api/pluginproxy/ds_proxy_test.go | 114 +++++++++--------- pkg/server/wire.go | 4 +- pkg/server/wireexts_oss.go | 5 +- .../datasourceproxy/datasourceproxy.go | 10 +- pkg/services/datasources/datasources.go | 62 ++++++++++ pkg/services/datasources/log.go | 9 -- .../{cache.go => service/cache_service.go} | 14 +-- .../datasource_service.go} | 4 +- .../datasource_service_test.go} | 2 +- pkg/tsdb/legacydata/service/service.go | 5 +- pkg/tsdb/legacydata/service/service_test.go | 4 +- 15 files changed, 230 insertions(+), 124 deletions(-) create mode 100644 pkg/services/datasources/datasources.go delete mode 100644 pkg/services/datasources/log.go rename pkg/services/datasources/{cache.go => service/cache_service.go} (81%) rename pkg/services/datasources/{service.go => service/datasource_service.go} (99%) rename pkg/services/datasources/{service_test.go => service/datasource_service_test.go} (99%) diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index cb54321e91b..5e03b0b37ab 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -27,7 +27,7 @@ var datasourcesLogger = log.New("datasources") func (hs *HTTPServer) GetDataSources(c *models.ReqContext) response.Response { query := models.GetDataSourcesQuery{OrgId: c.OrgId, DataSourceLimit: hs.Cfg.DataSourceLimit} - if err := hs.SQLStore.GetDataSources(c.Req.Context(), &query); err != nil { + if err := hs.DataSourcesService.GetDataSources(c.Req.Context(), &query); err != nil { return response.Error(500, "Failed to query datasources", err) } @@ -98,7 +98,7 @@ func (hs *HTTPServer) GetDataSourceById(c *models.ReqContext) response.Response OrgId: c.OrgId, } - if err := hs.SQLStore.GetDataSource(c.Req.Context(), &query); err != nil { + if err := hs.DataSourcesService.GetDataSource(c.Req.Context(), &query); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { return response.Error(404, "Data source not found", nil) } @@ -149,7 +149,7 @@ func (hs *HTTPServer) DeleteDataSourceById(c *models.ReqContext) response.Respon cmd := &models.DeleteDataSourceCommand{ID: id, OrgID: c.OrgId} - err = hs.SQLStore.DeleteDataSource(c.Req.Context(), cmd) + err = hs.DataSourcesService.DeleteDataSource(c.Req.Context(), cmd) if err != nil { return response.Error(500, "Failed to delete datasource", err) } @@ -209,7 +209,7 @@ func (hs *HTTPServer) DeleteDataSourceByUID(c *models.ReqContext) response.Respo cmd := &models.DeleteDataSourceCommand{UID: uid, OrgID: c.OrgId} - err = hs.SQLStore.DeleteDataSource(c.Req.Context(), cmd) + err = hs.DataSourcesService.DeleteDataSource(c.Req.Context(), cmd) if err != nil { return response.Error(500, "Failed to delete datasource", err) } @@ -231,7 +231,7 @@ func (hs *HTTPServer) DeleteDataSourceByName(c *models.ReqContext) response.Resp } getCmd := &models.GetDataSourceQuery{Name: name, OrgId: c.OrgId} - if err := hs.SQLStore.GetDataSource(c.Req.Context(), getCmd); err != nil { + if err := hs.DataSourcesService.GetDataSource(c.Req.Context(), getCmd); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { return response.Error(404, "Data source not found", nil) } @@ -243,7 +243,7 @@ func (hs *HTTPServer) DeleteDataSourceByName(c *models.ReqContext) response.Resp } cmd := &models.DeleteDataSourceCommand{Name: name, OrgID: c.OrgId} - err := hs.SQLStore.DeleteDataSource(c.Req.Context(), cmd) + err := hs.DataSourcesService.DeleteDataSource(c.Req.Context(), cmd) if err != nil { return response.Error(500, "Failed to delete datasource", err) } @@ -279,7 +279,7 @@ func (hs *HTTPServer) AddDataSource(c *models.ReqContext) response.Response { } } - if err := hs.SQLStore.AddDataSource(c.Req.Context(), &cmd); err != nil { + if err := hs.DataSourcesService.AddDataSource(c.Req.Context(), &cmd); err != nil { if errors.Is(err, models.ErrDataSourceNameExists) || errors.Is(err, models.ErrDataSourceUidExists) { return response.Error(409, err.Error(), err) } @@ -329,7 +329,7 @@ func (hs *HTTPServer) UpdateDataSource(c *models.ReqContext) response.Response { return response.Error(500, "Failed to update datasource", err) } - err = hs.SQLStore.UpdateDataSource(c.Req.Context(), &cmd) + err = hs.DataSourcesService.UpdateDataSource(c.Req.Context(), &cmd) if err != nil { if errors.Is(err, models.ErrDataSourceUpdatingOldVersion) { return response.Error(409, "Datasource has already been updated by someone else. Please reload and try again", err) @@ -342,7 +342,7 @@ func (hs *HTTPServer) UpdateDataSource(c *models.ReqContext) response.Response { OrgId: c.OrgId, } - if err := hs.SQLStore.GetDataSource(c.Req.Context(), &query); err != nil { + if err := hs.DataSourcesService.GetDataSource(c.Req.Context(), &query); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { return response.Error(404, "Data source not found", nil) } @@ -394,7 +394,7 @@ func (hs *HTTPServer) getRawDataSourceById(ctx context.Context, id int64, orgID OrgId: orgID, } - if err := hs.SQLStore.GetDataSource(ctx, &query); err != nil { + if err := hs.DataSourcesService.GetDataSource(ctx, &query); err != nil { return nil, err } @@ -407,7 +407,7 @@ func (hs *HTTPServer) getRawDataSourceByUID(ctx context.Context, uid string, org OrgId: orgID, } - if err := hs.SQLStore.GetDataSource(ctx, &query); err != nil { + if err := hs.DataSourcesService.GetDataSource(ctx, &query); err != nil { return nil, err } @@ -418,7 +418,7 @@ func (hs *HTTPServer) getRawDataSourceByUID(ctx context.Context, uid string, org func (hs *HTTPServer) GetDataSourceByName(c *models.ReqContext) response.Response { query := models.GetDataSourceQuery{Name: web.Params(c.Req)[":name"], OrgId: c.OrgId} - if err := hs.SQLStore.GetDataSource(c.Req.Context(), &query); err != nil { + if err := hs.DataSourcesService.GetDataSource(c.Req.Context(), &query); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { return response.Error(404, "Data source not found", nil) } @@ -438,7 +438,7 @@ func (hs *HTTPServer) GetDataSourceByName(c *models.ReqContext) response.Respons func (hs *HTTPServer) GetDataSourceIdByName(c *models.ReqContext) response.Response { query := models.GetDataSourceQuery{Name: web.Params(c.Req)[":name"], OrgId: c.OrgId} - if err := hs.SQLStore.GetDataSource(c.Req.Context(), &query); err != nil { + if err := hs.DataSourcesService.GetDataSource(c.Req.Context(), &query); err != nil { if errors.Is(err, models.ErrDataSourceNotFound) { return response.Error(404, "Data source not found", nil) } diff --git a/pkg/api/datasources_test.go b/pkg/api/datasources_test.go index c92cad413bb..0005e7d1aff 100644 --- a/pkg/api/datasources_test.go +++ b/pkg/api/datasources_test.go @@ -2,6 +2,7 @@ package api import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -13,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" @@ -36,14 +38,15 @@ func TestDataSourcesProxy_userLoggedIn(t *testing.T) { {Name: "BBB"}, {Name: "aaa"}, } - mockSQLStore.ExpectedDatasources = ds mockDatasourcePermissionService.dsResult = ds // handler func being tested hs := &HTTPServer{ - Cfg: setting.NewCfg(), - pluginStore: &fakePluginStore{}, - SQLStore: mockSQLStore, + Cfg: setting.NewCfg(), + pluginStore: &fakePluginStore{}, + DataSourcesService: &dataSourcesServiceMock{ + expectedDatasources: ds, + }, DatasourcePermissionsService: mockDatasourcePermissionService, } sc.handlerFunc = hs.GetDataSources @@ -76,7 +79,7 @@ func TestDataSourcesProxy_userLoggedIn(t *testing.T) { func TestAddDataSource_InvalidURL(t *testing.T) { sc := setupScenarioContext(t, "/api/datasources") hs := &HTTPServer{ - SQLStore: mockstore.NewSQLStoreMock(), + DataSourcesService: &dataSourcesServiceMock{}, } sc.m.Post(sc.url, routing.Wrap(func(c *models.ReqContext) response.Response { @@ -99,10 +102,10 @@ func TestAddDataSource_URLWithoutProtocol(t *testing.T) { const name = "Test" const url = "localhost:5432" - mockSQLStore := mockstore.NewSQLStoreMock() - mockSQLStore.ExpectedDatasource = &models.DataSource{} hs := &HTTPServer{ - SQLStore: mockSQLStore, + DataSourcesService: &dataSourcesServiceMock{ + expectedDatasource: &models.DataSource{}, + }, } sc := setupScenarioContext(t, "/api/datasources") @@ -125,7 +128,7 @@ func TestAddDataSource_URLWithoutProtocol(t *testing.T) { // Updating data sources with invalid URLs should lead to an error. func TestUpdateDataSource_InvalidURL(t *testing.T) { hs := &HTTPServer{ - SQLStore: mockstore.NewSQLStoreMock(), + DataSourcesService: &dataSourcesServiceMock{}, } sc := setupScenarioContext(t, "/api/datasources/1234") @@ -149,12 +152,11 @@ func TestUpdateDataSource_URLWithoutProtocol(t *testing.T) { const name = "Test" const url = "localhost:5432" - mockSQLStore := mockstore.NewSQLStoreMock() hs := &HTTPServer{ - SQLStore: mockSQLStore, + DataSourcesService: &dataSourcesServiceMock{ + expectedDatasource: &models.DataSource{}, + }, } - // Stub handler - mockSQLStore.ExpectedDatasource = &models.DataSource{} sc := setupScenarioContext(t, "/api/datasources/1234") @@ -204,8 +206,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) { return bytes.NewReader(s) } - sqlStore := mockstore.NewSQLStoreMock() - sqlStore.ExpectedDatasource = &testDatasource + dsServiceMock := &dataSourcesServiceMock{ + expectedDatasource: &testDatasource, + } dsPermissionService := newMockDatasourcePermissionService() dsPermissionService.dsResult = []*models.DataSource{ &testDatasource, @@ -500,14 +503,13 @@ func TestAPI_Datasources_AccessControl(t *testing.T) { sc, hs := setupAccessControlScenarioContext(t, cfg, test.url, test.permissions) // mock sqlStore and datasource permission service - sqlStore.ExpectedError = test.expectedSQLError - sqlStore.ExpectedDatasource = test.expectedDS + dsServiceMock.expectedError = test.expectedSQLError + dsServiceMock.expectedDatasource = test.expectedDS dsPermissionService.dsResult = []*models.DataSource{test.expectedDS} if test.expectedDS == nil { dsPermissionService.dsResult = nil } - sc.sqlStore = sqlStore - hs.SQLStore = sqlStore + hs.DataSourcesService = dsServiceMock hs.DatasourcePermissionsService = dsPermissionService // Create a middleware to pretend user is logged in @@ -539,3 +541,43 @@ func TestAPI_Datasources_AccessControl(t *testing.T) { }) } } + +type dataSourcesServiceMock struct { + datasources.DataSourceService + + expectedDatasources []*models.DataSource + expectedDatasource *models.DataSource + expectedError error +} + +func (m *dataSourcesServiceMock) GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error { + query.Result = m.expectedDatasource + return m.expectedError +} + +func (m *dataSourcesServiceMock) GetDataSources(ctx context.Context, query *models.GetDataSourcesQuery) error { + query.Result = m.expectedDatasources + return m.expectedError +} + +func (m *dataSourcesServiceMock) GetDataSourcesByType(ctx context.Context, query *models.GetDataSourcesByTypeQuery) error { + return m.expectedError +} + +func (m *dataSourcesServiceMock) GetDefaultDataSource(ctx context.Context, query *models.GetDefaultDataSourceQuery) error { + return m.expectedError +} + +func (m *dataSourcesServiceMock) DeleteDataSource(ctx context.Context, cmd *models.DeleteDataSourceCommand) error { + return m.expectedError +} + +func (m *dataSourcesServiceMock) AddDataSource(ctx context.Context, cmd *models.AddDataSourceCommand) error { + cmd.Result = m.expectedDatasource + return m.expectedError +} + +func (m *dataSourcesServiceMock) UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSourceCommand) error { + cmd.Result = m.expectedDatasource + return m.expectedError +} diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 3da4a233ce1..af58dbc2744 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -117,7 +117,7 @@ type HTTPServer struct { Listener net.Listener EncryptionService encryption.Internal SecretsService secrets.Service - DataSourcesService *datasources.Service + DataSourcesService datasources.DataSourceService cleanUpService *cleanup.CleanUpService tracer tracing.Tracer grafanaUpdateChecker *updatechecker.GrafanaService @@ -155,7 +155,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi quotaService *quota.QuotaService, socialService social.Service, tracer tracing.Tracer, encryptionService encryption.Internal, grafanaUpdateChecker *updatechecker.GrafanaService, pluginsUpdateChecker *updatechecker.PluginsService, searchUsersService searchusers.Service, - dataSourcesService *datasources.Service, secretsService secrets.Service, queryDataService *query.Service, + dataSourcesService datasources.DataSourceService, secretsService secrets.Service, queryDataService *query.Service, ldapGroups ldap.Groups, teamGuardian teamguardian.TeamGuardian, serviceaccountsService serviceaccounts.Service, authInfoService login.AuthInfoService, resourcePermissionServices *resourceservices.ResourceServices, notificationService *notifications.NotificationService, datasourcePermissionsService DatasourcePermissionsService) (*HTTPServer, error) { diff --git a/pkg/api/pluginproxy/ds_proxy.go b/pkg/api/pluginproxy/ds_proxy.go index f7b10b1c76b..fc12967768b 100644 --- a/pkg/api/pluginproxy/ds_proxy.go +++ b/pkg/api/pluginproxy/ds_proxy.go @@ -21,6 +21,7 @@ import ( "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/oauthtoken" + "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util/proxyutil" @@ -42,8 +43,9 @@ type DataSourceProxy struct { cfg *setting.Cfg clientProvider httpclient.Provider oAuthTokenService oauthtoken.OAuthTokenService - dataSourcesService *datasources.Service + dataSourcesService datasources.DataSourceService tracer tracing.Tracer + secretsService secrets.Service } type handleResponseTransport struct { @@ -78,8 +80,8 @@ func (lw *logWrapper) Write(p []byte) (n int, err error) { // NewDataSourceProxy creates a new Datasource proxy func NewDataSourceProxy(ds *models.DataSource, pluginRoutes []*plugins.Route, ctx *models.ReqContext, proxyPath string, cfg *setting.Cfg, clientProvider httpclient.Provider, - oAuthTokenService oauthtoken.OAuthTokenService, dsService *datasources.Service, - tracer tracing.Tracer) (*DataSourceProxy, error) { + oAuthTokenService oauthtoken.OAuthTokenService, dsService datasources.DataSourceService, + tracer tracing.Tracer, secretsService secrets.Service) (*DataSourceProxy, error) { targetURL, err := datasource.ValidateURL(ds.Type, ds.Url) if err != nil { return nil, err @@ -96,6 +98,7 @@ func NewDataSourceProxy(ds *models.DataSource, pluginRoutes []*plugins.Route, ct oAuthTokenService: oAuthTokenService, dataSourcesService: dsService, tracer: tracer, + secretsService: secretsService, }, nil } @@ -250,7 +253,7 @@ func (proxy *DataSourceProxy) director(req *http.Request) { } } - secureJsonData, err := proxy.dataSourcesService.SecretsService.DecryptJsonData(req.Context(), proxy.ds.SecureJsonData) + secureJsonData, err := proxy.secretsService.DecryptJsonData(req.Context(), proxy.ds.SecureJsonData) if err != nil { logger.Error("Error interpolating proxy url", "error", err) return diff --git a/pkg/api/pluginproxy/ds_proxy_test.go b/pkg/api/pluginproxy/ds_proxy_test.go index 084db92035b..bd1808aed6b 100644 --- a/pkg/api/pluginproxy/ds_proxy_test.go +++ b/pkg/api/pluginproxy/ds_proxy_test.go @@ -20,7 +20,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" - "github.com/grafana/grafana/pkg/services/datasources" + datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service" "github.com/grafana/grafana/pkg/services/oauthtoken" "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets/fakes" @@ -129,9 +129,9 @@ func TestDataSourceProxy_routeRule(t *testing.T) { t.Run("When matching route path", func(t *testing.T) { ctx, req := setUp() - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider, - &oauthtoken.Service{}, dsService, tracer) + &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.matchedRoute = routes[0] ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg) @@ -142,8 +142,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { t.Run("When matching route path and has dynamic url", func(t *testing.T) { ctx, req := setUp() - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/common/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/common/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.matchedRoute = routes[3] ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg) @@ -154,8 +154,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { t.Run("When matching route path with no url", func(t *testing.T) { ctx, req := setUp() - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.matchedRoute = routes[4] ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg) @@ -165,8 +165,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { t.Run("When matching route path and has dynamic body", func(t *testing.T) { ctx, req := setUp() - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/body", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/body", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.matchedRoute = routes[5] ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg) @@ -179,8 +179,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { t.Run("Validating request", func(t *testing.T) { t.Run("plugin route with valid role", func(t *testing.T) { ctx, _ := setUp() - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) err = proxy.validateRequest() require.NoError(t, err) @@ -188,8 +188,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { t.Run("plugin route with admin role and user is editor", func(t *testing.T) { ctx, _ := setUp() - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) err = proxy.validateRequest() require.Error(t, err) @@ -198,8 +198,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { t.Run("plugin route with admin role and user is admin", func(t *testing.T) { ctx, _ := setUp() ctx.SignedInUser.OrgRole = models.ROLE_ADMIN - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) err = proxy.validateRequest() require.NoError(t, err) @@ -289,8 +289,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { }, } - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg) @@ -305,8 +305,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { req, err := http.NewRequest("GET", "http://localhost/asd", nil) require.NoError(t, err) client = newFakeHTTPClient(t, json2) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken2", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken2", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[1], dsInfo, cfg) @@ -322,8 +322,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { require.NoError(t, err) client = newFakeHTTPClient(t, []byte{}) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg) @@ -344,8 +344,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { ctx := &models.ReqContext{} secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{BuildVersion: "5.3.0"}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{BuildVersion: "5.3.0"}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil) require.NoError(t, err) @@ -370,8 +370,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { ctx := &models.ReqContext{} var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil) @@ -394,8 +394,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { ctx := &models.ReqContext{} var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) requestURL, err := url.Parse("http://grafana.com/sub") @@ -422,8 +422,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { ctx := &models.ReqContext{} var pluginRoutes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, pluginRoutes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, pluginRoutes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) requestURL, err := url.Parse("http://grafana.com/sub") @@ -445,8 +445,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { ctx := &models.ReqContext{} var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil) req.Header.Set("Origin", "grafana.com") @@ -509,8 +509,8 @@ func TestDataSourceProxy_routeRule(t *testing.T) { var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &mockAuthToken, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &mockAuthToken, dsService, tracer, secretsService) require.NoError(t, err) req, err = http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil) require.NoError(t, err) @@ -642,8 +642,8 @@ func TestDataSourceProxy_requestHandling(t *testing.T) { ctx, ds := setUp(t) var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.HandleRequest() @@ -660,8 +660,8 @@ func TestDataSourceProxy_requestHandling(t *testing.T) { }) var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.HandleRequest() @@ -674,8 +674,8 @@ func TestDataSourceProxy_requestHandling(t *testing.T) { ctx, ds := setUp(t) var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.HandleRequest() @@ -696,8 +696,8 @@ func TestDataSourceProxy_requestHandling(t *testing.T) { }) var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.HandleRequest() @@ -721,8 +721,8 @@ func TestDataSourceProxy_requestHandling(t *testing.T) { ctx.Req = httptest.NewRequest("GET", "/api/datasources/proxy/1/path/%2Ftest%2Ftest%2F?query=%2Ftest%2Ftest%2F", nil) var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.HandleRequest() @@ -745,8 +745,8 @@ func TestDataSourceProxy_requestHandling(t *testing.T) { ctx.Req = httptest.NewRequest("GET", "/api/datasources/proxy/1/path/%2Ftest%2Ftest%2F?query=%2Ftest%2Ftest%2F", nil) var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) proxy.HandleRequest() @@ -770,8 +770,8 @@ func TestNewDataSourceProxy_InvalidURL(t *testing.T) { require.NoError(t, err) var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - _, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + _, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService) require.Error(t, err) assert.True(t, strings.HasPrefix(err.Error(), `validation of data source URL "://host/root" failed`)) } @@ -791,8 +791,8 @@ func TestNewDataSourceProxy_ProtocolLessURL(t *testing.T) { var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - _, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + _, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) } @@ -834,8 +834,8 @@ func TestNewDataSourceProxy_MSSQL(t *testing.T) { var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - p, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + p, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService) if tc.err == nil { require.NoError(t, err) assert.Equal(t, &url.URL{ @@ -861,8 +861,8 @@ func getDatasourceProxiedRequest(t *testing.T, ctx *models.ReqContext, cfg *sett var routes []*plugins.Route secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil) require.NoError(t, err) @@ -985,8 +985,8 @@ func runDatasourceAuthTest(t *testing.T, secretsService secrets.Service, test *t require.NoError(t, err) var routes []*plugins.Route - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(test.datasource, routes, ctx, "", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(test.datasource, routes, ctx, "", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil) @@ -1027,8 +1027,8 @@ func Test_PathCheck(t *testing.T) { } ctx, _ := setUp() secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) - proxy, err := NewDataSourceProxy(&models.DataSource{}, routes, ctx, "b", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + proxy, err := NewDataSourceProxy(&models.DataSource{}, routes, ctx, "b", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer, secretsService) require.NoError(t, err) require.Nil(t, proxy.validateRequest()) diff --git a/pkg/server/wire.go b/pkg/server/wire.go index 263a3844ea7..3e07435538c 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -37,6 +37,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboardsnapshots" "github.com/grafana/grafana/pkg/services/datasourceproxy" "github.com/grafana/grafana/pkg/services/datasources" + datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/hooks" "github.com/grafana/grafana/pkg/services/libraryelements" @@ -183,7 +184,8 @@ var wireBasicSet = wire.NewSet( wire.Bind(new(secrets.Store), new(*secretsDatabase.SecretsStoreImpl)), grafanads.ProvideService, dashboardsnapshots.ProvideService, - datasources.ProvideService, + datasourceservice.ProvideService, + wire.Bind(new(datasources.DataSourceService), new(*datasourceservice.Service)), pluginsettings.ProvideService, alerting.ProvideService, serviceaccountsmanager.ProvideServiceAccountsService, diff --git a/pkg/server/wireexts_oss.go b/pkg/server/wireexts_oss.go index b91578d4456..6c694411593 100644 --- a/pkg/server/wireexts_oss.go +++ b/pkg/server/wireexts_oss.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions" "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/datasources" + datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service" "github.com/grafana/grafana/pkg/services/encryption" "github.com/grafana/grafana/pkg/services/encryption/ossencryption" "github.com/grafana/grafana/pkg/services/kmsproviders" @@ -51,8 +52,8 @@ var wireExtsBasicSet = wire.NewSet( wire.Bind(new(provisioning.ProvisioningService), new(*provisioning.ProvisioningServiceImpl)), backgroundsvcs.ProvideBackgroundServiceRegistry, wire.Bind(new(registry.BackgroundServiceRegistry), new(*backgroundsvcs.BackgroundServiceRegistry)), - datasources.ProvideCacheService, - wire.Bind(new(datasources.CacheService), new(*datasources.CacheServiceImpl)), + datasourceservice.ProvideCacheService, + wire.Bind(new(datasources.CacheService), new(*datasourceservice.CacheServiceImpl)), migrations.ProvideOSSMigrations, wire.Bind(new(registry.DatabaseMigrator), new(*migrations.OSSMigrations)), authinfoservice.ProvideOSSUserProtectionService, diff --git a/pkg/services/datasourceproxy/datasourceproxy.go b/pkg/services/datasourceproxy/datasourceproxy.go index d8aa1607724..fc101016b87 100644 --- a/pkg/services/datasourceproxy/datasourceproxy.go +++ b/pkg/services/datasourceproxy/datasourceproxy.go @@ -16,13 +16,15 @@ import ( "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/oauthtoken" + "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" ) func ProvideService(dataSourceCache datasources.CacheService, plugReqValidator models.PluginRequestValidator, pluginStore plugins.Store, cfg *setting.Cfg, httpClientProvider httpclient.Provider, - oauthTokenService *oauthtoken.Service, dsService *datasources.Service, tracer tracing.Tracer) *DataSourceProxyService { + oauthTokenService *oauthtoken.Service, dsService datasources.DataSourceService, + tracer tracing.Tracer, secretsService secrets.Service) *DataSourceProxyService { return &DataSourceProxyService{ DataSourceCache: dataSourceCache, PluginRequestValidator: plugReqValidator, @@ -32,6 +34,7 @@ func ProvideService(dataSourceCache datasources.CacheService, plugReqValidator m OAuthTokenService: oauthTokenService, DataSourcesService: dsService, tracer: tracer, + secretsService: secretsService, } } @@ -42,8 +45,9 @@ type DataSourceProxyService struct { Cfg *setting.Cfg HTTPClientProvider httpclient.Provider OAuthTokenService *oauthtoken.Service - DataSourcesService *datasources.Service + DataSourcesService datasources.DataSourceService tracer tracing.Tracer + secretsService secrets.Service } func (p *DataSourceProxyService) ProxyDataSourceRequest(c *models.ReqContext) { @@ -87,7 +91,7 @@ func (p *DataSourceProxyService) ProxyDatasourceRequestWithID(c *models.ReqConte proxyPath := getProxyPath(c) proxy, err := pluginproxy.NewDataSourceProxy(ds, plugin.Routes, c, proxyPath, p.Cfg, p.HTTPClientProvider, - p.OAuthTokenService, p.DataSourcesService, p.tracer) + p.OAuthTokenService, p.DataSourcesService, p.tracer, p.secretsService) if err != nil { if errors.Is(err, datasource.URLValidationError{}) { c.JsonApiErr(http.StatusBadRequest, fmt.Sprintf("Invalid data source URL: %q", ds.Url), err) diff --git a/pkg/services/datasources/datasources.go b/pkg/services/datasources/datasources.go new file mode 100644 index 00000000000..cfbc2095548 --- /dev/null +++ b/pkg/services/datasources/datasources.go @@ -0,0 +1,62 @@ +package datasources + +import ( + "context" + "net/http" + + sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" + "github.com/grafana/grafana/pkg/infra/httpclient" + "github.com/grafana/grafana/pkg/models" +) + +// DataSourceService interface for interacting with datasources. +type DataSourceService interface { + // GetDataSource gets a datasource. + GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error + + // GetDataSources gets datasources. + GetDataSources(ctx context.Context, query *models.GetDataSourcesQuery) error + + // GetDataSourcesByType gets datasources by type. + GetDataSourcesByType(ctx context.Context, query *models.GetDataSourcesByTypeQuery) error + + // AddDataSource adds a new datasource. + AddDataSource(ctx context.Context, cmd *models.AddDataSourceCommand) error + + // DeleteDataSource deletes an existing datasource. + DeleteDataSource(ctx context.Context, cmd *models.DeleteDataSourceCommand) error + + // UpdateDataSource updates an existing datasource. + UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSourceCommand) error + + // GetDefaultDataSource gets the default datasource. + GetDefaultDataSource(ctx context.Context, query *models.GetDefaultDataSourceQuery) error + + // GetHTTPTransport gets a datasource specific HTTP transport. + GetHTTPTransport(ds *models.DataSource, provider httpclient.Provider, customMiddlewares ...sdkhttpclient.Middleware) (http.RoundTripper, error) + + // DecryptedValues decrypts the encrypted secureJSONData of the provided datasource and + // returns the decrypted values. + DecryptedValues(ds *models.DataSource) map[string]string + + // DecryptedValue decrypts the encrypted datasource secureJSONData identified by key + // and returns the decryped value. + DecryptedValue(ds *models.DataSource, key string) (string, bool) + + // DecryptedBasicAuthPassword decrypts the encrypted datasource basic authentication + // password and returns the decryped value. + DecryptedBasicAuthPassword(ds *models.DataSource) string + + // DecryptedPassword decrypts the encrypted datasource password and returns the + // decryped value. + DecryptedPassword(ds *models.DataSource) string +} + +// CacheService interface for retrieving a cached datasource. +type CacheService interface { + // GetDatasource gets a datasource identified by datasource numeric identifier. + GetDatasource(ctx context.Context, datasourceID int64, user *models.SignedInUser, skipCache bool) (*models.DataSource, error) + + // GetDatasourceByUID gets a datasource identified by datasource unique identifier (UID). + GetDatasourceByUID(ctx context.Context, datasourceUID string, user *models.SignedInUser, skipCache bool) (*models.DataSource, error) +} diff --git a/pkg/services/datasources/log.go b/pkg/services/datasources/log.go deleted file mode 100644 index c70321d9510..00000000000 --- a/pkg/services/datasources/log.go +++ /dev/null @@ -1,9 +0,0 @@ -package datasources - -import ( - "github.com/grafana/grafana/pkg/infra/log" -) - -var ( - plog = log.New("datasources") -) diff --git a/pkg/services/datasources/cache.go b/pkg/services/datasources/service/cache_service.go similarity index 81% rename from pkg/services/datasources/cache.go rename to pkg/services/datasources/service/cache_service.go index 45c1bac7781..b40c29f219f 100644 --- a/pkg/services/datasources/cache.go +++ b/pkg/services/datasources/service/cache_service.go @@ -1,4 +1,4 @@ -package datasources +package service import ( "context" @@ -6,23 +6,21 @@ import ( "time" "github.com/grafana/grafana/pkg/infra/localcache" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore" ) func ProvideCacheService(cacheService *localcache.CacheService, sqlStore *sqlstore.SQLStore) *CacheServiceImpl { return &CacheServiceImpl{ + logger: log.New("datasources"), CacheService: cacheService, SQLStore: sqlStore, } } -type CacheService interface { - GetDatasource(ctx context.Context, datasourceID int64, user *models.SignedInUser, skipCache bool) (*models.DataSource, error) - GetDatasourceByUID(ctx context.Context, datasourceUID string, user *models.SignedInUser, skipCache bool) (*models.DataSource, error) -} - type CacheServiceImpl struct { + logger log.Logger CacheService *localcache.CacheService SQLStore *sqlstore.SQLStore } @@ -44,7 +42,7 @@ func (dc *CacheServiceImpl) GetDatasource( } } - plog.Debug("Querying for data source via SQL store", "id", datasourceID, "orgId", user.OrgId) + dc.logger.Debug("Querying for data source via SQL store", "id", datasourceID, "orgId", user.OrgId) query := &models.GetDataSourceQuery{Id: datasourceID, OrgId: user.OrgId} err := dc.SQLStore.GetDataSource(ctx, query) @@ -84,7 +82,7 @@ func (dc *CacheServiceImpl) GetDatasourceByUID( } } - plog.Debug("Querying for data source via SQL store", "uid", datasourceUID, "orgId", user.OrgId) + dc.logger.Debug("Querying for data source via SQL store", "uid", datasourceUID, "orgId", user.OrgId) query := &models.GetDataSourceQuery{Uid: datasourceUID, OrgId: user.OrgId} err := dc.SQLStore.GetDataSource(ctx, query) if err != nil { diff --git a/pkg/services/datasources/service.go b/pkg/services/datasources/service/datasource_service.go similarity index 99% rename from pkg/services/datasources/service.go rename to pkg/services/datasources/service/datasource_service.go index ca38e501cef..f25fb98ebe4 100644 --- a/pkg/services/datasources/service.go +++ b/pkg/services/datasources/service/datasource_service.go @@ -1,4 +1,4 @@ -package datasources +package service import ( "context" @@ -77,7 +77,9 @@ func ProvideService(bus bus.Bus, store *sqlstore.SQLStore, secretsService secret return s } +// DataSourceRetriever interface for retrieving a datasource. type DataSourceRetriever interface { + // GetDataSource gets a datasource. GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error } diff --git a/pkg/services/datasources/service_test.go b/pkg/services/datasources/service/datasource_service_test.go similarity index 99% rename from pkg/services/datasources/service_test.go rename to pkg/services/datasources/service/datasource_service_test.go index 136540fd516..99ddcbf8c8a 100644 --- a/pkg/services/datasources/service_test.go +++ b/pkg/services/datasources/service/datasource_service_test.go @@ -1,4 +1,4 @@ -package datasources +package service import ( "context" diff --git a/pkg/tsdb/legacydata/service/service.go b/pkg/tsdb/legacydata/service/service.go index 31ddd30a69a..b946d255252 100644 --- a/pkg/tsdb/legacydata/service/service.go +++ b/pkg/tsdb/legacydata/service/service.go @@ -21,10 +21,11 @@ var oAuthIsOAuthPassThruEnabledFunc = func(oAuthTokenService oauthtoken.OAuthTok type Service struct { pluginsClient plugins.Client oAuthTokenService oauthtoken.OAuthTokenService - dataSourcesService *datasources.Service + dataSourcesService datasources.DataSourceService } -func ProvideService(pluginsClient plugins.Client, oAuthTokenService oauthtoken.OAuthTokenService, dataSourcesService *datasources.Service) *Service { +func ProvideService(pluginsClient plugins.Client, oAuthTokenService oauthtoken.OAuthTokenService, + dataSourcesService datasources.DataSourceService) *Service { return &Service{ pluginsClient: pluginsClient, oAuthTokenService: oAuthTokenService, diff --git a/pkg/tsdb/legacydata/service/service_test.go b/pkg/tsdb/legacydata/service/service_test.go index 1f3c7312e01..ccd402b25c6 100644 --- a/pkg/tsdb/legacydata/service/service_test.go +++ b/pkg/tsdb/legacydata/service/service_test.go @@ -10,7 +10,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" - "github.com/grafana/grafana/pkg/services/datasources" + datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service" "github.com/grafana/grafana/pkg/services/oauthtoken" "github.com/grafana/grafana/pkg/services/secrets/fakes" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" @@ -36,7 +36,7 @@ func TestHandleRequest(t *testing.T) { return backend.NewQueryDataResponse(), nil } secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) - dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) + dsService := datasourceservice.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{}) s := ProvideService(client, nil, dsService) ds := &models.DataSource{Id: 12, Type: "unregisteredType", JsonData: simplejson.New()}