diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go index f03eb0eb304..993b5aa8e0f 100644 --- a/pkg/api/common_test.go +++ b/pkg/api/common_test.go @@ -364,7 +364,7 @@ func setupHTTPServerWithCfg(t *testing.T, useFakeAccessControl, enableAccessCont RouteRegister: routeRegister, SQLStore: db, searchUsersService: searchusers.ProvideUsersService(bus, filters.ProvideOSSSearchUserFilter()), - dashboardService: dashboardservice.ProvideDashboardService(dashboardsStore), + dashboardService: dashboardservice.ProvideDashboardService(dashboardsStore, nil), } // Defining the accesscontrol service has to be done before registering routes diff --git a/pkg/api/dashboard_permission_test.go b/pkg/api/dashboard_permission_test.go index a64ef0b8da3..9d40c5529a6 100644 --- a/pkg/api/dashboard_permission_test.go +++ b/pkg/api/dashboard_permission_test.go @@ -29,7 +29,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) { hs := &HTTPServer{ Cfg: settings, - dashboardService: dashboardservice.ProvideDashboardService(dashboardStore), + dashboardService: dashboardservice.ProvideDashboardService(dashboardStore, nil), SQLStore: mockSQLStore, } diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index 36fa2f632bc..ea37a7da2ba 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -219,7 +219,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { Live: newTestLive(t), LibraryPanelService: &mockLibraryPanelService{}, LibraryElementService: &mockLibraryElementService{}, - dashboardService: service.ProvideDashboardService(dashboardStore), + dashboardService: service.ProvideDashboardService(dashboardStore, nil), SQLStore: mockSQLStore, } hs.SQLStore = mockSQLStore @@ -939,7 +939,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr LibraryPanelService: &libraryPanelsService, LibraryElementService: &libraryElementsService, ProvisioningService: provisioningService, - dashboardProvisioningService: service.ProvideDashboardService(dashboardStore), + dashboardProvisioningService: service.ProvideDashboardService(dashboardStore, nil), SQLStore: sc.sqlStore, } diff --git a/pkg/api/datasources_test.go b/pkg/api/datasources_test.go index 0005e7d1aff..7f7191e3428 100644 --- a/pkg/api/datasources_test.go +++ b/pkg/api/datasources_test.go @@ -15,6 +15,7 @@ import ( "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/datasources/permissions" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" @@ -29,7 +30,7 @@ const ( func TestDataSourcesProxy_userLoggedIn(t *testing.T) { mockSQLStore := mockstore.NewSQLStoreMock() - mockDatasourcePermissionService := newMockDatasourcePermissionService() + mockDatasourcePermissionService := permissions.NewMockDatasourcePermissionService() loggedInUserScenario(t, "When calling GET on", "/api/datasources/", "/api/datasources/", func(sc *scenarioContext) { // Stubs the database query ds := []*models.DataSource{ @@ -38,7 +39,7 @@ func TestDataSourcesProxy_userLoggedIn(t *testing.T) { {Name: "BBB"}, {Name: "aaa"}, } - mockDatasourcePermissionService.dsResult = ds + mockDatasourcePermissionService.DsResult = ds // handler func being tested hs := &HTTPServer{ @@ -209,8 +210,8 @@ func TestAPI_Datasources_AccessControl(t *testing.T) { dsServiceMock := &dataSourcesServiceMock{ expectedDatasource: &testDatasource, } - dsPermissionService := newMockDatasourcePermissionService() - dsPermissionService.dsResult = []*models.DataSource{ + dsPermissionService := permissions.NewMockDatasourcePermissionService() + dsPermissionService.DsResult = []*models.DataSource{ &testDatasource, } @@ -505,9 +506,9 @@ func TestAPI_Datasources_AccessControl(t *testing.T) { // mock sqlStore and datasource permission service dsServiceMock.expectedError = test.expectedSQLError dsServiceMock.expectedDatasource = test.expectedDS - dsPermissionService.dsResult = []*models.DataSource{test.expectedDS} + dsPermissionService.DsResult = []*models.DataSource{test.expectedDS} if test.expectedDS == nil { - dsPermissionService.dsResult = nil + dsPermissionService.DsResult = nil } hs.DataSourcesService = dsServiceMock hs.DatasourcePermissionsService = dsPermissionService diff --git a/pkg/api/folder_permission_test.go b/pkg/api/folder_permission_test.go index 46df1f74192..1405b75ba2a 100644 --- a/pkg/api/folder_permission_test.go +++ b/pkg/api/folder_permission_test.go @@ -30,7 +30,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) { dashboardStore := &database.FakeDashboardStore{} defer dashboardStore.AssertExpectations(t) - hs := &HTTPServer{Cfg: settings, folderService: folderService, dashboardService: service.ProvideDashboardService(dashboardStore)} + hs := &HTTPServer{Cfg: settings, folderService: folderService, dashboardService: service.ProvideDashboardService(dashboardStore, nil)} t.Run("Given folder not exists", func(t *testing.T) { folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, models.ErrFolderNotFound).Twice() diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 34770a3bf5d..25040a02729 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -36,6 +36,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboardsnapshots" "github.com/grafana/grafana/pkg/services/datasourceproxy" "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/services/datasources/permissions" "github.com/grafana/grafana/pkg/services/encryption" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/hooks" @@ -135,7 +136,7 @@ type HTTPServer struct { dashboardService dashboards.DashboardService dashboardProvisioningService dashboards.DashboardProvisioningService folderService dashboards.FolderService - DatasourcePermissionsService DatasourcePermissionsService + DatasourcePermissionsService permissions.DatasourcePermissionsService commentsService *comments.Service AlertNotificationService *alerting.AlertNotificationService DashboardsnapshotsService *dashboardsnapshots.Service @@ -169,7 +170,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi authInfoService login.AuthInfoService, permissionsServices accesscontrol.PermissionsServices, notificationService *notifications.NotificationService, dashboardService dashboards.DashboardService, dashboardProvisioningService dashboards.DashboardProvisioningService, folderService dashboards.FolderService, - datasourcePermissionsService DatasourcePermissionsService, alertNotificationService *alerting.AlertNotificationService, + datasourcePermissionsService permissions.DatasourcePermissionsService, alertNotificationService *alerting.AlertNotificationService, dashboardsnapshotsService *dashboardsnapshots.Service, commentsService *comments.Service, pluginSettings *pluginsettings.ServiceImpl, ) (*HTTPServer, error) { web.Env = cfg.Env diff --git a/pkg/plugins/manager/dashboards_test.go b/pkg/plugins/manager/dashboards_test.go index d801c65e78b..55397f0bff2 100644 --- a/pkg/plugins/manager/dashboards_test.go +++ b/pkg/plugins/manager/dashboards_test.go @@ -11,9 +11,6 @@ import ( "github.com/grafana/grafana/pkg/plugins/backendplugin/provider" "github.com/grafana/grafana/pkg/plugins/manager/loader" "github.com/grafana/grafana/pkg/plugins/manager/signature" - "github.com/grafana/grafana/pkg/services/dashboards/database" - service "github.com/grafana/grafana/pkg/services/dashboards/manager" - "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/require" ) @@ -27,9 +24,8 @@ func TestGetPluginDashboards(t *testing.T) { }, } pmCfg := plugins.FromGrafanaCfg(cfg) - dashboardService := service.ProvideDashboardService(database.ProvideDashboardStore(&sqlstore.SQLStore{})) pm, err := ProvideService(cfg, loader.New(pmCfg, nil, - signature.NewUnsignedAuthorizer(pmCfg), &provider.Service{}), dashboardService) + signature.NewUnsignedAuthorizer(pmCfg), &provider.Service{})) require.NoError(t, err) bus.AddHandler("test", func(ctx context.Context, query *models.GetDashboardQuery) error { diff --git a/pkg/plugins/manager/manager.go b/pkg/plugins/manager/manager.go index d74bad4f744..5e2a4ef1cf6 100644 --- a/pkg/plugins/manager/manager.go +++ b/pkg/plugins/manager/manager.go @@ -14,7 +14,6 @@ import ( "github.com/grafana/grafana/pkg/plugins/backendplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin/instrumentation" "github.com/grafana/grafana/pkg/plugins/manager/installer" - "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util/errutil" ) @@ -30,38 +29,35 @@ var _ plugins.StaticRouteResolver = (*PluginManager)(nil) var _ plugins.RendererManager = (*PluginManager)(nil) type PluginManager struct { - cfg *plugins.Cfg - store map[string]*plugins.Plugin - pluginInstaller plugins.Installer - pluginLoader plugins.Loader - pluginsMu sync.RWMutex - pluginPaths map[plugins.Class][]string - dashboardService dashboards.DashboardService - log log.Logger + cfg *plugins.Cfg + store map[string]*plugins.Plugin + pluginInstaller plugins.Installer + pluginLoader plugins.Loader + pluginsMu sync.RWMutex + pluginPaths map[plugins.Class][]string + log log.Logger } -func ProvideService(grafanaCfg *setting.Cfg, pluginLoader plugins.Loader, dashboardService dashboards.DashboardService) (*PluginManager, error) { +func ProvideService(grafanaCfg *setting.Cfg, pluginLoader plugins.Loader) (*PluginManager, error) { pm := New(plugins.FromGrafanaCfg(grafanaCfg), map[plugins.Class][]string{ plugins.Core: corePluginPaths(grafanaCfg), plugins.Bundled: {grafanaCfg.BundledPluginsPath}, plugins.External: append([]string{grafanaCfg.PluginsPath}, pluginSettingPaths(grafanaCfg)...), - }, pluginLoader, dashboardService) + }, pluginLoader) if err := pm.Init(); err != nil { return nil, err } return pm, nil } -func New(cfg *plugins.Cfg, pluginPaths map[plugins.Class][]string, pluginLoader plugins.Loader, - dashboardService dashboards.DashboardService) *PluginManager { +func New(cfg *plugins.Cfg, pluginPaths map[plugins.Class][]string, pluginLoader plugins.Loader) *PluginManager { return &PluginManager{ - cfg: cfg, - pluginLoader: pluginLoader, - pluginPaths: pluginPaths, - store: make(map[string]*plugins.Plugin), - log: log.New("plugin.manager"), - pluginInstaller: installer.New(false, cfg.BuildVersion, newInstallerLogger("plugin.installer", true)), - dashboardService: dashboardService, + cfg: cfg, + pluginLoader: pluginLoader, + pluginPaths: pluginPaths, + store: make(map[string]*plugins.Plugin), + log: log.New("plugin.manager"), + pluginInstaller: installer.New(false, cfg.BuildVersion, newInstallerLogger("plugin.installer", true)), } } diff --git a/pkg/plugins/manager/manager_integration_test.go b/pkg/plugins/manager/manager_integration_test.go index e0c871f0428..1bb2651f8d2 100644 --- a/pkg/plugins/manager/manager_integration_test.go +++ b/pkg/plugins/manager/manager_integration_test.go @@ -14,7 +14,6 @@ import ( "github.com/grafana/grafana/pkg/plugins/backendplugin/provider" "github.com/grafana/grafana/pkg/plugins/manager/loader" "github.com/grafana/grafana/pkg/plugins/manager/signature" - service "github.com/grafana/grafana/pkg/services/dashboards/manager" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/licensing" "github.com/grafana/grafana/pkg/services/searchV2" @@ -94,7 +93,7 @@ func TestPluginManager_int_init(t *testing.T) { pmCfg := plugins.FromGrafanaCfg(cfg) pm, err := ProvideService(cfg, loader.New(pmCfg, license, signature.NewUnsignedAuthorizer(pmCfg), - provider.ProvideService(coreRegistry)), &service.DashboardServiceImpl{}) + provider.ProvideService(coreRegistry))) require.NoError(t, err) verifyCorePluginCatalogue(t, pm) diff --git a/pkg/plugins/manager/manager_test.go b/pkg/plugins/manager/manager_test.go index 6a35bd463d0..d0b5d9dc813 100644 --- a/pkg/plugins/manager/manager_test.go +++ b/pkg/plugins/manager/manager_test.go @@ -12,9 +12,6 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/backendplugin" - "github.com/grafana/grafana/pkg/services/dashboards/database" - service "github.com/grafana/grafana/pkg/services/dashboards/manager" - "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -469,8 +466,7 @@ func TestPluginManager_lifecycle_unmanaged(t *testing.T) { func createManager(t *testing.T, cbs ...func(*PluginManager)) *PluginManager { t.Helper() - dashboardService := service.ProvideDashboardService(database.ProvideDashboardStore(&sqlstore.SQLStore{})) - pm := New(&plugins.Cfg{}, nil, &fakeLoader{}, dashboardService) + pm := New(&plugins.Cfg{}, nil, &fakeLoader{}) for _, cb := range cbs { cb(pm) @@ -524,8 +520,7 @@ func newScenario(t *testing.T, managed bool, fn func(t *testing.T, ctx *managerS cfg.Azure.ManagedIdentityClientId = "client-id" loader := &fakeLoader{} - dashboardService := service.ProvideDashboardService(database.ProvideDashboardStore(&sqlstore.SQLStore{})) - manager := New(cfg, nil, loader, dashboardService) + manager := New(cfg, nil, loader) manager.pluginLoader = loader ctx := &managerScenarioCtx{ manager: manager, diff --git a/pkg/server/wire.go b/pkg/server/wire.go index e5b2d32beb3..ab8daa4d39a 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -213,6 +213,8 @@ var wireBasicSet = wire.NewSet( dashboardimportservice.ProvideService, wire.Bind(new(dashboardimport.Service), new(*dashboardimportservice.ImportDashboardService)), plugindashboards.ProvideService, + alerting.ProvideDashAlertExtractorService, + wire.Bind(new(alerting.DashAlertExtractor), new(*alerting.DashAlertExtractorService)), comments.ProvideService, ) diff --git a/pkg/server/wireexts_oss.go b/pkg/server/wireexts_oss.go index 292b666c3f5..37c66778ded 100644 --- a/pkg/server/wireexts_oss.go +++ b/pkg/server/wireexts_oss.go @@ -5,7 +5,6 @@ package server import ( "github.com/google/wire" - "github.com/grafana/grafana/pkg/api" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/backendplugin/provider" @@ -18,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions" "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/services/datasources/permissions" datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service" "github.com/grafana/grafana/pkg/services/encryption" "github.com/grafana/grafana/pkg/services/encryption/ossencryption" @@ -75,8 +75,8 @@ var wireExtsBasicSet = wire.NewSet( wire.Bind(new(kmsproviders.Service), new(osskmsproviders.Service)), ldap.ProvideGroupsService, wire.Bind(new(ldap.Groups), new(*ldap.OSSGroups)), - api.ProvideDatasourcePermissionsService, - wire.Bind(new(api.DatasourcePermissionsService), new(*api.OSSDatasourcePermissionsService)), + permissions.ProvideDatasourcePermissionsService, + wire.Bind(new(permissions.DatasourcePermissionsService), new(*permissions.OSSDatasourcePermissionsService)), ossaccesscontrol.ProvidePermissionsServices, wire.Bind(new(accesscontrol.PermissionsServices), new(*ossaccesscontrol.PermissionsService)), ) diff --git a/pkg/services/alerting/engine.go b/pkg/services/alerting/engine.go index 54b5e50010d..cb39ff67448 100644 --- a/pkg/services/alerting/engine.go +++ b/pkg/services/alerting/engine.go @@ -45,16 +45,17 @@ type AlertEngine struct { DataService legacydata.RequestHandler Cfg *setting.Cfg - execQueue chan *Job - ticker *Ticker - scheduler scheduler - evalHandler evalHandler - ruleReader ruleReader - log log.Logger - resultHandler resultHandler - usageStatsService usagestats.Service - tracer tracing.Tracer - sqlStore AlertStore + execQueue chan *Job + ticker *Ticker + scheduler scheduler + evalHandler evalHandler + ruleReader ruleReader + log log.Logger + resultHandler resultHandler + usageStatsService usagestats.Service + tracer tracing.Tracer + sqlStore AlertStore + dashAlertExtractor DashAlertExtractor } // IsDisabled returns true if the alerting service is disabled for this instance. @@ -65,16 +66,18 @@ func (e *AlertEngine) IsDisabled() bool { // ProvideAlertEngine returns a new AlertEngine. func ProvideAlertEngine(renderer rendering.Service, bus bus.Bus, requestValidator models.PluginRequestValidator, dataService legacydata.RequestHandler, usageStatsService usagestats.Service, encryptionService encryption.Internal, - notificationService *notifications.NotificationService, tracer tracing.Tracer, sqlStore AlertStore, cfg *setting.Cfg) *AlertEngine { + notificationService *notifications.NotificationService, tracer tracing.Tracer, sqlStore AlertStore, cfg *setting.Cfg, + dashAlertExtractor DashAlertExtractor) *AlertEngine { e := &AlertEngine{ - Cfg: cfg, - RenderService: renderer, - Bus: bus, - RequestValidator: requestValidator, - DataService: dataService, - usageStatsService: usageStatsService, - tracer: tracer, - sqlStore: sqlStore, + Cfg: cfg, + RenderService: renderer, + Bus: bus, + RequestValidator: requestValidator, + DataService: dataService, + usageStatsService: usageStatsService, + tracer: tracer, + sqlStore: sqlStore, + dashAlertExtractor: dashAlertExtractor, } e.ticker = NewTicker(time.Now(), time.Second*0, clock.New(), 1) e.execQueue = make(chan *Job, 1000) diff --git a/pkg/services/alerting/engine_integration_test.go b/pkg/services/alerting/engine_integration_test.go index f8a308ac5f2..05725068215 100644 --- a/pkg/services/alerting/engine_integration_test.go +++ b/pkg/services/alerting/engine_integration_test.go @@ -24,7 +24,7 @@ func TestEngineTimeouts(t *testing.T) { usMock := &usagestats.UsageStatsMock{T: t} tracer, err := tracing.InitializeTracerForTest() require.NoError(t, err) - engine := ProvideAlertEngine(nil, nil, nil, nil, usMock, ossencryption.ProvideService(), nil, tracer, nil, setting.NewCfg()) + engine := ProvideAlertEngine(nil, nil, nil, nil, usMock, ossencryption.ProvideService(), nil, tracer, nil, setting.NewCfg(), nil) setting.AlertingNotificationTimeout = 30 * time.Second setting.AlertingMaxAttempts = 3 engine.resultHandler = &FakeResultHandler{} diff --git a/pkg/services/alerting/engine_test.go b/pkg/services/alerting/engine_test.go index 771970efd95..6e7fb674d68 100644 --- a/pkg/services/alerting/engine_test.go +++ b/pkg/services/alerting/engine_test.go @@ -102,7 +102,7 @@ func TestEngineProcessJob(t *testing.T) { require.NoError(t, err) store := &AlertStoreMock{} - engine := ProvideAlertEngine(nil, bus, nil, nil, usMock, ossencryption.ProvideService(), nil, tracer, store, setting.NewCfg()) + engine := ProvideAlertEngine(nil, bus, nil, nil, usMock, ossencryption.ProvideService(), nil, tracer, store, setting.NewCfg(), nil) setting.AlertingEvaluationTimeout = 30 * time.Second setting.AlertingNotificationTimeout = 30 * time.Second setting.AlertingMaxAttempts = 3 diff --git a/pkg/services/alerting/extractor.go b/pkg/services/alerting/extractor.go index c3273ed6ca6..f8af2b8f858 100644 --- a/pkg/services/alerting/extractor.go +++ b/pkg/services/alerting/extractor.go @@ -6,31 +6,34 @@ import ( "errors" "fmt" - "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/services/datasources/permissions" ) -// DashAlertExtractor extracts alerts from the dashboard json. -type DashAlertExtractor struct { - User *models.SignedInUser - Dash *models.Dashboard - OrgID int64 - log log.Logger +type DashAlertExtractor interface { + GetAlerts(ctx context.Context, dashAlertInfo DashAlertInfo) ([]*models.Alert, error) + ValidateAlerts(ctx context.Context, dashAlertInfo DashAlertInfo) error } -// NewDashAlertExtractor returns a new DashAlertExtractor. -func NewDashAlertExtractor(dash *models.Dashboard, orgID int64, user *models.SignedInUser) *DashAlertExtractor { - return &DashAlertExtractor{ - User: user, - Dash: dash, - OrgID: orgID, - log: log.New("alerting.extractor"), +// DashAlertExtractorService extracts alerts from the dashboard json. +type DashAlertExtractorService struct { + datasourcePermissionsService permissions.DatasourcePermissionsService + datasourceService datasources.DataSourceService + log log.Logger +} + +func ProvideDashAlertExtractorService(datasourcePermissionsService permissions.DatasourcePermissionsService, datasourceService datasources.DataSourceService) *DashAlertExtractorService { + return &DashAlertExtractorService{ + datasourcePermissionsService: datasourcePermissionsService, + datasourceService: datasourceService, + log: log.New("alerting.extractor"), } } -func (e *DashAlertExtractor) lookupQueryDataSource(ctx context.Context, panel *simplejson.Json, panelQuery *simplejson.Json) (*models.DataSource, error) { +func (e *DashAlertExtractorService) lookupQueryDataSource(ctx context.Context, panel *simplejson.Json, panelQuery *simplejson.Json, orgID int64) (*models.DataSource, error) { dsName := "" dsUid := "" @@ -47,15 +50,15 @@ func (e *DashAlertExtractor) lookupQueryDataSource(ctx context.Context, panel *s } if dsName == "" && dsUid == "" { - query := &models.GetDefaultDataSourceQuery{OrgId: e.OrgID} - if err := bus.Dispatch(ctx, query); err != nil { + query := &models.GetDefaultDataSourceQuery{OrgId: orgID} + if err := e.datasourceService.GetDefaultDataSource(ctx, query); err != nil { return nil, err } return query.Result, nil } - query := &models.GetDataSourceQuery{Name: dsName, Uid: dsUid, OrgId: e.OrgID} - if err := bus.Dispatch(ctx, query); err != nil { + query := &models.GetDataSourceQuery{Name: dsName, Uid: dsUid, OrgId: orgID} + if err := e.datasourceService.GetDataSource(ctx, query); err != nil { return nil, err } @@ -101,7 +104,7 @@ func UAEnabled(ctx context.Context) bool { return enabled } -func (e *DashAlertExtractor) getAlertFromPanels(ctx context.Context, jsonWithPanels *simplejson.Json, validateAlertFunc func(*models.Alert) bool, logTranslationFailures bool) ([]*models.Alert, error) { +func (e *DashAlertExtractorService) getAlertFromPanels(ctx context.Context, jsonWithPanels *simplejson.Json, validateAlertFunc func(*models.Alert) bool, logTranslationFailures bool, dashAlertInfo DashAlertInfo) ([]*models.Alert, error) { alerts := make([]*models.Alert, 0) for _, panelObj := range jsonWithPanels.Get("panels").MustArray() { @@ -111,7 +114,7 @@ func (e *DashAlertExtractor) getAlertFromPanels(ctx context.Context, jsonWithPan // check if the panel is collapsed if collapsed && collapsedJSON.MustBool() { // extract alerts from sub panels for collapsed panels - alertSlice, err := e.getAlertFromPanels(ctx, panel, validateAlertFunc, logTranslationFailures) + alertSlice, err := e.getAlertFromPanels(ctx, panel, validateAlertFunc, logTranslationFailures, dashAlertInfo) if err != nil { return nil, err } @@ -143,8 +146,8 @@ func (e *DashAlertExtractor) getAlertFromPanels(ctx context.Context, jsonWithPan Err: validationErr.Err, PanelID: panelID, } - if e.Dash != nil { - ve.DashboardID = e.Dash.Id + if dashAlertInfo.Dash != nil { + ve.DashboardID = dashAlertInfo.Dash.Id } return ve } @@ -170,8 +173,8 @@ func (e *DashAlertExtractor) getAlertFromPanels(ctx context.Context, jsonWithPan } alert := &models.Alert{ - DashboardId: e.Dash.Id, - OrgId: e.OrgID, + DashboardId: dashAlertInfo.Dash.Id, + OrgId: dashAlertInfo.OrgID, PanelId: panelID, Id: jsonAlert.Get("id").MustInt64(), Name: jsonAlert.Get("name").MustString(), @@ -198,24 +201,21 @@ func (e *DashAlertExtractor) getAlertFromPanels(ctx context.Context, jsonWithPan return nil, ValidationError{Reason: reason} } - datasource, err := e.lookupQueryDataSource(ctx, panel, panelQuery) + datasource, err := e.lookupQueryDataSource(ctx, panel, panelQuery, dashAlertInfo.OrgID) if err != nil { return nil, err } dsFilterQuery := models.DatasourcesPermissionFilterQuery{ - User: e.User, + User: dashAlertInfo.User, Datasources: []*models.DataSource{datasource}, } - if err := bus.Dispatch(ctx, &dsFilterQuery); err != nil { - if !errors.Is(err, bus.ErrHandlerNotFound) { - return nil, err - } - } else { - if len(dsFilterQuery.Result) == 0 { - return nil, models.ErrDataSourceAccessDenied - } + if err := e.datasourcePermissionsService.FilterDatasourcesBasedOnQueryPermissions(ctx, &dsFilterQuery); err != nil { + return nil, err + } + if len(dsFilterQuery.Result) == 0 { + return nil, models.ErrDataSourceAccessDenied } jsonQuery.SetPath([]string{"datasourceId"}, datasource.Id) @@ -250,12 +250,12 @@ func validateAlertRule(alert *models.Alert) bool { } // GetAlerts extracts alerts from the dashboard json and does full validation on the alert json data. -func (e *DashAlertExtractor) GetAlerts(ctx context.Context) ([]*models.Alert, error) { - return e.extractAlerts(ctx, validateAlertRule, true) +func (e *DashAlertExtractorService) GetAlerts(ctx context.Context, dashAlertInfo DashAlertInfo) ([]*models.Alert, error) { + return e.extractAlerts(ctx, validateAlertRule, true, dashAlertInfo) } -func (e *DashAlertExtractor) extractAlerts(ctx context.Context, validateFunc func(alert *models.Alert) bool, logTranslationFailures bool) ([]*models.Alert, error) { - dashboardJSON, err := copyJSON(e.Dash.Data) +func (e *DashAlertExtractorService) extractAlerts(ctx context.Context, validateFunc func(alert *models.Alert) bool, logTranslationFailures bool, dashAlertInfo DashAlertInfo) ([]*models.Alert, error) { + dashboardJSON, err := copyJSON(dashAlertInfo.Dash.Data) if err != nil { return nil, err } @@ -268,7 +268,7 @@ func (e *DashAlertExtractor) extractAlerts(ctx context.Context, validateFunc fun if len(rows) > 0 { for _, rowObj := range rows { row := simplejson.NewFromAny(rowObj) - a, err := e.getAlertFromPanels(ctx, row, validateFunc, logTranslationFailures) + a, err := e.getAlertFromPanels(ctx, row, validateFunc, logTranslationFailures, dashAlertInfo) if err != nil { return nil, err } @@ -276,7 +276,7 @@ func (e *DashAlertExtractor) extractAlerts(ctx context.Context, validateFunc fun alerts = append(alerts, a...) } } else { - a, err := e.getAlertFromPanels(ctx, dashboardJSON, validateFunc, logTranslationFailures) + a, err := e.getAlertFromPanels(ctx, dashboardJSON, validateFunc, logTranslationFailures, dashAlertInfo) if err != nil { return nil, err } @@ -290,9 +290,9 @@ func (e *DashAlertExtractor) extractAlerts(ctx context.Context, validateFunc fun // ValidateAlerts validates alerts in the dashboard json but does not require a valid dashboard id // in the first validation pass. -func (e *DashAlertExtractor) ValidateAlerts(ctx context.Context) error { +func (e *DashAlertExtractorService) ValidateAlerts(ctx context.Context, dashAlertInfo DashAlertInfo) error { _, err := e.extractAlerts(ctx, func(alert *models.Alert) bool { return alert.OrgId != 0 && alert.PanelId != 0 - }, false) + }, false, dashAlertInfo) return err } diff --git a/pkg/services/alerting/extractor_test.go b/pkg/services/alerting/extractor_test.go index 68ee6cc3567..6b8ea7861a6 100644 --- a/pkg/services/alerting/extractor_test.go +++ b/pkg/services/alerting/extractor_test.go @@ -6,9 +6,10 @@ import ( "testing" "time" - "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/services/datasources/permissions" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/stretchr/testify/require" ) @@ -21,40 +22,24 @@ func TestAlertRuleExtraction(t *testing.T) { // mock data defaultDs := &models.DataSource{Id: 12, OrgId: 1, Name: "I am default", IsDefault: true, Uid: "def-uid"} graphite2Ds := &models.DataSource{Id: 15, OrgId: 1, Name: "graphite2", Uid: "graphite2-uid"} - influxDBDs := &models.DataSource{Id: 16, OrgId: 1, Name: "InfluxDB", Uid: "InfluxDB-uid"} - prom := &models.DataSource{Id: 17, OrgId: 1, Name: "Prometheus", Uid: "Prometheus-uid"} - - bus.AddHandler("test", func(ctx context.Context, query *models.GetDefaultDataSourceQuery) error { - query.Result = defaultDs - return nil - }) - - bus.AddHandler("test", func(ctx context.Context, query *models.GetDataSourceQuery) error { - if query.Name == defaultDs.Name || query.Uid == defaultDs.Uid { - query.Result = defaultDs - } - if query.Name == graphite2Ds.Name || query.Uid == graphite2Ds.Uid { - query.Result = graphite2Ds - } - if query.Name == influxDBDs.Name || query.Uid == influxDBDs.Uid { - query.Result = influxDBDs - } - if query.Name == prom.Name || query.Uid == prom.Uid { - query.Result = prom - } - - return nil - }) json, err := ioutil.ReadFile("./testdata/graphite-alert.json") require.Nil(t, err) + dsPermissions := permissions.NewMockDatasourcePermissionService() + dsPermissions.DsResult = []*models.DataSource{ + { + Id: 1, + }, + } + + dsService := &fakeDatasourceService{ExpectedDatasource: defaultDs} + extractor := ProvideDashAlertExtractorService(dsPermissions, dsService) + t.Run("Parsing alert rules from dashboard json", func(t *testing.T) { dashJSON, err := simplejson.NewJson(json) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - getTarget := func(j *simplejson.Json) string { rowObj := j.Get("rows").MustArray()[0] row := simplejson.NewFromAny(rowObj) @@ -67,8 +52,11 @@ func TestAlertRuleExtraction(t *testing.T) { require.Equal(t, getTarget(dashJSON), "") - extractor := NewDashAlertExtractor(dash, 1, nil) - _, _ = extractor.GetAlerts(context.Background()) + _, _ = extractor.GetAlerts(context.Background(), DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + }) require.Equal(t, getTarget(dashJSON), "") }) @@ -77,10 +65,12 @@ func TestAlertRuleExtraction(t *testing.T) { dashJSON, err := simplejson.NewJson(json) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - - alerts, err := extractor.GetAlerts(context.Background()) + dsService.ExpectedDatasource = &models.DataSource{Id: 12} + alerts, err := extractor.GetAlerts(context.Background(), DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + }) require.Nil(t, err) @@ -127,10 +117,12 @@ func TestAlertRuleExtraction(t *testing.T) { dashJSON, err := simplejson.NewJson(panelWithoutID) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - _, err = extractor.GetAlerts(context.Background()) + _, err = extractor.GetAlerts(context.Background(), DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + }) require.NotNil(t, err) }) @@ -141,10 +133,12 @@ func TestAlertRuleExtraction(t *testing.T) { dashJSON, err := simplejson.NewJson(panelWithIDZero) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - _, err = extractor.GetAlerts(context.Background()) + _, err = extractor.GetAlerts(context.Background(), DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + }) require.NotNil(t, err) }) @@ -154,10 +148,12 @@ func TestAlertRuleExtraction(t *testing.T) { require.Nil(t, err) dashJSON, err := simplejson.NewJson(panelWithQuery) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - _, err = extractor.GetAlerts(WithUAEnabled(context.Background(), true)) + _, err = extractor.GetAlerts(WithUAEnabled(context.Background(), true), DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + }) require.Equal(t, "alert validation error: Alert on PanelId: 2 refers to query(B) that cannot be found. Legacy alerting queries are not able to be removed at this time in order to preserve the ability to rollback to previous versions of Grafana", err.Error()) }) @@ -167,10 +163,13 @@ func TestAlertRuleExtraction(t *testing.T) { dashJSON, err := simplejson.NewJson(panelWithoutSpecifiedDatasource) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - alerts, err := extractor.GetAlerts(context.Background()) + dsService.ExpectedDatasource = &models.DataSource{Id: 12} + alerts, err := extractor.GetAlerts(context.Background(), DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + }) require.Nil(t, err) condition := simplejson.NewFromAny(alerts[0].Settings.Get("conditions").MustArray()[0]) @@ -184,10 +183,12 @@ func TestAlertRuleExtraction(t *testing.T) { dashJSON, err := simplejson.NewJson(json) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - alerts, err := extractor.GetAlerts(context.Background()) + alerts, err := extractor.GetAlerts(context.Background(), DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + }) require.Nil(t, err) require.Len(t, alerts, 2) @@ -209,10 +210,12 @@ func TestAlertRuleExtraction(t *testing.T) { dashJSON, err := simplejson.NewJson(json) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - alerts, err := extractor.GetAlerts(context.Background()) + alerts, err := extractor.GetAlerts(context.Background(), DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + }) require.Nil(t, err) require.Len(t, alerts, 1) @@ -235,9 +238,12 @@ func TestAlertRuleExtraction(t *testing.T) { require.Nil(t, err) dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - alerts, err := extractor.GetAlerts(context.Background()) + alerts, err := extractor.GetAlerts(context.Background(), DashAlertInfo{ + User: nil, + Dash: dash, + OrgID: 1, + }) require.Nil(t, err) require.Len(t, alerts, 4) @@ -249,14 +255,17 @@ func TestAlertRuleExtraction(t *testing.T) { dashJSON, err := simplejson.NewJson(json) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - err = extractor.ValidateAlerts(context.Background()) + dashAlertInfo := DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + } + err = extractor.ValidateAlerts(context.Background(), dashAlertInfo) require.Nil(t, err) - _, err = extractor.GetAlerts(context.Background()) + _, err = extractor.GetAlerts(context.Background(), dashAlertInfo) require.Equal(t, err.Error(), "alert validation error: Panel id is not correct, alertName=Influxdb, panelId=1") }) @@ -266,14 +275,18 @@ func TestAlertRuleExtraction(t *testing.T) { dashJSON, err := simplejson.NewJson(json) require.Nil(t, err) - dash := models.NewDashboardFromJson(dashJSON) - extractor := NewDashAlertExtractor(dash, 1, nil) - err = extractor.ValidateAlerts(context.Background()) + dsService.ExpectedDatasource = graphite2Ds + dashAlertInfo := DashAlertInfo{ + User: nil, + Dash: models.NewDashboardFromJson(dashJSON), + OrgID: 1, + } + err = extractor.ValidateAlerts(context.Background(), dashAlertInfo) require.Nil(t, err) - alerts, err := extractor.GetAlerts(context.Background()) + alerts, err := extractor.GetAlerts(context.Background(), dashAlertInfo) require.Nil(t, err) condition := simplejson.NewFromAny(alerts[0].Settings.Get("conditions").MustArray()[0]) @@ -281,3 +294,18 @@ func TestAlertRuleExtraction(t *testing.T) { require.EqualValues(t, 15, query.Get("datasourceId").MustInt64()) }) } + +type fakeDatasourceService struct { + ExpectedDatasource *models.DataSource + datasources.DataSourceService +} + +func (f *fakeDatasourceService) GetDefaultDataSource(ctx context.Context, query *models.GetDefaultDataSourceQuery) error { + query.Result = f.ExpectedDatasource + return nil +} + +func (f *fakeDatasourceService) GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error { + query.Result = f.ExpectedDatasource + return nil +} diff --git a/pkg/services/alerting/models.go b/pkg/services/alerting/models.go index 0085418ac74..d4cb0bf84b5 100644 --- a/pkg/services/alerting/models.go +++ b/pkg/services/alerting/models.go @@ -4,6 +4,7 @@ import ( "sync" "github.com/grafana/grafana/pkg/components/null" + "github.com/grafana/grafana/pkg/models" ) // Job holds state about when the alert rule should be evaluated. @@ -42,3 +43,9 @@ type EvalMatch struct { Metric string `json:"metric"` Tags map[string]string `json:"tags"` } + +type DashAlertInfo struct { + User *models.SignedInUser + Dash *models.Dashboard + OrgID int64 +} diff --git a/pkg/services/alerting/test_rule.go b/pkg/services/alerting/test_rule.go index 3ccee726f6c..d04e052672f 100644 --- a/pkg/services/alerting/test_rule.go +++ b/pkg/services/alerting/test_rule.go @@ -11,9 +11,12 @@ import ( // AlertTest makes a test alert. func (e *AlertEngine) AlertTest(orgID int64, dashboard *simplejson.Json, panelID int64, user *models.SignedInUser) (*EvalContext, error) { dash := models.NewDashboardFromJson(dashboard) - - extractor := NewDashAlertExtractor(dash, orgID, user) - alerts, err := extractor.GetAlerts(context.Background()) + dashInfo := DashAlertInfo{ + User: user, + Dash: dash, + OrgID: orgID, + } + alerts, err := e.dashAlertExtractor.GetAlerts(context.Background(), dashInfo) if err != nil { return nil, err } diff --git a/pkg/services/dashboards/manager/dashboard_service.go b/pkg/services/dashboards/manager/dashboard_service.go index 93457ffa7bc..a48829ee8c8 100644 --- a/pkg/services/dashboards/manager/dashboard_service.go +++ b/pkg/services/dashboards/manager/dashboard_service.go @@ -19,14 +19,16 @@ import ( ) type DashboardServiceImpl struct { - dashboardStore m.Store - log log.Logger + dashboardStore m.Store + dashAlertExtractor alerting.DashAlertExtractor + log log.Logger } -func ProvideDashboardService(store m.Store) *DashboardServiceImpl { +func ProvideDashboardService(store m.Store, dashAlertExtractor alerting.DashAlertExtractor) *DashboardServiceImpl { return &DashboardServiceImpl{ - dashboardStore: store, - log: log.New("dashboard-service"), + dashboardStore: store, + dashAlertExtractor: dashAlertExtractor, + log: log.New("dashboard-service"), } } @@ -74,7 +76,8 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d } if shouldValidateAlerts { - if err := validateAlerts(ctx, dash, dto.User); err != nil { + dashAlertInfo := alerting.DashAlertInfo{Dash: dash, User: dto.User, OrgID: dash.OrgId} + if err := dr.dashAlertExtractor.ValidateAlerts(ctx, dashAlertInfo); err != nil { return nil, err } } @@ -139,11 +142,6 @@ func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context. return dr.dashboardStore.DeleteOrphanedProvisionedDashboards(ctx, cmd) } -var validateAlerts = func(ctx context.Context, dash *models.Dashboard, user *models.SignedInUser) error { - extractor := alerting.NewDashAlertExtractor(dash, dash.OrgId, user) - return extractor.ValidateAlerts(ctx) -} - func validateDashboardRefreshInterval(dash *models.Dashboard) error { if setting.MinRefreshInterval == "" { return nil @@ -171,19 +169,6 @@ func validateDashboardRefreshInterval(dash *models.Dashboard) error { return nil } -// UpdateAlerting updates alerting. -// -// Stubbable by tests. -var UpdateAlerting = func(ctx context.Context, store m.Store, orgID int64, dashboard *models.Dashboard, user *models.SignedInUser) error { - extractor := alerting.NewDashAlertExtractor(dashboard, orgID, user) - alerts, err := extractor.GetAlerts(ctx) - if err != nil { - return err - } - - return store.SaveAlerts(ctx, dashboard.Id, alerts) -} - func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dto *m.SaveDashboardDTO, provisioning *models.DashboardProvisioning) (*models.Dashboard, error) { if err := validateDashboardRefreshInterval(dto.Dashboard); err != nil { @@ -210,7 +195,19 @@ func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dt } // alerts - if err := UpdateAlerting(ctx, dr.dashboardStore, dto.OrgId, dash, dto.User); err != nil { + dashAlertInfo := alerting.DashAlertInfo{ + User: dto.User, + Dash: dash, + OrgID: dto.OrgId, + } + + alerts, err := dr.dashAlertExtractor.GetAlerts(ctx, dashAlertInfo) + if err != nil { + return nil, err + } + + err = dr.dashboardStore.SaveAlerts(ctx, dash.Id, alerts) + if err != nil { return nil, err } @@ -232,7 +229,19 @@ func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.C return nil, err } - if err := UpdateAlerting(ctx, dr.dashboardStore, dto.OrgId, dash, dto.User); err != nil { + dashAlertInfo := alerting.DashAlertInfo{ + User: dto.User, + Dash: dash, + OrgID: dto.OrgId, + } + + alerts, err := dr.dashAlertExtractor.GetAlerts(ctx, dashAlertInfo) + if err != nil { + return nil, err + } + + err = dr.dashboardStore.SaveAlerts(ctx, dash.Id, alerts) + if err != nil { return nil, err } @@ -258,7 +267,19 @@ func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *m.SaveDa return nil, fmt.Errorf("saving dashboard failed: %w", err) } - if err := UpdateAlerting(ctx, dr.dashboardStore, dto.OrgId, dash, dto.User); err != nil { + dashAlertInfo := alerting.DashAlertInfo{ + User: dto.User, + Dash: dash, + OrgID: dto.OrgId, + } + + alerts, err := dr.dashAlertExtractor.GetAlerts(ctx, dashAlertInfo) + if err != nil { + return nil, err + } + + err = dr.dashboardStore.SaveAlerts(ctx, dash.Id, alerts) + if err != nil { return nil, err } diff --git a/pkg/services/dashboards/manager/dashboard_service_integration_test.go b/pkg/services/dashboards/manager/dashboard_service_integration_test.go index 00bc7ca305b..713b56aedd5 100644 --- a/pkg/services/dashboards/manager/dashboard_service_integration_test.go +++ b/pkg/services/dashboards/manager/dashboard_service_integration_test.go @@ -5,6 +5,7 @@ package service import ( "context" + "github.com/grafana/grafana/pkg/services/alerting" "testing" "github.com/grafana/grafana/pkg/components/simplejson" @@ -21,14 +22,6 @@ const testOrgID int64 = 1 func TestIntegratedDashboardService(t *testing.T) { t.Run("Given saved folders and dashboards in organization A", func(t *testing.T) { - origUpdateAlerting := UpdateAlerting - t.Cleanup(func() { - UpdateAlerting = origUpdateAlerting - }) - UpdateAlerting = func(ctx context.Context, store dashbboardservice.Store, orgID int64, dashboard *models.Dashboard, user *models.SignedInUser) error { - return nil - } - // Basic validation tests permissionScenario(t, "When saving a dashboard with non-existing id", true, @@ -861,7 +854,7 @@ func callSaveWithResult(t *testing.T, cmd models.SaveDashboardCommand, sqlStore dto := toSaveDashboardDto(cmd) dashboardStore := database.ProvideDashboardStore(sqlStore) - res, err := ProvideDashboardService(dashboardStore).SaveDashboard(context.Background(), &dto, false) + res, err := ProvideDashboardService(dashboardStore, &dummyDashAlertExtractor{}).SaveDashboard(context.Background(), &dto, false) require.NoError(t, err) return res @@ -870,7 +863,7 @@ func callSaveWithResult(t *testing.T, cmd models.SaveDashboardCommand, sqlStore func callSaveWithError(cmd models.SaveDashboardCommand, sqlStore *sqlstore.SQLStore) error { dto := toSaveDashboardDto(cmd) dashboardStore := database.ProvideDashboardStore(sqlStore) - _, err := ProvideDashboardService(dashboardStore).SaveDashboard(context.Background(), &dto, false) + _, err := ProvideDashboardService(dashboardStore, &dummyDashAlertExtractor{}).SaveDashboard(context.Background(), &dto, false) return err } @@ -897,7 +890,7 @@ func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlSto } dashboardStore := database.ProvideDashboardStore(sqlStore) - res, err := ProvideDashboardService(dashboardStore).SaveDashboard(context.Background(), &dto, false) + res, err := ProvideDashboardService(dashboardStore, &dummyDashAlertExtractor{}).SaveDashboard(context.Background(), &dto, false) require.NoError(t, err) return res @@ -925,7 +918,7 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore *sqlstore. } dashboardStore := database.ProvideDashboardStore(sqlStore) - res, err := ProvideDashboardService(dashboardStore).SaveDashboard(context.Background(), &dto, false) + res, err := ProvideDashboardService(dashboardStore, &dummyDashAlertExtractor{}).SaveDashboard(context.Background(), &dto, false) require.NoError(t, err) return res @@ -942,3 +935,14 @@ func toSaveDashboardDto(cmd models.SaveDashboardCommand) dashbboardservice.SaveD Overwrite: cmd.Overwrite, } } + +type dummyDashAlertExtractor struct { +} + +func (d *dummyDashAlertExtractor) GetAlerts(ctx context.Context, dashAlertInfo alerting.DashAlertInfo) ([]*models.Alert, error) { + return nil, nil +} + +func (d *dummyDashAlertExtractor) ValidateAlerts(ctx context.Context, dashAlertInfo alerting.DashAlertInfo) error { + return nil +} diff --git a/pkg/services/dashboards/manager/dashboard_service_test.go b/pkg/services/dashboards/manager/dashboard_service_test.go index 1fb721e2e9f..dba479c8160 100644 --- a/pkg/services/dashboards/manager/dashboard_service_test.go +++ b/pkg/services/dashboards/manager/dashboard_service_test.go @@ -27,8 +27,9 @@ func TestDashboardService(t *testing.T) { fakeStore := database.FakeDashboardStore{} defer fakeStore.AssertExpectations(t) service := &DashboardServiceImpl{ - log: log.New("test.logger"), - dashboardStore: &fakeStore, + log: log.New("test.logger"), + dashboardStore: &fakeStore, + dashAlertExtractor: &dummyDashAlertExtractor{}, } origNewDashboardGuardian := guardian.New diff --git a/pkg/services/dashboards/manager/folder_service_test.go b/pkg/services/dashboards/manager/folder_service_test.go index 962e0fe88de..9b199959694 100644 --- a/pkg/services/dashboards/manager/folder_service_test.go +++ b/pkg/services/dashboards/manager/folder_service_test.go @@ -25,7 +25,7 @@ func TestFolderService(t *testing.T) { store := &database.FakeDashboardStore{} defer store.AssertExpectations(t) service := ProvideFolderService( - &dashboards.FakeDashboardService{DashboardService: ProvideDashboardService(store)}, + &dashboards.FakeDashboardService{DashboardService: ProvideDashboardService(store, nil)}, store, nil, ) diff --git a/pkg/api/datasource_permissions.go b/pkg/services/datasources/permissions/datasource_permissions.go similarity index 96% rename from pkg/api/datasource_permissions.go rename to pkg/services/datasources/permissions/datasource_permissions.go index 5035b8da6c9..9dee1b2d0b5 100644 --- a/pkg/api/datasource_permissions.go +++ b/pkg/services/datasources/permissions/datasource_permissions.go @@ -1,4 +1,4 @@ -package api +package permissions import ( "context" diff --git a/pkg/api/datasource_permissions_mocks.go b/pkg/services/datasources/permissions/datasource_permissions_mocks.go similarity index 71% rename from pkg/api/datasource_permissions_mocks.go rename to pkg/services/datasources/permissions/datasource_permissions_mocks.go index 1fd921fa6ac..767fdda5e5d 100644 --- a/pkg/api/datasource_permissions_mocks.go +++ b/pkg/services/datasources/permissions/datasource_permissions_mocks.go @@ -1,4 +1,4 @@ -package api +package permissions import ( "context" @@ -7,14 +7,14 @@ import ( ) type mockDatasourcePermissionService struct { - dsResult []*models.DataSource + DsResult []*models.DataSource } func (m *mockDatasourcePermissionService) FilterDatasourcesBasedOnQueryPermissions(ctx context.Context, cmd *models.DatasourcesPermissionFilterQuery) error { - cmd.Result = m.dsResult + cmd.Result = m.DsResult return nil } -func newMockDatasourcePermissionService() *mockDatasourcePermissionService { +func NewMockDatasourcePermissionService() *mockDatasourcePermissionService { return &mockDatasourcePermissionService{} } diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index 8c1df027581..273b90ad2d8 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" @@ -195,7 +196,8 @@ func createDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, user models.Sign } dashboardStore := database.ProvideDashboardStore(sqlStore) - dashboard, err := dashboardservice.ProvideDashboardService(dashboardStore).SaveDashboard(context.Background(), dashItem, true) + dashAlertExtractor := alerting.ProvideDashAlertExtractorService(nil, nil) + dashboard, err := dashboardservice.ProvideDashboardService(dashboardStore, dashAlertExtractor).SaveDashboard(context.Background(), dashItem, true) require.NoError(t, err) return dashboard @@ -206,7 +208,7 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string t.Helper() dashboardStore := database.ProvideDashboardStore(sqlStore) - d := dashboardservice.ProvideDashboardService(dashboardStore) + d := dashboardservice.ProvideDashboardService(dashboardStore, nil) s := dashboardservice.ProvideFolderService(d, dashboardStore, nil) t.Logf("Creating folder with title and UID %q", title) folder, err := s.CreateFolder(context.Background(), &user, user.OrgId, title, title) @@ -292,7 +294,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo role := models.ROLE_ADMIN sqlStore := sqlstore.InitTestDB(t) dashboardStore := database.ProvideDashboardStore(sqlStore) - dashboardService := dashboardservice.ProvideDashboardService(dashboardStore) + dashboardService := dashboardservice.ProvideDashboardService(dashboardStore, &alerting.DashAlertExtractorService{}) service := LibraryElementService{ Cfg: setting.NewCfg(), SQLStore: sqlStore, diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index 7a101269709..51c5e7e957c 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" @@ -1416,7 +1417,8 @@ func createDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, user *models.Sig } dashboadStore := database.ProvideDashboardStore(sqlStore) - dashboard, err := dashboardservice.ProvideDashboardService(dashboadStore).SaveDashboard(context.Background(), dashItem, true) + dashAlertService := alerting.ProvideDashAlertExtractorService(nil, nil) + dashboard, err := dashboardservice.ProvideDashboardService(dashboadStore, dashAlertService).SaveDashboard(context.Background(), dashItem, true) require.NoError(t, err) return dashboard @@ -1427,7 +1429,7 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string t.Helper() dashboardStore := database.ProvideDashboardStore(sqlStore) - d := dashboardservice.ProvideDashboardService(dashboardStore) + d := dashboardservice.ProvideDashboardService(dashboardStore, nil) s := dashboardservice.ProvideFolderService(d, dashboardStore, nil) t.Logf("Creating folder with title and UID %q", title) folder, err := s.CreateFolder(context.Background(), user, user.OrgId, title, title) @@ -1516,7 +1518,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo role := models.ROLE_ADMIN sqlStore := sqlstore.InitTestDB(t) dashboardStore := database.ProvideDashboardStore(sqlStore) - folderService := dashboardservice.ProvideFolderService(dashboardservice.ProvideDashboardService(dashboardStore), dashboardStore, nil) + folderService := dashboardservice.ProvideFolderService(dashboardservice.ProvideDashboardService(dashboardStore, &alerting.DashAlertExtractorService{}), dashboardStore, nil) elementService := libraryelements.ProvideService(cfg, sqlStore, routing.NewRouteRegister(), folderService) service := LibraryPanelService{ diff --git a/pkg/services/ngalert/tests/util.go b/pkg/services/ngalert/tests/util.go index 5a9dfaf1e02..826fe6e1f64 100644 --- a/pkg/services/ngalert/tests/util.go +++ b/pkg/services/ngalert/tests/util.go @@ -41,7 +41,7 @@ func SetupTestEnv(t *testing.T, baseInterval time.Duration) (*ngalert.AlertNG, * sqlStore := sqlstore.InitTestDB(t) secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) dashboardStore := databasestore.ProvideDashboardStore(sqlStore) - folderService := dashboardservice.ProvideFolderService(dashboardservice.ProvideDashboardService(dashboardStore), dashboardStore, nil) + folderService := dashboardservice.ProvideFolderService(dashboardservice.ProvideDashboardService(dashboardStore, nil), dashboardStore, nil) ng, err := ngalert.ProvideService( cfg, nil, routing.NewRouteRegister(), sqlStore, nil, nil, nil, nil, secretsService, nil, m, folderService, diff --git a/pkg/services/sqlstore/mockstore/mockstore.go b/pkg/services/sqlstore/mockstore/mockstore.go index 61b19b0a53c..33d5c5f45bc 100644 --- a/pkg/services/sqlstore/mockstore/mockstore.go +++ b/pkg/services/sqlstore/mockstore/mockstore.go @@ -503,6 +503,7 @@ func (m *SQLStoreMock) GetDataSourcesByType(ctx context.Context, query *models.G } func (m *SQLStoreMock) GetDefaultDataSource(ctx context.Context, query *models.GetDefaultDataSourceQuery) error { + query.Result = m.ExpectedDatasource return m.ExpectedError }