backend/services: Move GetDashboard from sqlstore to dashboard service (#48971)

* rename folder to match package name
* backend/sqlstore: move GetDashboard into DashboardService

This is a stepping-stone commit which copies the GetDashboard function - which lets us remove the sqlstore from the interfaces in dashboards - without changing any other callers.
* checkpoint: moving GetDashboard calls into dashboard service
* finish refactoring api tests for dashboardService.GetDashboard
This commit is contained in:
Kristin Laemmert 2022-05-17 14:52:22 -04:00 committed by GitHub
parent 9af30f6570
commit 1df340ff28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 376 additions and 269 deletions

View File

@ -53,7 +53,7 @@ func (hs *HTTPServer) GetAnnotations(c *models.ReqContext) response.Response {
item.DashboardUID = val
} else {
query := models.GetDashboardQuery{Id: item.DashboardId, OrgId: c.OrgId}
err := hs.SQLStore.GetDashboard(c.Req.Context(), &query)
err := hs.dashboardService.GetDashboard(c.Req.Context(), &query)
if err == nil && query.Result != nil {
item.DashboardUID = &query.Result.Uid
dashboardCache[item.DashboardId] = &query.Result.Uid
@ -82,7 +82,7 @@ func (hs *HTTPServer) PostAnnotation(c *models.ReqContext) response.Response {
// overwrite dashboardId when dashboardUID is not empty
if cmd.DashboardUID != "" {
query := models.GetDashboardQuery{OrgId: c.OrgId, Uid: cmd.DashboardUID}
err := hs.SQLStore.GetDashboard(c.Req.Context(), &query)
err := hs.dashboardService.GetDashboard(c.Req.Context(), &query)
if err == nil {
cmd.DashboardId = query.Result.Id
}
@ -291,7 +291,7 @@ func (hs *HTTPServer) MassDeleteAnnotations(c *models.ReqContext) response.Respo
if cmd.DashboardUID != "" {
query := models.GetDashboardQuery{OrgId: c.OrgId, Uid: cmd.DashboardUID}
err := hs.SQLStore.GetDashboard(c.Req.Context(), &query)
err := hs.dashboardService.GetDashboard(c.Req.Context(), &query)
if err == nil {
cmd.DashboardId = query.Result.Id
}

View File

@ -16,6 +16,7 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
@ -221,10 +222,6 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
role := models.ROLE_ADMIN
mock := mockstore.NewSQLStoreMock()
mock.ExpectedDashboard = &models.Dashboard{
Id: 1,
Uid: "home",
}
t.Run("Should be able to do anything", func(t *testing.T) {
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, func(sc *scenarioContext) {
@ -327,6 +324,7 @@ func postAnnotationScenario(t *testing.T, desc string, url string, routePattern
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
hs := setupSimpleHTTPServer(nil)
hs.SQLStore = store
hs.dashboardService = &dashboards.FakeDashboardService{}
sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
@ -411,6 +409,7 @@ func deleteAnnotationsScenario(t *testing.T, desc string, url string, routePatte
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
hs := setupSimpleHTTPServer(nil)
hs.SQLStore = store
hs.dashboardService = &dashboards.FakeDashboardService{}
sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {

View File

@ -11,6 +11,8 @@ import (
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/fs"
@ -27,7 +29,7 @@ import (
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
"github.com/grafana/grafana/pkg/services/dashboards"
dashboardsstore "github.com/grafana/grafana/pkg/services/dashboards/database"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/login/loginservice"
@ -41,7 +43,6 @@ import (
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/grafana/grafana/pkg/web/webtest"
"github.com/stretchr/testify/require"
)
func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) {

View File

@ -151,7 +151,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
// lookup folder title
if dash.FolderId > 0 {
query := models.GetDashboardQuery{Id: dash.FolderId, OrgId: c.OrgId}
if err := hs.SQLStore.GetDashboard(c.Req.Context(), &query); err != nil {
if err := hs.dashboardService.GetDashboard(c.Req.Context(), &query); err != nil {
if errors.Is(err, models.ErrFolderNotFound) {
return response.Error(404, "Folder not found", err)
}
@ -242,7 +242,7 @@ func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id in
query = models.GetDashboardQuery{Id: id, OrgId: orgID}
}
if err := hs.SQLStore.GetDashboard(ctx, &query); err != nil {
if err := hs.dashboardService.GetDashboard(ctx, &query); err != nil {
return nil, response.Error(404, "Dashboard not found", err)
}
@ -531,7 +531,7 @@ func (hs *HTTPServer) GetDashboardVersions(c *models.ReqContext) response.Respon
OrgId: c.SignedInUser.OrgId,
Uid: dashUID,
}
if err := hs.SQLStore.GetDashboard(c.Req.Context(), &q); err != nil {
if err := hs.dashboardService.GetDashboard(c.Req.Context(), &q); err != nil {
return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err)
}
dashID = q.Result.Id
@ -589,7 +589,7 @@ func (hs *HTTPServer) GetDashboardVersion(c *models.ReqContext) response.Respons
OrgId: c.SignedInUser.OrgId,
Uid: dashUID,
}
if err := hs.SQLStore.GetDashboard(c.Req.Context(), &q); err != nil {
if err := hs.dashboardService.GetDashboard(c.Req.Context(), &q); err != nil {
return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err)
}
dashID = q.Result.Id

View File

@ -15,7 +15,7 @@ import (
"github.com/grafana/grafana/pkg/models"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/dashboards"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
@ -26,6 +26,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
t.Run("Dashboard permissions test", func(t *testing.T) {
settings := setting.NewCfg()
dashboardStore := &dashboards.FakeDashboardStore{}
dashboardStore.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Return(nil)
defer dashboardStore.AssertExpectations(t)
features := featuremgmt.WithFeatures()

View File

@ -23,7 +23,7 @@ import (
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database"
service "github.com/grafana/grafana/pkg/services/dashboards/manager"
service "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/libraryelements"
@ -101,7 +101,7 @@ func newTestLive(t *testing.T, store *sqlstore.SQLStore) *live.GrafanaLive {
nil,
&usagestats.UsageStatsMock{T: t},
nil,
features, accesscontrolmock.New())
features, accesscontrolmock.New(), &dashboards.FakeDashboardService{})
require.NoError(t, err)
return gLive
}
@ -118,18 +118,22 @@ func TestDashboardAPIEndpoint(t *testing.T) {
fakeDash.Id = 1
fakeDash.FolderId = 1
fakeDash.HasAcl = false
dashboardService := &dashboards.FakeDashboardService{}
dashboardService.GetDashboardFn = func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = fakeDash
return nil
}
mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = fakeDash
hs := &HTTPServer{
Cfg: setting.NewCfg(),
pluginStore: &fakePluginStore{},
SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(),
Features: featuremgmt.WithFeatures(),
Cfg: setting.NewCfg(),
pluginStore: &fakePluginStore{},
SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(),
Features: featuremgmt.WithFeatures(),
dashboardService: dashboardService,
}
hs.SQLStore = mockSQLStore
setUp := func() {
viewerRole := models.ROLE_VIEWER
@ -153,7 +157,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc)
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
@ -185,7 +189,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc)
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
@ -216,14 +220,16 @@ func TestDashboardAPIEndpoint(t *testing.T) {
fakeDash.Id = 1
fakeDash.FolderId = 1
fakeDash.HasAcl = true
dashboardService := &dashboards.FakeDashboardService{}
dashboardService.GetDashboardFn = func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = fakeDash
return nil
}
mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = fakeDash
cfg := setting.NewCfg()
features := featuremgmt.WithFeatures()
sql := sqlstore.InitTestDB(t)
dashboardStore := database.ProvideDashboardStore(sql)
hs := &HTTPServer{
Cfg: cfg,
Live: newTestLive(t, sql),
@ -231,12 +237,8 @@ func TestDashboardAPIEndpoint(t *testing.T) {
LibraryElementService: &mockLibraryElementService{},
SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(),
dashboardService: service.ProvideDashboardService(
cfg, dashboardStore, nil, features,
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
),
dashboardService: dashboardService,
}
hs.SQLStore = mockSQLStore
setUp := func() {
origCanEdit := setting.ViewersCanEdit
@ -281,7 +283,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
sc.sqlStore = mockSQLStore
hs.callDeleteDashboardByUID(t, sc, nil)
hs.callDeleteDashboardByUID(t, sc, &dashboards.FakeDashboardService{})
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
@ -319,7 +321,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUp()
hs.callDeleteDashboardByUID(t, sc, nil)
hs.callDeleteDashboardByUID(t, sc, &dashboards.FakeDashboardService{})
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
@ -357,7 +359,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc)
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
@ -420,7 +422,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
require.True(t, setting.ViewersCanEdit)
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc)
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.True(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
@ -430,7 +432,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
hs.callDeleteDashboardByUID(t, sc, nil)
hs.callDeleteDashboardByUID(t, sc, dashboardService)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
})
@ -450,7 +452,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc)
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
@ -495,7 +497,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
sc.sqlStore = mockSQLStore
dash := getDashboardShouldReturn200(t, sc)
dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService)
assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
@ -503,7 +505,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
setUpInner()
hs.callDeleteDashboardByUID(t, sc, nil)
hs.callDeleteDashboardByUID(t, sc, dashboardService)
assert.Equal(t, 403, sc.resp.Code)
}, mockSQLStore)
@ -780,13 +782,19 @@ func TestDashboardAPIEndpoint(t *testing.T) {
fakeDash.FolderId = folderID
fakeDash.HasAcl = false
saved := &models.Dashboard{
Id: 2,
Uid: "uid",
Title: "Dash",
Slug: "dash",
Version: 1,
}
mock := &dashboards.FakeDashboardService{
SaveDashboardResult: &models.Dashboard{
Id: 2,
Uid: "uid",
Title: "Dash",
Slug: "dash",
Version: 1,
SaveDashboardResult: saved,
GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = fakeDash
return nil
},
}
@ -794,7 +802,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Version: 1,
}
mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = fakeDash
mockSQLStore.ExpectedDashboardVersions = []*models.DashboardVersion{
{
DashboardId: 2,
@ -818,13 +825,19 @@ func TestDashboardAPIEndpoint(t *testing.T) {
fakeDash.Id = 2
fakeDash.HasAcl = false
saved := &models.Dashboard{
Id: 2,
Uid: "uid",
Title: "Dash",
Slug: "dash",
Version: 1,
}
mock := &dashboards.FakeDashboardService{
SaveDashboardResult: &models.Dashboard{
Id: 2,
Uid: "uid",
Title: "Dash",
Slug: "dash",
Version: 1,
SaveDashboardResult: saved,
GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = fakeDash
return nil
},
}
@ -832,7 +845,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Version: 1,
}
mockSQLStore := mockstore.NewSQLStoreMock()
mockSQLStore.ExpectedDashboard = fakeDash
mockSQLStore.ExpectedDashboardVersions = []*models.DashboardVersion{
{
DashboardId: 2,
@ -861,7 +873,12 @@ func TestDashboardAPIEndpoint(t *testing.T) {
dataValue, err := simplejson.NewJson([]byte(`{"id": 1, "editable": true, "style": "dark"}`))
require.NoError(t, err)
mockSQLStore.ExpectedDashboard = &models.Dashboard{Id: 1, Data: dataValue}
dashboardService := &dashboards.FakeDashboardService{
GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = &models.Dashboard{Id: 1, Data: dataValue}
return nil
},
}
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp()
@ -875,7 +892,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
dashboardStore.On("GetProvisionedDataByDashboardID", mock.Anything).Return(&models.DashboardProvisioning{ExternalId: "/dashboard1.json"}, nil).Once()
dash := getDashboardShouldReturn200WithConfig(t, sc, fakeProvisioningService, dashboardStore)
dash := getDashboardShouldReturn200WithConfig(t, sc, fakeProvisioningService, dashboardStore, dashboardService)
assert.Equal(t, "../../../dashboard1.json", dash.Meta.ProvisionedExternalId, mockSQLStore)
}, mockSQLStore)
@ -899,6 +916,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
dashboardProvisioningService: mockDashboardProvisioningService{},
SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(),
dashboardService: dashboardService,
}
hs.callGetDashboard(sc)
@ -913,7 +931,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
})
}
func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, provisioningService provisioning.ProvisioningService, dashboardStore dashboards.Store) dtos.DashboardFullWithMeta {
func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, provisioningService provisioning.ProvisioningService, dashboardStore dashboards.Store, dashboardService dashboards.DashboardService) dtos.DashboardFullWithMeta {
t.Helper()
if provisioningService == nil {
@ -925,6 +943,10 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
dashboardStore = database.ProvideDashboardStore(sql)
}
if dashboardService == nil {
dashboardService = &dashboards.FakeDashboardService{}
}
libraryPanelsService := mockLibraryPanelService{}
libraryElementsService := mockLibraryElementService{}
cfg := setting.NewCfg()
@ -941,6 +963,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
cfg, dashboardStore, nil, features,
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
),
dashboardService: dashboardService,
}
hs.callGetDashboard(sc)
@ -954,10 +977,6 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
return dash
}
func getDashboardShouldReturn200(t *testing.T, sc *scenarioContext) dtos.DashboardFullWithMeta {
return getDashboardShouldReturn200WithConfig(t, sc, nil, nil)
}
func (hs *HTTPServer) callGetDashboard(sc *scenarioContext) {
sc.handlerFunc = hs.GetDashboard
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()

View File

@ -15,7 +15,7 @@ import (
"github.com/grafana/grafana/pkg/models"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/dashboards"
service "github.com/grafana/grafana/pkg/services/dashboards/manager"
service "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"

View File

@ -5,6 +5,7 @@ import (
"net/http"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"

View File

@ -7,16 +7,15 @@ import (
"strings"
"testing"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/web/webtest"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/stretchr/testify/require"
"golang.org/x/oauth2"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/models"
fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/query"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/web/webtest"
)
var queryDatasourceInput = `{

View File

@ -31,7 +31,7 @@ func (hs *HTTPServer) SetHomeDashboard(c *models.ReqContext) response.Response {
dashboardID := cmd.HomeDashboardID
if cmd.HomeDashboardUID != nil {
query := models.GetDashboardQuery{Uid: *cmd.HomeDashboardUID}
err := hs.SQLStore.GetDashboard(c.Req.Context(), &query)
err := hs.dashboardService.GetDashboard(c.Req.Context(), &query)
if err != nil {
return response.Error(404, "Dashboard not found", err)
}
@ -65,7 +65,7 @@ func (hs *HTTPServer) getPreferencesFor(ctx context.Context, orgID, userID, team
// when homedashboardID is 0, that means it is the default home dashboard, no UID would be returned in the response
if preference.HomeDashboardID != 0 {
query := models.GetDashboardQuery{Id: preference.HomeDashboardID, OrgId: orgID}
err = hs.SQLStore.GetDashboard(ctx, &query)
err = hs.dashboardService.GetDashboard(ctx, &query)
if err == nil {
dashboardUID = query.Result.Uid
}
@ -104,7 +104,7 @@ func (hs *HTTPServer) updatePreferencesFor(ctx context.Context, orgID, userID, t
dashboardID := dtoCmd.HomeDashboardID
if dtoCmd.HomeDashboardUID != nil {
query := models.GetDashboardQuery{Uid: *dtoCmd.HomeDashboardUID, OrgId: orgID}
err := hs.SQLStore.GetDashboard(ctx, &query)
err := hs.dashboardService.GetDashboard(ctx, &query)
if err != nil {
return response.Error(404, "Dashboard not found", err)
}
@ -147,7 +147,7 @@ func (hs *HTTPServer) patchPreferencesFor(ctx context.Context, orgID, userID, te
dashboardID := dtoCmd.HomeDashboardID
if dtoCmd.HomeDashboardUID != nil {
query := models.GetDashboardQuery{Uid: *dtoCmd.HomeDashboardUID, OrgId: orgID}
err := hs.SQLStore.GetDashboard(ctx, &query)
err := hs.dashboardService.GetDashboard(ctx, &query)
if err != nil {
return response.Error(404, "Dashboard not found", err)
}

View File

@ -1,19 +1,21 @@
package api
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
"strings"
"testing"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/preference/preftest"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/preference/preftest"
)
var (
@ -32,12 +34,13 @@ var (
func TestAPIEndpoint_GetCurrentOrgPreferences_LegacyAccessControl(t *testing.T) {
sc := setupHTTPServer(t, true, false)
sqlstore := mockstore.NewSQLStoreMock()
sqlstore.ExpectedDashboard = &models.Dashboard{
Uid: "home",
Id: 1,
dashSvc := &dashboards.FakeDashboardService{
GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error {
cmd.Result = &models.Dashboard{Uid: "home", Id: 1}
return nil
},
}
sc.hs.SQLStore = sqlstore
sc.hs.dashboardService = dashSvc
prefService := preftest.NewPreferenceServiceFake()
prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"}
@ -68,13 +71,6 @@ func TestAPIEndpoint_GetCurrentOrgPreferences_AccessControl(t *testing.T) {
sc := setupHTTPServer(t, true, true)
setInitCtxSignedInViewer(sc.initCtx)
sqlstore := mockstore.NewSQLStoreMock()
sqlstore.ExpectedDashboard = &models.Dashboard{
Uid: "home",
Id: 1,
}
sc.hs.SQLStore = sqlstore
prefService := preftest.NewPreferenceServiceFake()
prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"}
sc.hs.preferenceService = prefService
@ -168,12 +164,8 @@ func TestAPIEndpoint_PatchUserPreferences(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, response.Code)
})
input = strings.NewReader(testUpdateOrgPreferencesWithHomeDashboardUIDCmd)
sqlstore := mockstore.NewSQLStoreMock()
sqlstore.ExpectedDashboard = &models.Dashboard{
Uid: "home",
Id: 1,
}
sc.hs.SQLStore = sqlstore
dashSvc := &dashboards.FakeDashboardService{}
sc.hs.dashboardService = dashSvc
t.Run("Returns 200 on success", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPatch, patchUserPreferencesUrl, input, t)
assert.Equal(t, http.StatusOK, response.Code)

View File

@ -26,7 +26,7 @@ func (hs *HTTPServer) GetStars(c *models.ReqContext) response.Response {
Id: dashboardId,
OrgId: c.OrgId,
}
err := hs.SQLStore.GetDashboard(c.Req.Context(), query)
err := hs.dashboardService.GetDashboard(c.Req.Context(), query)
if err != nil {
return response.Error(500, "Failed to get dashboard", err)
}

View File

@ -369,10 +369,6 @@ func TestTeamAPIEndpoint_GetTeamPreferences_RBAC(t *testing.T) {
_, err := sc.db.CreateTeam("team1", "", 1)
sqlstore := mockstore.NewSQLStoreMock()
sqlstore.ExpectedDashboard = &models.Dashboard{
Uid: "home",
Id: 1,
}
sc.hs.SQLStore = sqlstore
prefService := preftest.NewPreferenceServiceFake()

View File

@ -46,7 +46,7 @@ import (
dashboardimportservice "github.com/grafana/grafana/pkg/services/dashboardimport/service"
"github.com/grafana/grafana/pkg/services/dashboards"
dashboardstore "github.com/grafana/grafana/pkg/services/dashboards/database"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
"github.com/grafana/grafana/pkg/services/datasourceproxy"
"github.com/grafana/grafana/pkg/services/datasources"

View File

@ -109,10 +109,11 @@ var DashboardAdminActions = append(DashboardEditActions, []string{dashboards.Act
func ProvideDashboardPermissions(
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
ac accesscontrol.AccessControl, store resourcepermissions.Store,
dashboardStore dashboards.Store,
) (*DashboardPermissionsService, error) {
getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*models.Dashboard, error) {
query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID}
if err := sql.GetDashboard(ctx, query); err != nil {
if err := dashboardStore.GetDashboard(ctx, query); err != nil {
return nil, err
}
return query.Result, nil
@ -141,7 +142,7 @@ func ProvideDashboardPermissions(
}
if dashboard.FolderId > 0 {
query := &models.GetDashboardQuery{Id: dashboard.FolderId, OrgId: orgID}
if err := sql.GetDashboard(ctx, query); err != nil {
if err := dashboardStore.GetDashboard(ctx, query); err != nil {
return nil, err
}
return []string{dashboards.ScopeFoldersProvider.GetResourceScopeUID(query.Result.Uid)}, nil
@ -181,13 +182,14 @@ var FolderAdminActions = append(FolderEditActions, []string{dashboards.ActionFol
func ProvideFolderPermissions(
cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore,
accesscontrol accesscontrol.AccessControl, store resourcepermissions.Store,
dashboardStore dashboards.Store,
) (*FolderPermissionsService, error) {
options := resourcepermissions.Options{
Resource: "folders",
ResourceAttribute: "uid",
ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID}
if err := sql.GetDashboard(ctx, query); err != nil {
if err := dashboardStore.GetDashboard(ctx, query); err != nil {
return err
}

View File

@ -7,24 +7,28 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore"
)
type PermissionChecker struct {
sqlStore *sqlstore.SQLStore
features featuremgmt.FeatureToggles
accessControl accesscontrol.AccessControl
sqlStore *sqlstore.SQLStore
features featuremgmt.FeatureToggles
accessControl accesscontrol.AccessControl
dashboardService dashboards.DashboardService
}
func NewPermissionChecker(sqlStore *sqlstore.SQLStore, features featuremgmt.FeatureToggles, accessControl accesscontrol.AccessControl) *PermissionChecker {
func NewPermissionChecker(sqlStore *sqlstore.SQLStore, features featuremgmt.FeatureToggles,
accessControl accesscontrol.AccessControl, dashboardService dashboards.DashboardService,
) *PermissionChecker {
return &PermissionChecker{sqlStore: sqlStore, features: features, accessControl: accessControl}
}
func (c *PermissionChecker) getDashboardByUid(ctx context.Context, orgID int64, uid string) (*models.Dashboard, error) {
query := models.GetDashboardQuery{Uid: uid, OrgId: orgID}
if err := c.sqlStore.GetDashboard(ctx, &query); err != nil {
if err := c.dashboardService.GetDashboard(ctx, &query); err != nil {
return nil, err
}
return query.Result, nil
@ -32,7 +36,7 @@ func (c *PermissionChecker) getDashboardByUid(ctx context.Context, orgID int64,
func (c *PermissionChecker) getDashboardById(ctx context.Context, orgID int64, id int64) (*models.Dashboard, error) {
query := models.GetDashboardQuery{Id: id, OrgId: orgID}
if err := c.sqlStore.GetDashboard(ctx, &query); err != nil {
if err := c.dashboardService.GetDashboard(ctx, &query); err != nil {
return nil, err
}
return query.Result, nil

View File

@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/comments/commentmodel"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/live"
"github.com/grafana/grafana/pkg/services/sqlstore"
@ -19,7 +20,9 @@ type Service struct {
permissions *commentmodel.PermissionChecker
}
func ProvideService(cfg *setting.Cfg, store *sqlstore.SQLStore, live *live.GrafanaLive, features featuremgmt.FeatureToggles, accessControl accesscontrol.AccessControl) *Service {
func ProvideService(cfg *setting.Cfg, store *sqlstore.SQLStore, live *live.GrafanaLive,
features featuremgmt.FeatureToggles, accessControl accesscontrol.AccessControl,
dashboardService dashboards.DashboardService) *Service {
s := &Service{
cfg: cfg,
live: live,
@ -27,7 +30,7 @@ func ProvideService(cfg *setting.Cfg, store *sqlstore.SQLStore, live *live.Grafa
storage: &sqlStorage{
sql: store,
},
permissions: commentmodel.NewPermissionChecker(store, features, accessControl),
permissions: commentmodel.NewPermissionChecker(store, features, accessControl, dashboardService),
}
return s
}

View File

@ -14,6 +14,7 @@ type DashboardService interface {
MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error
BuildSaveDashboardCommand(ctx context.Context, dto *SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool) (*models.SaveDashboardCommand, error)
UpdateDashboardACL(ctx context.Context, uid int64, items []*models.DashboardAcl) error
GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error
}
// PluginService is a service for operating on plugin dashboards.
@ -51,6 +52,7 @@ type Store interface {
UnprovisionDashboard(ctx context.Context, id int64) error
// GetDashboardsByPluginID retrieves dashboards identified by plugin.
GetDashboardsByPluginID(ctx context.Context, query *models.GetDashboardsByPluginIdQuery) error
GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error
DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error
FolderStore
}

View File

@ -13,6 +13,8 @@ type FakeDashboardService struct {
SaveDashboardError error
SavedDashboards []*SaveDashboardDTO
ProvisionedDashData *models.DashboardProvisioning
GetDashboardFn func(ctx context.Context, cmd *models.GetDashboardQuery) error
}
func (s *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error) {
@ -45,3 +47,15 @@ func (s *FakeDashboardService) GetProvisionedDashboardDataByDashboardID(id int64
func (s *FakeDashboardService) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *models.DeleteOrphanedProvisionedDashboardsCommand) error {
return nil
}
func (s *FakeDashboardService) GetDashboard(ctx context.Context, cmd *models.GetDashboardQuery) error {
if s.GetDashboardFn != nil {
return s.GetDashboardFn(ctx, cmd)
}
// A minimal result for tests that need a valid result, but don't care what's in it.
d := models.NewDashboard("mocked")
d.Id = 1
d.Uid = "1"
cmd.Result = d
return nil
}

View File

@ -21,6 +21,9 @@ type DashboardStore struct {
log log.Logger
}
// DashboardStore implements the Store interface
var _ dashboards.Store = (*DashboardStore)(nil)
func ProvideDashboardStore(sqlStore *sqlstore.SQLStore) *DashboardStore {
return &DashboardStore{sqlStore: sqlStore, log: log.New("dashboard-store")}
}
@ -823,3 +826,25 @@ func (d *DashboardStore) deleteAlertDefinition(dashboardId int64, sess *sqlstore
return nil
}
func (d *DashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
return d.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
if query.Id == 0 && len(query.Slug) == 0 && len(query.Uid) == 0 {
return models.ErrDashboardIdentifierNotSet
}
dashboard := models.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
has, err := sess.Get(&dashboard)
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
}
dashboard.SetId(dashboard.Id)
dashboard.SetUid(dashboard.Uid)
query.Result = &dashboard
return nil
})
}

View File

@ -61,7 +61,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1,
}
err := sqlStore.GetDashboard(context.Background(), &query)
err := dashboardStore.GetDashboard(context.Background(), &query)
require.NoError(t, err)
require.Equal(t, query.Result.Title, "test dash 23")
@ -78,7 +78,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1,
}
err := sqlStore.GetDashboard(context.Background(), &query)
err := dashboardStore.GetDashboard(context.Background(), &query)
require.NoError(t, err)
require.Equal(t, query.Result.Title, "test dash 23")
@ -95,7 +95,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1,
}
err := sqlStore.GetDashboard(context.Background(), &query)
err := dashboardStore.GetDashboard(context.Background(), &query)
require.NoError(t, err)
require.Equal(t, query.Result.Title, "test dash 23")
@ -111,7 +111,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1,
}
err := sqlStore.GetDashboard(context.Background(), &query)
err := dashboardStore.GetDashboard(context.Background(), &query)
require.Equal(t, err, models.ErrDashboardIdentifierNotSet)
})
@ -180,7 +180,7 @@ func TestDashboardDataAccess(t *testing.T) {
OrgId: 1,
}
err = sqlStore.GetDashboard(context.Background(), &query)
err = dashboardStore.GetDashboard(context.Background(), &query)
require.NoError(t, err)
require.Equal(t, query.Result.FolderId, int64(0))
require.Equal(t, query.Result.CreatedBy, savedDash.CreatedBy)

View File

@ -1,4 +1,4 @@
// Code generated by mockery v2.10.0. DO NOT EDIT.
// Code generated by mockery v2.12.2. DO NOT EDIT.
package dashboards
@ -7,6 +7,8 @@ import (
models "github.com/grafana/grafana/pkg/models"
mock "github.com/stretchr/testify/mock"
testing "testing"
)
// FakeDashboardStore is an autogenerated mock type for the Store type
@ -42,6 +44,20 @@ func (_m *FakeDashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Co
return r0
}
// GetDashboard provides a mock function with given fields: ctx, query
func (_m *FakeDashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
ret := _m.Called(ctx, query)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *models.GetDashboardQuery) error); ok {
r0 = rf(ctx, query)
} else {
r0 = ret.Error(0)
}
return r0
}
// GetDashboardsByPluginID provides a mock function with given fields: ctx, query
func (_m *FakeDashboardStore) GetDashboardsByPluginID(ctx context.Context, query *models.GetDashboardsByPluginIdQuery) error {
ret := _m.Called(ctx, query)
@ -302,3 +318,13 @@ func (_m *FakeDashboardStore) ValidateDashboardBeforeSave(dashboard *models.Dash
return r0, r1
}
// NewFakeDashboardStore creates a new instance of FakeDashboardStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
func NewFakeDashboardStore(t testing.TB) *FakeDashboardStore {
mock := &FakeDashboardStore{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -481,3 +481,7 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
return nil
}
func (dr *DashboardServiceImpl) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
return dr.dashboardStore.GetDashboard(ctx, query)
}

View File

@ -7,18 +7,20 @@ import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/dashboards"
dashbboardservice "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const testOrgID int64 = 1
@ -76,7 +78,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
OrgId: otherOrgId,
Uid: sc.savedDashInFolder.Uid,
})
@ -316,7 +318,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id,
OrgId: cmd.OrgId,
})
@ -341,7 +343,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id,
OrgId: cmd.OrgId,
})
@ -366,7 +368,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id)
assert.True(t, res.IsFolder)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id,
OrgId: cmd.OrgId,
})
@ -388,7 +390,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.Greater(t, res.Id, int64(0))
assert.NotEmpty(t, res.Uid)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id,
OrgId: cmd.OrgId,
})
@ -409,7 +411,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id,
OrgId: cmd.OrgId,
})
@ -463,7 +465,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInGeneralFolder.Id,
OrgId: cmd.OrgId,
})
@ -503,7 +505,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInFolder.Id,
OrgId: cmd.OrgId,
})
@ -577,7 +579,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInGeneralFolder.Id,
OrgId: cmd.OrgId,
})
@ -599,7 +601,7 @@ func TestIntegratedDashboardService(t *testing.T) {
res := callSaveWithResult(t, cmd, sc.sqlStore)
require.NotNil(t, res)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInFolder.Id,
OrgId: cmd.OrgId,
})
@ -623,7 +625,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.Equal(t, sc.savedDashInFolder.Id, res.Id)
assert.Equal(t, "new-uid", res.Uid)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: sc.savedDashInFolder.Id,
OrgId: cmd.OrgId,
})
@ -663,7 +665,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.Equal(t, sc.savedDashInFolder.Id, res.Id)
assert.Equal(t, sc.savedDashInFolder.Uid, res.Uid)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id,
OrgId: cmd.OrgId,
})
@ -687,7 +689,7 @@ func TestIntegratedDashboardService(t *testing.T) {
assert.Equal(t, sc.savedDashInGeneralFolder.Id, res.Id)
assert.Equal(t, sc.savedDashInGeneralFolder.Uid, res.Uid)
err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{
Id: res.Id,
OrgId: cmd.OrgId,
})
@ -795,6 +797,7 @@ func TestIntegratedDashboardService(t *testing.T) {
type permissionScenarioContext struct {
dashboardGuardianMock *guardian.FakeDashboardGuardian
sqlStore *sqlstore.SQLStore
dashboardStore dashboards.Store
savedFolder *models.Dashboard
savedDashInFolder *models.Dashboard
otherSavedFolder *models.Dashboard
@ -813,6 +816,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
t.Run(desc, func(t *testing.T) {
sqlStore := sqlstore.InitTestDB(t)
guardian.InitLegacyGuardian(sqlStore)
dashboardStore := database.ProvideDashboardStore(sqlStore)
savedFolder := saveTestFolder(t, "Saved folder", testOrgID, sqlStore)
savedDashInFolder := saveTestDashboard(t, "Saved dash in folder", testOrgID, savedFolder.Id, sqlStore)
@ -847,6 +851,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
otherSavedFolder: otherSavedFolder,
savedDashInGeneralFolder: savedDashInGeneralFolder,
savedFolder: savedFolder,
dashboardStore: dashboardStore,
}
fn(t, sc)

View File

@ -12,7 +12,6 @@ import (
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
)
@ -24,13 +23,12 @@ type FolderServiceImpl struct {
searchService *search.SearchService
features featuremgmt.FeatureToggles
permissions accesscontrol.FolderPermissionsService
sqlStore sqlstore.Store
}
func ProvideFolderService(
cfg *setting.Cfg, dashboardService dashboards.DashboardService, dashboardStore dashboards.Store,
searchService *search.SearchService, features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService,
ac accesscontrol.AccessControl, sqlStore sqlstore.Store,
ac accesscontrol.AccessControl,
) *FolderServiceImpl {
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(dashboardStore))
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(dashboardStore))
@ -43,7 +41,6 @@ func ProvideFolderService(
searchService: searchService,
features: features,
permissions: folderPermissionsService,
sqlStore: sqlStore,
}
}
@ -190,7 +187,7 @@ func (f *FolderServiceImpl) CreateFolder(ctx context.Context, user *models.Signe
func (f *FolderServiceImpl) UpdateFolder(ctx context.Context, user *models.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error {
query := models.GetDashboardQuery{OrgId: orgID, Uid: existingUid}
if err := f.sqlStore.GetDashboard(ctx, &query); err != nil {
if err := f.dashboardStore.GetDashboard(ctx, &query); err != nil {
return toFolderError(err)
}

View File

@ -18,7 +18,6 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
@ -39,7 +38,7 @@ func TestProvideFolderService(t *testing.T) {
ProvideFolderService(
cfg, &dashboards.FakeDashboardService{DashboardService: dashboardService},
store, nil, features, folderPermissions, ac, mockstore.NewSQLStoreMock(),
store, nil, features, folderPermissions, ac,
)
require.Len(t, ac.Calls.RegisterAttributeScopeResolver, 2)
@ -55,7 +54,6 @@ func TestFolderService(t *testing.T) {
folderPermissions := acmock.NewMockedPermissionsService()
dashboardPermissions := acmock.NewMockedPermissionsService()
dashboardService := ProvideDashboardService(cfg, store, nil, features, folderPermissions, dashboardPermissions)
mockStore := mockstore.NewSQLStoreMock()
service := FolderServiceImpl{
cfg: cfg,
@ -65,7 +63,6 @@ func TestFolderService(t *testing.T) {
searchService: nil,
features: features,
permissions: folderPermissions,
sqlStore: mockStore,
}
t.Run("Given user has no permissions", func(t *testing.T) {
@ -105,7 +102,11 @@ func TestFolderService(t *testing.T) {
})
t.Run("When updating folder should return access denied error", func(t *testing.T) {
mockStore.ExpectedDashboard = models.NewDashboardFolder("Folder")
store.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) {
folder := args.Get(1).(*models.GetDashboardQuery)
folder.Result = models.NewDashboard("dashboard-test")
folder.Result.IsFolder = true
}).Return(nil)
err := service.UpdateFolder(context.Background(), user, orgID, folderUID, &models.UpdateFolderCommand{
Uid: folderUID,
Title: "Folder-TEST",
@ -156,8 +157,6 @@ func TestFolderService(t *testing.T) {
dashboardFolder.Uid = util.GenerateShortUID()
f := models.DashboardToFolder(dashboardFolder)
mockStore.ExpectedDashboard = dashboardFolder
store.On("ValidateDashboardBeforeSave", mock.Anything, mock.Anything).Return(true, nil)
store.On("SaveDashboard", mock.Anything).Return(dashboardFolder, nil)
store.On("GetFolderByID", mock.Anything, orgID, dashboardFolder.Id).Return(f, nil)

View File

@ -25,6 +25,7 @@ func NewAccessControlDashboardGuardian(
store sqlstore.Store, ac accesscontrol.AccessControl,
folderPermissionsService accesscontrol.FolderPermissionsService,
dashboardPermissionsService accesscontrol.DashboardPermissionsService,
dashboardService dashboards.DashboardService,
) *AccessControlDashboardGuardian {
return &AccessControlDashboardGuardian{
ctx: ctx,
@ -35,6 +36,7 @@ func NewAccessControlDashboardGuardian(
ac: ac,
folderPermissionsService: folderPermissionsService,
dashboardPermissionsService: dashboardPermissionsService,
dashboardService: dashboardService,
}
}
@ -49,6 +51,7 @@ type AccessControlDashboardGuardian struct {
ac accesscontrol.AccessControl
folderPermissionsService accesscontrol.FolderPermissionsService
dashboardPermissionsService accesscontrol.DashboardPermissionsService
dashboardService dashboards.DashboardService
}
func (a *AccessControlDashboardGuardian) CanSave() (bool, error) {
@ -264,7 +267,7 @@ func (a *AccessControlDashboardGuardian) GetHiddenACL(cfg *setting.Cfg) ([]*mode
func (a *AccessControlDashboardGuardian) loadDashboard() error {
if a.dashboard == nil {
query := &models.GetDashboardQuery{Id: a.dashboardID, OrgId: a.user.OrgId}
if err := a.store.GetDashboard(a.ctx, query); err != nil {
if err := a.dashboardService.GetDashboard(a.ctx, query); err != nil {
return err
}
if !query.Result.IsFolder {
@ -284,7 +287,7 @@ func (a *AccessControlDashboardGuardian) loadParentFolder(folderID int64) (*mode
return &models.Dashboard{Uid: accesscontrol.GeneralFolderUID}, nil
}
folderQuery := &models.GetDashboardQuery{Id: folderID, OrgId: a.user.OrgId}
if err := a.store.GetDashboard(a.ctx, folderQuery); err != nil {
if err := a.dashboardService.GetDashboard(a.ctx, folderQuery); err != nil {
return nil, err
}
return folderQuery.Result, nil

View File

@ -595,10 +595,12 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []*acc
})
require.NoError(t, err)
ac := accesscontrolmock.New().WithPermissions(permissions)
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store))
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), &dashboards.FakeDashboardStore{})
require.NoError(t, err)
dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions(setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store))
dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), &dashboards.FakeDashboardStore{})
require.NoError(t, err)
return NewAccessControlDashboardGuardian(context.Background(), dash.Id, &models.SignedInUser{OrgId: 1}, store, ac, folderPermissions, dashboardPermissions), dash
return NewAccessControlDashboardGuardian(context.Background(), dash.Id, &models.SignedInUser{OrgId: 1}, store, ac, folderPermissions, dashboardPermissions, &dashboards.FakeDashboardService{}), dash
}

View File

@ -7,9 +7,10 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert"
)
type scenarioContext struct {

View File

@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/sqlstore"
)
@ -13,10 +14,11 @@ type Provider struct{}
func ProvideService(
store *sqlstore.SQLStore, ac accesscontrol.AccessControl,
folderPermissionsService accesscontrol.FolderPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService,
dashboardService dashboards.DashboardService,
) *Provider {
if !ac.IsDisabled() {
// TODO: Fix this hack, see https://github.com/grafana/grafana-enterprise/issues/2935
InitAccessControlGuardian(store, ac, folderPermissionsService, dashboardPermissionsService)
InitAccessControlGuardian(store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
} else {
InitLegacyGuardian(store)
}
@ -31,9 +33,9 @@ func InitLegacyGuardian(store sqlstore.Store) {
func InitAccessControlGuardian(
store sqlstore.Store, ac accesscontrol.AccessControl, folderPermissionsService accesscontrol.FolderPermissionsService,
dashboardPermissionsService accesscontrol.DashboardPermissionsService,
dashboardPermissionsService accesscontrol.DashboardPermissionsService, dashboardService dashboards.DashboardService,
) {
New = func(ctx context.Context, dashId int64, orgId int64, user *models.SignedInUser) DashboardGuardian {
return NewAccessControlDashboardGuardian(ctx, dashId, user, store, ac, folderPermissionsService, dashboardPermissionsService)
return NewAccessControlDashboardGuardian(ctx, dashId, user, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService)
}
}

View File

@ -19,7 +19,7 @@ import (
"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"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore"
@ -235,7 +235,7 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string
ac := acmock.New()
s := dashboardservice.ProvideFolderService(
cfg, d, dashboardStore, nil,
features, folderPermissions, ac, nil,
features, folderPermissions, ac,
)
t.Logf("Creating folder with title and UID %q", title)
folder, err := s.CreateFolder(context.Background(), &user, user.OrgId, title, title)
@ -340,7 +340,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
SQLStore: sqlStore,
folderService: dashboardservice.ProvideFolderService(
cfg, dashboardService, dashboardStore, nil,
features, folderPermissions, ac, nil,
features, folderPermissions, ac,
),
}

View File

@ -17,7 +17,7 @@ import (
"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"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/libraryelements"
@ -1392,7 +1392,7 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string
dashboardPermissions := acmock.NewMockedPermissionsService()
dashboardStore := database.ProvideDashboardStore(sqlStore)
d := dashboardservice.ProvideDashboardService(cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions)
s := dashboardservice.ProvideFolderService(cfg, d, dashboardStore, nil, features, folderPermissions, ac, nil)
s := dashboardservice.ProvideFolderService(cfg, d, dashboardStore, nil, features, folderPermissions, ac)
t.Logf("Creating folder with title and UID %q", title)
folder, err := s.CreateFolder(context.Background(), user, user.OrgId, title, title)
@ -1496,7 +1496,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
folderService := dashboardservice.ProvideFolderService(
cfg, dashboardService, dashboardStore, nil,
features, folderPermissions, ac, nil,
features, folderPermissions, ac,
)
elementService := libraryelements.ProvideService(cfg, sqlStore, routing.NewRouteRegister(), folderService)

View File

@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore"
)
@ -37,9 +38,10 @@ type dashboardEvent struct {
// DashboardHandler manages all the `grafana/dashboard/*` channels
type DashboardHandler struct {
Publisher models.ChannelPublisher
ClientCount models.ChannelClientCount
Store sqlstore.Store
Publisher models.ChannelPublisher
ClientCount models.ChannelClientCount
Store sqlstore.Store
DashboardService dashboards.DashboardService
}
// GetHandlerForPath called on init
@ -63,7 +65,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *models.SignedI
// make sure can view this dashboard
if len(parts) == 2 && parts[0] == "uid" {
query := models.GetDashboardQuery{Uid: parts[1], OrgId: user.OrgId}
if err := h.Store.GetDashboard(ctx, &query); err != nil {
if err := h.DashboardService.GetDashboard(ctx, &query); err != nil {
logger.Error("Error getting dashboard", "query", query, "error", err)
return models.SubscribeReply{}, backend.SubscribeStreamStatusNotFound, nil
}
@ -110,7 +112,7 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, user *models.SignedInU
return models.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("ignore???")
}
query := models.GetDashboardQuery{Uid: parts[1], OrgId: user.OrgId}
if err := h.Store.GetDashboard(ctx, &query); err != nil {
if err := h.DashboardService.GetDashboard(ctx, &query); err != nil {
logger.Error("Unknown dashboard", "query", query)
return models.PublishReply{}, backend.PublishStreamStatusNotFound, nil
}

View File

@ -26,6 +26,7 @@ import (
"github.com/grafana/grafana/pkg/plugins/plugincontext"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/comments/commentmodel"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/live/database"
@ -71,7 +72,7 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
pluginStore plugins.Store, cacheService *localcache.CacheService,
dataSourceCache datasources.CacheService, sqlStore *sqlstore.SQLStore, secretsService secrets.Service,
usageStatsService usagestats.Service, queryDataService *query.Service, toggles featuremgmt.FeatureToggles,
accessControl accesscontrol.AccessControl) (*GrafanaLive, error) {
accessControl accesscontrol.AccessControl, dashboardService dashboards.DashboardService) (*GrafanaLive, error) {
g := &GrafanaLive{
Cfg: cfg,
Features: toggles,
@ -234,15 +235,16 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
// Initialize the main features
dash := &features.DashboardHandler{
Publisher: g.Publish,
ClientCount: g.ClientCount,
Store: sqlStore,
Publisher: g.Publish,
ClientCount: g.ClientCount,
Store: sqlStore,
DashboardService: dashboardService,
}
g.storage = database.NewStorage(g.SQLStore, g.CacheService)
g.GrafanaScope.Dashboards = dash
g.GrafanaScope.Features["dashboard"] = dash
g.GrafanaScope.Features["broadcast"] = features.NewBroadcastRunner(g.storage)
g.GrafanaScope.Features["comment"] = features.NewCommentHandler(commentmodel.NewPermissionChecker(g.SQLStore, g.Features, accessControl))
g.GrafanaScope.Features["comment"] = features.NewCommentHandler(commentmodel.NewPermissionChecker(g.SQLStore, g.Features, accessControl, dashboardService))
g.surveyCaller = survey.NewCaller(managedStreamRunner, node)
err = g.surveyCaller.SetupHandlers()

View File

@ -33,7 +33,7 @@ import (
func ProvideService(cfg *setting.Cfg, dataSourceCache datasources.CacheService, routeRegister routing.RouteRegister,
sqlStore *sqlstore.SQLStore, kvStore kvstore.KVStore, expressionService *expr.Service, dataProxy *datasourceproxy.DataSourceProxyService,
quotaService *quota.QuotaService, secretsService secrets.Service, notificationService notifications.Service, m *metrics.NGAlert,
folderService dashboards.FolderService, ac accesscontrol.AccessControl) (*AlertNG, error) {
folderService dashboards.FolderService, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService) (*AlertNG, error) {
ng := &AlertNG{
Cfg: cfg,
DataSourceCache: dataSourceCache,
@ -79,6 +79,7 @@ type AlertNG struct {
schedule schedule.ScheduleService
stateManager *state.Manager
folderService dashboards.FolderService
dashboardService dashboards.DashboardService
// Alerting notification services
MultiOrgAlertmanager *notifier.MultiOrgAlertmanager
@ -131,7 +132,7 @@ func (ng *AlertNG) init() error {
ng.Log.Error("Failed to parse application URL. Continue without it.", "error", err)
appUrl = nil
}
stateManager := state.NewManager(ng.Log, ng.Metrics.GetStateMetrics(), appUrl, store, store, ng.SQLStore)
stateManager := state.NewManager(ng.Log, ng.Metrics.GetStateMetrics(), appUrl, store, store, ng.SQLStore, ng.dashboardService)
scheduler := schedule.NewScheduler(schedCfg, ng.ExpressionService, appUrl, stateManager)
ng.stateManager = stateManager

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
"github.com/grafana/grafana/pkg/services/ngalert/models"
@ -106,7 +107,7 @@ func TestWarmStateCache(t *testing.T) {
Metrics: testMetrics.GetSchedulerMetrics(),
AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests.
}
st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore)
st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore, &dashboards.FakeDashboardService{})
st.Warm(ctx)
t.Run("instance cache has expected entries", func(t *testing.T) {
@ -158,7 +159,7 @@ func TestAlertingTicker(t *testing.T) {
disabledOrgID: {},
},
}
st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore)
st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore, &dashboards.FakeDashboardService{})
appUrl := &url.URL{
Scheme: "http",
Host: "localhost",

View File

@ -21,6 +21,7 @@ import (
"github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
"github.com/grafana/grafana/pkg/services/ngalert/models"
@ -925,7 +926,7 @@ func setupScheduler(t *testing.T, rs store.RuleStore, is store.InstanceStore, ac
Metrics: m.GetSchedulerMetrics(),
AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests.
}
st := state.NewManager(schedCfg.Logger, m.GetStateMetrics(), nil, rs, is, mockstore.NewSQLStoreMock())
st := state.NewManager(schedCfg.Logger, m.GetStateMetrics(), nil, rs, is, mockstore.NewSQLStoreMock(), &dashboards.FakeDashboardService{})
appUrl := &url.URL{
Scheme: "http",
Host: "localhost",

View File

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
ngModels "github.com/grafana/grafana/pkg/services/ngalert/models"
@ -36,22 +37,25 @@ type Manager struct {
quit chan struct{}
ResendDelay time.Duration
ruleStore store.RuleStore
instanceStore store.InstanceStore
sqlStore sqlstore.Store
ruleStore store.RuleStore
instanceStore store.InstanceStore
sqlStore sqlstore.Store
dashboardService dashboards.DashboardService
}
func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL, ruleStore store.RuleStore,
instanceStore store.InstanceStore, sqlStore sqlstore.Store) *Manager {
func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL,
ruleStore store.RuleStore, instanceStore store.InstanceStore, sqlStore sqlstore.Store,
dashboardService dashboards.DashboardService) *Manager {
manager := &Manager{
cache: newCache(logger, metrics, externalURL),
quit: make(chan struct{}),
ResendDelay: ResendDelay, // TODO: make this configurable
log: logger,
metrics: metrics,
ruleStore: ruleStore,
instanceStore: instanceStore,
sqlStore: sqlStore,
cache: newCache(logger, metrics, externalURL),
quit: make(chan struct{}),
ResendDelay: ResendDelay, // TODO: make this configurable
log: logger,
metrics: metrics,
ruleStore: ruleStore,
instanceStore: instanceStore,
sqlStore: sqlStore,
dashboardService: dashboardService,
}
go manager.recordMetrics()
return manager
@ -274,7 +278,7 @@ func (st *Manager) annotateState(ctx context.Context, alertRule *ngModels.AlertR
OrgId: alertRule.OrgID,
}
err = st.sqlStore.GetDashboard(ctx, query)
err = st.dashboardService.GetDashboard(ctx, query)
if err != nil {
st.log.Error("error getting dashboard for alert annotation", "dashboardUID", dashUid, "alertRuleUID", alertRule.UID, "error", err.Error())
return

View File

@ -9,6 +9,7 @@ import (
"time"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
@ -37,7 +38,7 @@ func TestDashboardAnnotations(t *testing.T) {
_, dbstore := tests.SetupTestEnv(t, 1)
sqlStore := mockstore.NewSQLStoreMock()
st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore)
st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore, &dashboards.FakeDashboardService{})
fakeAnnoRepo := store.NewFakeAnnotationsRepo()
annotations.SetRepository(fakeAnnoRepo)
@ -1770,7 +1771,7 @@ func TestProcessEvalResults(t *testing.T) {
for _, tc := range testCases {
ss := mockstore.NewSQLStoreMock()
st := state.NewManager(log.New("test_state_manager"), testMetrics.GetStateMetrics(), nil, nil, &store.FakeInstanceStore{}, ss)
st := state.NewManager(log.New("test_state_manager"), testMetrics.GetStateMetrics(), nil, nil, &store.FakeInstanceStore{}, ss, &dashboards.FakeDashboardService{})
t.Run(tc.desc, func(t *testing.T) {
fakeAnnoRepo := store.NewFakeAnnotationsRepo()
annotations.SetRepository(fakeAnnoRepo)
@ -1881,7 +1882,7 @@ func TestStaleResultsHandler(t *testing.T) {
for _, tc := range testCases {
ctx := context.Background()
sqlStore := mockstore.NewSQLStoreMock()
st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore)
st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore, &dashboards.FakeDashboardService{})
st.Warm(ctx)
existingStatesForRule := st.GetStatesForRuleUID(rule.OrgID, rule.UID)

View File

@ -10,8 +10,9 @@ import (
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/dashboards"
databasestore "github.com/grafana/grafana/pkg/services/dashboards/database"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager"
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/ngalert"
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
@ -60,12 +61,12 @@ func SetupTestEnv(t *testing.T, baseInterval time.Duration) (*ngalert.AlertNG, *
)
folderService := dashboardservice.ProvideFolderService(
cfg, dashboardService, dashboardStore, nil,
features, folderPermissions, ac, nil,
features, folderPermissions, ac,
)
ng, err := ngalert.ProvideService(
cfg, nil, routing.NewRouteRegister(), sqlStore,
nil, nil, nil, nil, secretsService, nil, m, folderService, ac,
cfg, nil, routing.NewRouteRegister(), sqlStore, nil, nil, nil, nil,
secretsService, nil, m, folderService, ac, &dashboards.FakeDashboardService{},
)
require.NoError(t, err)
return ng, &store.DBstore{

View File

@ -26,25 +26,27 @@ import (
func ProvideService(cfg *setting.Cfg, sqlStore *sqlstore.SQLStore, pluginStore plugifaces.Store,
encryptionService encryption.Internal, notificatonService *notifications.NotificationService,
dashboardService dashboardservice.DashboardProvisioningService,
dashboardProvisioningService dashboardservice.DashboardProvisioningService,
datasourceService datasourceservice.DataSourceService,
dashboardService dashboardservice.DashboardService,
alertingService *alerting.AlertNotificationService, pluginSettings pluginsettings.Service,
) (*ProvisioningServiceImpl, error) {
s := &ProvisioningServiceImpl{
Cfg: cfg,
SQLStore: sqlStore,
pluginStore: pluginStore,
EncryptionService: encryptionService,
NotificationService: notificatonService,
log: log.New("provisioning"),
newDashboardProvisioner: dashboards.New,
provisionNotifiers: notifiers.Provision,
provisionDatasources: datasources.Provision,
provisionPlugins: plugins.Provision,
dashboardService: dashboardService,
datasourceService: datasourceService,
alertingService: alertingService,
pluginsSettings: pluginSettings,
Cfg: cfg,
SQLStore: sqlStore,
pluginStore: pluginStore,
EncryptionService: encryptionService,
NotificationService: notificatonService,
log: log.New("provisioning"),
newDashboardProvisioner: dashboards.New,
provisionNotifiers: notifiers.Provision,
provisionDatasources: datasources.Provision,
provisionPlugins: plugins.Provision,
dashboardProvisioningService: dashboardProvisioningService,
dashboardService: dashboardService,
datasourceService: datasourceService,
alertingService: alertingService,
pluginsSettings: pluginSettings,
}
return s, nil
}
@ -88,23 +90,24 @@ func newProvisioningServiceImpl(
}
type ProvisioningServiceImpl struct {
Cfg *setting.Cfg
SQLStore *sqlstore.SQLStore
pluginStore plugifaces.Store
EncryptionService encryption.Internal
NotificationService *notifications.NotificationService
log log.Logger
pollingCtxCancel context.CancelFunc
newDashboardProvisioner dashboards.DashboardProvisionerFactory
dashboardProvisioner dashboards.DashboardProvisioner
provisionNotifiers func(context.Context, string, notifiers.Manager, notifiers.SQLStore, encryption.Internal, *notifications.NotificationService) error
provisionDatasources func(context.Context, string, datasources.Store, utils.OrgStore) error
provisionPlugins func(context.Context, string, plugins.Store, plugifaces.Store, pluginsettings.Service) error
mutex sync.Mutex
dashboardService dashboardservice.DashboardProvisioningService
datasourceService datasourceservice.DataSourceService
alertingService *alerting.AlertNotificationService
pluginsSettings pluginsettings.Service
Cfg *setting.Cfg
SQLStore *sqlstore.SQLStore
pluginStore plugifaces.Store
EncryptionService encryption.Internal
NotificationService *notifications.NotificationService
log log.Logger
pollingCtxCancel context.CancelFunc
newDashboardProvisioner dashboards.DashboardProvisionerFactory
dashboardProvisioner dashboards.DashboardProvisioner
provisionNotifiers func(context.Context, string, notifiers.Manager, notifiers.SQLStore, encryption.Internal, *notifications.NotificationService) error
provisionDatasources func(context.Context, string, datasources.Store, utils.OrgStore) error
provisionPlugins func(context.Context, string, plugins.Store, plugifaces.Store, pluginsettings.Service) error
mutex sync.Mutex
dashboardProvisioningService dashboardservice.DashboardProvisioningService
dashboardService dashboardservice.DashboardService
datasourceService datasourceservice.DataSourceService
alertingService *alerting.AlertNotificationService
pluginsSettings pluginsettings.Service
}
func (ps *ProvisioningServiceImpl) RunInitProvisioners(ctx context.Context) error {
@ -187,7 +190,7 @@ func (ps *ProvisioningServiceImpl) ProvisionNotifications(ctx context.Context) e
func (ps *ProvisioningServiceImpl) ProvisionDashboards(ctx context.Context) error {
dashboardPath := filepath.Join(ps.Cfg.ProvisioningPath, "dashboards")
dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardService, ps.SQLStore, ps.SQLStore)
dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardProvisioningService, ps.SQLStore, ps.dashboardService)
if err != nil {
return errutil.Wrap("Failed to create provisioner", err)
}

View File

@ -29,28 +29,6 @@ func init() {
var generateNewUid func() string = util.GenerateShortUID
func (ss *SQLStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
return ss.WithDbSession(ctx, func(dbSession *DBSession) error {
if query.Id == 0 && len(query.Slug) == 0 && len(query.Uid) == 0 {
return models.ErrDashboardIdentifierNotSet
}
dashboard := models.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
has, err := dbSession.Get(&dashboard)
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
}
dashboard.SetId(dashboard.Id)
dashboard.SetUid(dashboard.Uid)
query.Result = &dashboard
return nil
})
}
type DashboardSearchProjection struct {
ID int64 `xorm:"id"`
UID string `xorm:"uid"`

View File

@ -9,11 +9,12 @@ import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/require"
)
func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard, data map[string]interface{}) {
@ -94,14 +95,13 @@ func TestGetDashboardVersion(t *testing.T) {
require.Equal(t, query.DashboardId, savedDash.Id)
require.Equal(t, query.Version, savedDash.Version)
dashCmd := models.GetDashboardQuery{
OrgId: savedDash.OrgId,
dashCmd := &models.Dashboard{
Uid: savedDash.Uid,
OrgId: savedDash.OrgId,
}
err = sqlStore.GetDashboard(context.Background(), &dashCmd)
err = getDashboard(t, sqlStore, dashCmd)
require.Nil(t, err)
eq := reflect.DeepEqual(dashCmd.Result.Data, query.Result.Data)
eq := reflect.DeepEqual(dashCmd.Data, query.Result.Data)
require.Equal(t, true, eq)
})
@ -222,3 +222,20 @@ func TestDeleteExpiredVersions(t *testing.T) {
require.LessOrEqual(t, versionsToWriteBigNumber-len(query.Result), perBatch*maxBatches)
})
}
func getDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard) error {
t.Helper()
return sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
has, err := sess.Get(dashboard)
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
}
dashboard.SetId(dashboard.Id)
dashboard.SetUid(dashboard.Uid)
return nil
})
}

View File

@ -20,7 +20,6 @@ type SQLStoreMock struct {
ExpectedDatasource *models.DataSource
ExpectedAlert *models.Alert
ExpectedPluginSetting *models.PluginSetting
ExpectedDashboard *models.Dashboard
ExpectedDashboards []*models.Dashboard
ExpectedDashboardVersion *models.DashboardVersion
ExpectedDashboardVersions []*models.DashboardVersion
@ -466,11 +465,6 @@ func (m *SQLStoreMock) SaveDashboard(cmd models.SaveDashboardCommand) (*models.D
return nil, m.ExpectedError
}
func (m *SQLStoreMock) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error {
query.Result = m.ExpectedDashboard
return m.ExpectedError
}
func (m SQLStoreMock) SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error {
query.Result = m.ExpectedPersistedDashboards
return m.ExpectedError

View File

@ -100,7 +100,6 @@ type Store interface {
GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQuery) error
SearchOrgUsers(ctx context.Context, query *models.SearchOrgUsersQuery) error
RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUserCommand) error
GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error
GetDashboardTags(ctx context.Context, query *models.GetDashboardTagsQuery) error
SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error
GetDashboards(ctx context.Context, query *models.GetDashboardsQuery) error

View File

@ -9,11 +9,14 @@ import (
"net/http"
"time"
"github.com/segmentio/encoding/json"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/serverlock"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/live"
@ -21,7 +24,6 @@ import (
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/segmentio/encoding/json"
)
type Service interface {
@ -53,6 +55,7 @@ type thumbService struct {
log log.Logger
canRunCrawler bool
settings setting.DashboardPreviewsSettings
dashboardService dashboards.DashboardService
}
type crawlerScheduleOptions struct {
@ -65,7 +68,10 @@ type crawlerScheduleOptions struct {
auth CrawlerAuth
}
func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, lockService *serverlock.ServerLockService, renderService rendering.Service, gl *live.GrafanaLive, store *sqlstore.SQLStore, authSetupService CrawlerAuthSetupService) Service {
func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles,
lockService *serverlock.ServerLockService, renderService rendering.Service,
gl *live.GrafanaLive, store *sqlstore.SQLStore, authSetupService CrawlerAuthSetupService,
dashboardService dashboards.DashboardService) Service {
if !features.IsEnabled(featuremgmt.FlagDashboardPreviews) {
return &dummyService{}
}
@ -96,7 +102,6 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, lockS
log: logger,
canRunCrawler: canRunCrawler,
settings: cfg.DashboardPreviews,
scheduleOptions: crawlerScheduleOptions{
tickerInterval: 5 * time.Minute,
crawlInterval: cfg.DashboardPreviews.SchedulerInterval,
@ -106,6 +111,7 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, lockS
themes: []models.Theme{models.ThemeDark, models.ThemeLight},
auth: crawlerAuth,
},
dashboardService: dashboardService,
}
return t
@ -400,7 +406,7 @@ func (hs *thumbService) getStatus(c *models.ReqContext, uid string, checkSave bo
func (hs *thumbService) getDashboardId(c *models.ReqContext, uid string) (int64, error) {
query := models.GetDashboardQuery{Uid: uid, OrgId: c.OrgId}
if err := hs.store.GetDashboard(c.Req.Context(), &query); err != nil {
if err := hs.dashboardService.GetDashboard(c.Req.Context(), &query); err != nil {
return 0, err
}