From 96b032e1039b71cc250ca52d16d524861ede7688 Mon Sep 17 00:00:00 2001 From: Serge Zaitsev Date: Mon, 19 Sep 2022 11:29:22 +0200 Subject: [PATCH] Chore: Split dashboard thumbnail service (#55344) * Chore: split dashboard thumbnail service * fix typo * move tests * make linter happy --- .../dashboardthumbsimpl/dashboard_thumbs.go | 19 +- .../dashboardthumbsimpl/store.go | 224 ++++++++++ .../dashboardthumbsimpl/store_test.go | 399 ++++++++++++++++++ pkg/services/sqlstore/dashboard_thumbs.go | 211 --------- .../sqlstore/dashboard_thumbs_test.go | 342 --------------- pkg/services/thumbs/repo.go | 8 +- pkg/services/thumbs/service.go | 5 +- 7 files changed, 639 insertions(+), 569 deletions(-) delete mode 100644 pkg/services/sqlstore/dashboard_thumbs.go delete mode 100644 pkg/services/sqlstore/dashboard_thumbs_test.go diff --git a/pkg/services/dashboard_thumbs/dashboardthumbsimpl/dashboard_thumbs.go b/pkg/services/dashboard_thumbs/dashboardthumbsimpl/dashboard_thumbs.go index b4dd71e8f1f..7c7bfe899df 100644 --- a/pkg/services/dashboard_thumbs/dashboardthumbsimpl/dashboard_thumbs.go +++ b/pkg/services/dashboard_thumbs/dashboardthumbsimpl/dashboard_thumbs.go @@ -5,24 +5,23 @@ import ( "github.com/grafana/grafana/pkg/models" dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs" - "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/sqlstore/db" ) type Service struct { - // TODO remove sqlstore - sqlStore *sqlstore.SQLStore + store store } func ProvideService( - ss *sqlstore.SQLStore, + db db.DB, ) dashboardthumbs.Service { return &Service{ - sqlStore: ss, + store: &xormStore{db: db}, } } func (s *Service) GetThumbnail(ctx context.Context, query *models.GetDashboardThumbnailCommand) (*models.DashboardThumbnail, error) { - dt, err := s.sqlStore.GetThumbnail(ctx, query) + dt, err := s.store.Get(ctx, query) if err != nil { return dt, err } @@ -30,7 +29,7 @@ func (s *Service) GetThumbnail(ctx context.Context, query *models.GetDashboardTh } func (s *Service) SaveThumbnail(ctx context.Context, cmd *models.SaveDashboardThumbnailCommand) (*models.DashboardThumbnail, error) { - dt, err := s.sqlStore.SaveThumbnail(ctx, cmd) + dt, err := s.store.Save(ctx, cmd) if err != nil { return dt, err } @@ -38,7 +37,7 @@ func (s *Service) SaveThumbnail(ctx context.Context, cmd *models.SaveDashboardTh } func (s *Service) UpdateThumbnailState(ctx context.Context, cmd *models.UpdateThumbnailStateCommand) error { - err := s.sqlStore.UpdateThumbnailState(ctx, cmd) + err := s.store.UpdateState(ctx, cmd) if err != nil { return err } @@ -46,7 +45,7 @@ func (s *Service) UpdateThumbnailState(ctx context.Context, cmd *models.UpdateTh } func (s *Service) FindThumbnailCount(ctx context.Context, cmd *models.FindDashboardThumbnailCountCommand) (int64, error) { - i, err := s.sqlStore.FindThumbnailCount(ctx, cmd) + i, err := s.store.Count(ctx, cmd) if err != nil { return i, err } @@ -54,7 +53,7 @@ func (s *Service) FindThumbnailCount(ctx context.Context, cmd *models.FindDashbo } func (s *Service) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *models.FindDashboardsWithStaleThumbnailsCommand) ([]*models.DashboardWithStaleThumbnail, error) { - d, err := s.sqlStore.FindDashboardsWithStaleThumbnails(ctx, cmd) + d, err := s.store.FindDashboardsWithStaleThumbnails(ctx, cmd) if err != nil { return d, err } diff --git a/pkg/services/dashboard_thumbs/dashboardthumbsimpl/store.go b/pkg/services/dashboard_thumbs/dashboardthumbsimpl/store.go index 126fbc20bad..754797d008f 100644 --- a/pkg/services/dashboard_thumbs/dashboardthumbsimpl/store.go +++ b/pkg/services/dashboard_thumbs/dashboardthumbsimpl/store.go @@ -1 +1,225 @@ package dashboardthumbsimpl + +import ( + "context" + "encoding/json" + "errors" + "time" + + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/sqlstore/db" +) + +type store interface { + Get(ctx context.Context, query *models.GetDashboardThumbnailCommand) (*models.DashboardThumbnail, error) + Save(ctx context.Context, cmd *models.SaveDashboardThumbnailCommand) (*models.DashboardThumbnail, error) + UpdateState(ctx context.Context, cmd *models.UpdateThumbnailStateCommand) error + Count(ctx context.Context, cmd *models.FindDashboardThumbnailCountCommand) (int64, error) + FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *models.FindDashboardsWithStaleThumbnailsCommand) ([]*models.DashboardWithStaleThumbnail, error) +} + +type xormStore struct { + db db.DB +} + +func (ss *xormStore) Get(ctx context.Context, query *models.GetDashboardThumbnailCommand) (*models.DashboardThumbnail, error) { + err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + result, err := findThumbnailByMeta(sess, query.DashboardThumbnailMeta) + if err != nil { + return err + } + query.Result = result + return nil + }) + + return query.Result, err +} + +func marshalDatasourceUids(dsUids []string) (string, error) { + if dsUids == nil { + return "", nil + } + + b, err := json.Marshal(dsUids) + if err != nil { + return "", err + } + return string(b), nil +} + +func (ss *xormStore) Save(ctx context.Context, cmd *models.SaveDashboardThumbnailCommand) (*models.DashboardThumbnail, error) { + err := ss.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error { + existing, err := findThumbnailByMeta(sess, cmd.DashboardThumbnailMeta) + + if err != nil && !errors.Is(err, dashboards.ErrDashboardThumbnailNotFound) { + return err + } + + dsUids, err := marshalDatasourceUids(cmd.DatasourceUIDs) + if err != nil { + return err + } + + if existing != nil { + existing.Image = cmd.Image + existing.MimeType = cmd.MimeType + existing.Updated = time.Now() + existing.DashboardVersion = cmd.DashboardVersion + existing.DsUIDs = dsUids + existing.State = models.ThumbnailStateDefault + _, err = sess.ID(existing.Id).Update(existing) + cmd.Result = existing + return err + } + + thumb := &models.DashboardThumbnail{} + + dash, err := findDashboardIdByThumbMeta(sess, cmd.DashboardThumbnailMeta) + + if err != nil { + return err + } + + thumb.Updated = time.Now() + thumb.Theme = cmd.Theme + thumb.Kind = cmd.Kind + thumb.Image = cmd.Image + thumb.DsUIDs = dsUids + thumb.MimeType = cmd.MimeType + thumb.DashboardId = dash.Id + thumb.DashboardVersion = cmd.DashboardVersion + thumb.State = models.ThumbnailStateDefault + thumb.PanelId = cmd.PanelID + _, err = sess.Insert(thumb) + cmd.Result = thumb + return err + }) + + return cmd.Result, err +} + +func (ss *xormStore) UpdateState(ctx context.Context, cmd *models.UpdateThumbnailStateCommand) error { + err := ss.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error { + existing, err := findThumbnailByMeta(sess, cmd.DashboardThumbnailMeta) + + if err != nil { + return err + } + + existing.State = cmd.State + _, err = sess.ID(existing.Id).Update(existing) + return err + }) + + return err +} + +func (ss *xormStore) Count(ctx context.Context, cmd *models.FindDashboardThumbnailCountCommand) (int64, error) { + err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + count, err := sess.Count(&models.DashboardThumbnail{}) + if err != nil { + return err + } + + cmd.Result = count + return nil + }) + + return cmd.Result, err +} + +func (ss *xormStore) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *models.FindDashboardsWithStaleThumbnailsCommand) ([]*models.DashboardWithStaleThumbnail, error) { + err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + sess.Table("dashboard") + sess.Join("LEFT", "dashboard_thumbnail", "dashboard.id = dashboard_thumbnail.dashboard_id AND dashboard_thumbnail.theme = ? AND dashboard_thumbnail.kind = ?", cmd.Theme, cmd.Kind) + sess.Where("dashboard.is_folder = ?", ss.db.GetDialect().BooleanStr(false)) + + query := "(dashboard.version != dashboard_thumbnail.dashboard_version " + + "OR dashboard_thumbnail.state = ? " + + "OR dashboard_thumbnail.id IS NULL" + args := []interface{}{models.ThumbnailStateStale} + + if cmd.IncludeThumbnailsWithEmptyDsUIDs { + query += " OR dashboard_thumbnail.ds_uids = ? OR dashboard_thumbnail.ds_uids IS NULL" + args = append(args, "") + } + sess.Where(query+")", args...) + + if !cmd.IncludeManuallyUploadedThumbnails { + sess.Where("(dashboard_thumbnail.id is not null AND dashboard_thumbnail.dashboard_version != ?) "+ + "OR dashboard_thumbnail.id is null "+ + "OR dashboard_thumbnail.state = ?", models.DashboardVersionForManualThumbnailUpload, models.ThumbnailStateStale) + } + + sess.Where("(dashboard_thumbnail.id IS NULL OR dashboard_thumbnail.state != ?)", models.ThumbnailStateLocked) + + sess.Cols("dashboard.id", + "dashboard.uid", + "dashboard.org_id", + "dashboard.version", + "dashboard.slug") + + var result = make([]*models.DashboardWithStaleThumbnail, 0) + err := sess.Find(&result) + + if err != nil { + return err + } + cmd.Result = result + return err + }) + + return cmd.Result, err +} + +func findThumbnailByMeta(sess *sqlstore.DBSession, meta models.DashboardThumbnailMeta) (*models.DashboardThumbnail, error) { + result := &models.DashboardThumbnail{} + + sess.Table("dashboard_thumbnail") + sess.Join("INNER", "dashboard", "dashboard.id = dashboard_thumbnail.dashboard_id") + sess.Where("dashboard.uid = ? AND dashboard.org_id = ? AND panel_id = ? AND kind = ? AND theme = ?", meta.DashboardUID, meta.OrgId, meta.PanelID, meta.Kind, meta.Theme) + sess.Cols("dashboard_thumbnail.id", + "dashboard_thumbnail.dashboard_id", + "dashboard_thumbnail.panel_id", + "dashboard_thumbnail.image", + "dashboard_thumbnail.dashboard_version", + "dashboard_thumbnail.state", + "dashboard_thumbnail.kind", + "dashboard_thumbnail.ds_uids", + "dashboard_thumbnail.mime_type", + "dashboard_thumbnail.theme", + "dashboard_thumbnail.updated") + exists, err := sess.Get(result) + + if !exists { + return nil, dashboards.ErrDashboardThumbnailNotFound + } + + if err != nil { + return nil, err + } + + return result, nil +} + +type dash struct { + Id int64 +} + +func findDashboardIdByThumbMeta(sess *sqlstore.DBSession, meta models.DashboardThumbnailMeta) (*dash, error) { + result := &dash{} + + sess.Table("dashboard").Where("dashboard.uid = ? AND dashboard.org_id = ?", meta.DashboardUID, meta.OrgId).Cols("id") + exists, err := sess.Get(result) + + if err != nil { + return nil, err + } + if !exists { + return nil, dashboards.ErrDashboardNotFound + } + + return result, err +} diff --git a/pkg/services/dashboard_thumbs/dashboardthumbsimpl/store_test.go b/pkg/services/dashboard_thumbs/dashboardthumbsimpl/store_test.go index 126fbc20bad..b17d777aca0 100644 --- a/pkg/services/dashboard_thumbs/dashboardthumbsimpl/store_test.go +++ b/pkg/services/dashboard_thumbs/dashboardthumbsimpl/store_test.go @@ -1 +1,400 @@ package dashboardthumbsimpl + +import ( + "context" + "testing" + "time" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/util" + "github.com/stretchr/testify/require" +) + +var theme = models.ThemeDark +var kind = models.ThumbnailKindDefault + +func TestIntegrationSqlStorage(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + var sqlStore *sqlstore.SQLStore + var store store + var savedFolder *models.Dashboard + + setup := func() { + sqlStore = sqlstore.InitTestDB(t) + store = &xormStore{db: sqlStore} + savedFolder = insertTestDashboard(t, sqlStore, "1 test dash folder", 1, 0, true, "prod", "webapp") + } + + t.Run("Should insert dashboard in default state", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) + thumb := getThumbnail(t, store, dash.Uid, dash.OrgId) + + require.Positive(t, thumb.Id) + require.Equal(t, models.ThumbnailStateDefault, thumb.State) + require.Equal(t, dash.Version, thumb.DashboardVersion) + }) + + t.Run("Should be able to update the thumbnail", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) + thumb := getThumbnail(t, store, dash.Uid, dash.OrgId) + + insertedThumbnailId := thumb.Id + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version+1) + + updatedThumb := getThumbnail(t, store, dash.Uid, dash.OrgId) + require.Equal(t, insertedThumbnailId, updatedThumb.Id) + require.Equal(t, dash.Version+1, updatedThumb.DashboardVersion) + }) + + t.Run("Should return empty array if all dashboards have thumbnails", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) + + cmd := models.FindDashboardsWithStaleThumbnailsCommand{ + Kind: kind, + Theme: theme, + } + res, err := store.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) + require.NoError(t, err) + require.Len(t, res, 0) + }) + + t.Run("Should return dashboards with thumbnails with empty ds_uids array", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) + + cmd := models.FindDashboardsWithStaleThumbnailsCommand{ + Kind: kind, + IncludeThumbnailsWithEmptyDsUIDs: true, + Theme: theme, + } + res, err := store.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) + require.NoError(t, err) + require.Len(t, res, 1) + require.Equal(t, dash.Id, res[0].Id) + }) + + t.Run("Should return dashboards with thumbnails marked as stale", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) + updateThumbnailState(t, store, dash.Uid, dash.OrgId, models.ThumbnailStateStale) + + cmd := models.FindDashboardsWithStaleThumbnailsCommand{ + Kind: kind, + Theme: theme, + } + res, err := store.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) + require.NoError(t, err) + require.Len(t, res, 1) + require.Equal(t, dash.Id, res[0].Id) + }) + + t.Run("Should not return dashboards with updated thumbnails that had been marked as stale", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) + updateThumbnailState(t, store, dash.Uid, dash.OrgId, models.ThumbnailStateStale) + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) + + cmd := models.FindDashboardsWithStaleThumbnailsCommand{ + Kind: kind, + Theme: theme, + } + res, err := store.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) + require.NoError(t, err) + require.Len(t, res, 0) + }) + + t.Run("Should find dashboards without thumbnails", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + + cmd := models.FindDashboardsWithStaleThumbnailsCommand{ + Kind: kind, + Theme: theme, + } + res, err := store.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) + require.NoError(t, err) + require.Len(t, res, 1) + require.Equal(t, dash.Id, res[0].Id) + }) + + t.Run("Should find dashboards with outdated thumbnails", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) + + updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ + "tags": "different-tag", + }) + + cmd := models.FindDashboardsWithStaleThumbnailsCommand{ + Kind: kind, + Theme: theme, + } + res, err := store.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) + require.NoError(t, err) + require.Len(t, res, 1) + require.Equal(t, dash.Id, res[0].Id) + }) + + t.Run("Should not return dashboards with locked thumbnails even if they are outdated", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) + updateThumbnailState(t, store, dash.Uid, dash.OrgId, models.ThumbnailStateLocked) + + updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ + "tags": "different-tag", + }) + + cmd := models.FindDashboardsWithStaleThumbnailsCommand{ + Kind: kind, + Theme: theme, + } + res, err := store.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) + require.NoError(t, err) + require.Len(t, res, 0) + }) + + t.Run("Should not return dashboards with manually uploaded thumbnails by default", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, models.DashboardVersionForManualThumbnailUpload) + + updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ + "tags": "different-tag", + }) + + cmd := models.FindDashboardsWithStaleThumbnailsCommand{ + Kind: kind, + Theme: theme, + } + res, err := store.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) + require.NoError(t, err) + require.Len(t, res, 0) + }) + + t.Run("Should return dashboards with manually uploaded thumbnails if requested", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, models.DashboardVersionForManualThumbnailUpload) + + updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ + "tags": "different-tag", + }) + + cmd := models.FindDashboardsWithStaleThumbnailsCommand{ + Kind: kind, + Theme: theme, + IncludeManuallyUploadedThumbnails: true, + } + res, err := store.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) + require.NoError(t, err) + require.Len(t, res, 1) + require.Equal(t, dash.Id, res[0].Id) + }) + + t.Run("Should count all dashboard thumbnails", func(t *testing.T) { + setup() + dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, 1) + dash2 := insertTestDashboard(t, sqlStore, "test dash 23", 2, savedFolder.Id, false, "prod", "webapp") + upsertTestDashboardThumbnail(t, store, dash2.Uid, dash2.OrgId, 1) + + updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ + "tags": "different-tag", + }) + + cmd := models.FindDashboardThumbnailCountCommand{} + res, err := store.Count(context.Background(), &cmd) + require.NoError(t, err) + require.Equal(t, res, int64(2)) + }) +} + +func getThumbnail(t *testing.T, store store, dashboardUID string, orgId int64) *models.DashboardThumbnail { + t.Helper() + cmd := models.GetDashboardThumbnailCommand{ + DashboardThumbnailMeta: models.DashboardThumbnailMeta{ + DashboardUID: dashboardUID, + OrgId: orgId, + PanelID: 0, + Kind: kind, + Theme: theme, + }, + } + + thumb, err := store.Get(context.Background(), &cmd) + require.NoError(t, err) + return thumb +} + +func upsertTestDashboardThumbnail(t *testing.T, store store, dashboardUID string, orgId int64, dashboardVersion int) *models.DashboardThumbnail { + t.Helper() + cmd := models.SaveDashboardThumbnailCommand{ + DashboardThumbnailMeta: models.DashboardThumbnailMeta{ + DashboardUID: dashboardUID, + OrgId: orgId, + PanelID: 0, + Kind: kind, + Theme: theme, + }, + DashboardVersion: dashboardVersion, + Image: make([]byte, 0), + MimeType: "image/png", + } + dash, err := store.Save(context.Background(), &cmd) + require.NoError(t, err) + require.NotNil(t, dash) + + return dash +} + +func updateThumbnailState(t *testing.T, store store, dashboardUID string, orgId int64, state models.ThumbnailState) { + t.Helper() + cmd := models.UpdateThumbnailStateCommand{ + DashboardThumbnailMeta: models.DashboardThumbnailMeta{ + DashboardUID: dashboardUID, + OrgId: orgId, + PanelID: 0, + Kind: kind, + Theme: theme, + }, + State: state, + } + err := store.UpdateState(context.Background(), &cmd) + require.NoError(t, err) +} + +func updateTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, dashModel *models.Dashboard, data map[string]interface{}) { + t.Helper() + + data["id"] = dashModel.Id + + parentVersion := dashModel.Version + + cmd := models.SaveDashboardCommand{ + OrgId: dashModel.OrgId, + Overwrite: true, + Dashboard: simplejson.NewFromAny(data), + } + var dash *models.Dashboard + err := sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { + var existing models.Dashboard + dash = cmd.GetDashboardModel() + dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing) + require.NoError(t, err) + require.True(t, dashWithIdExists) + + if dash.Version != existing.Version { + dash.SetVersion(existing.Version) + dash.Version = existing.Version + } + + dash.SetVersion(dash.Version + 1) + dash.Created = time.Now() + dash.Updated = time.Now() + dash.Id = dashModel.Id + dash.Uid = util.GenerateShortUID() + + _, err = sess.MustCols("folder_id").ID(dash.Id).Update(dash) + return err + }) + + require.Nil(t, err) + + err = sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { + dashVersion := &dashver.DashboardVersion{ + DashboardID: dash.Id, + ParentVersion: parentVersion, + RestoredFrom: cmd.RestoredFrom, + Version: dash.Version, + Created: time.Now(), + CreatedBy: dash.UpdatedBy, + Message: cmd.Message, + Data: dash.Data, + } + + if affectedRows, err := sess.Insert(dashVersion); err != nil { + return err + } else if affectedRows == 0 { + return dashboards.ErrDashboardNotFound + } + + return nil + }) + + require.NoError(t, err) +} + +func insertTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, title string, orgId int64, + folderId int64, isFolder bool, tags ...interface{}) *models.Dashboard { + t.Helper() + cmd := models.SaveDashboardCommand{ + OrgId: orgId, + FolderId: folderId, + IsFolder: isFolder, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": title, + "tags": tags, + }), + } + + var dash *models.Dashboard + err := sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { + dash = cmd.GetDashboardModel() + dash.SetVersion(1) + dash.Created = time.Now() + dash.Updated = time.Now() + dash.Uid = util.GenerateShortUID() + _, err := sess.Insert(dash) + return err + }) + + require.NoError(t, err) + require.NotNil(t, dash) + dash.Data.Set("id", dash.Id) + dash.Data.Set("uid", dash.Uid) + + err = sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { + dashVersion := &dashver.DashboardVersion{ + DashboardID: dash.Id, + ParentVersion: dash.Version, + RestoredFrom: cmd.RestoredFrom, + Version: dash.Version, + Created: time.Now(), + CreatedBy: dash.UpdatedBy, + Message: cmd.Message, + Data: dash.Data, + } + require.NoError(t, err) + + if affectedRows, err := sess.Insert(dashVersion); err != nil { + return err + } else if affectedRows == 0 { + return dashboards.ErrDashboardNotFound + } + + return nil + }) + require.NoError(t, err) + + return dash +} diff --git a/pkg/services/sqlstore/dashboard_thumbs.go b/pkg/services/sqlstore/dashboard_thumbs.go deleted file mode 100644 index a4db55bf684..00000000000 --- a/pkg/services/sqlstore/dashboard_thumbs.go +++ /dev/null @@ -1,211 +0,0 @@ -package sqlstore - -import ( - "context" - "encoding/json" - "errors" - "time" - - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/dashboards" -) - -func (ss *SQLStore) GetThumbnail(ctx context.Context, query *models.GetDashboardThumbnailCommand) (*models.DashboardThumbnail, error) { - err := ss.WithDbSession(ctx, func(sess *DBSession) error { - result, err := findThumbnailByMeta(sess, query.DashboardThumbnailMeta) - if err != nil { - return err - } - query.Result = result - return nil - }) - - return query.Result, err -} - -func marshalDatasourceUids(dsUids []string) (string, error) { - if dsUids == nil { - return "", nil - } - - b, err := json.Marshal(dsUids) - if err != nil { - return "", err - } - return string(b), nil -} - -func (ss *SQLStore) SaveThumbnail(ctx context.Context, cmd *models.SaveDashboardThumbnailCommand) (*models.DashboardThumbnail, error) { - err := ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { - existing, err := findThumbnailByMeta(sess, cmd.DashboardThumbnailMeta) - - if err != nil && !errors.Is(err, dashboards.ErrDashboardThumbnailNotFound) { - return err - } - - dsUids, err := marshalDatasourceUids(cmd.DatasourceUIDs) - if err != nil { - return err - } - - if existing != nil { - existing.Image = cmd.Image - existing.MimeType = cmd.MimeType - existing.Updated = time.Now() - existing.DashboardVersion = cmd.DashboardVersion - existing.DsUIDs = dsUids - existing.State = models.ThumbnailStateDefault - _, err = sess.ID(existing.Id).Update(existing) - cmd.Result = existing - return err - } - - thumb := &models.DashboardThumbnail{} - - dash, err := findDashboardIdByThumbMeta(sess, cmd.DashboardThumbnailMeta) - - if err != nil { - return err - } - - thumb.Updated = time.Now() - thumb.Theme = cmd.Theme - thumb.Kind = cmd.Kind - thumb.Image = cmd.Image - thumb.DsUIDs = dsUids - thumb.MimeType = cmd.MimeType - thumb.DashboardId = dash.Id - thumb.DashboardVersion = cmd.DashboardVersion - thumb.State = models.ThumbnailStateDefault - thumb.PanelId = cmd.PanelID - _, err = sess.Insert(thumb) - cmd.Result = thumb - return err - }) - - return cmd.Result, err -} - -func (ss *SQLStore) UpdateThumbnailState(ctx context.Context, cmd *models.UpdateThumbnailStateCommand) error { - err := ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error { - existing, err := findThumbnailByMeta(sess, cmd.DashboardThumbnailMeta) - - if err != nil { - return err - } - - existing.State = cmd.State - _, err = sess.ID(existing.Id).Update(existing) - return err - }) - - return err -} - -func (ss *SQLStore) FindThumbnailCount(ctx context.Context, cmd *models.FindDashboardThumbnailCountCommand) (int64, error) { - err := ss.WithDbSession(ctx, func(sess *DBSession) error { - count, err := sess.Count(&models.DashboardThumbnail{}) - if err != nil { - return err - } - - cmd.Result = count - return nil - }) - - return cmd.Result, err -} - -func (ss *SQLStore) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *models.FindDashboardsWithStaleThumbnailsCommand) ([]*models.DashboardWithStaleThumbnail, error) { - err := ss.WithDbSession(ctx, func(sess *DBSession) error { - sess.Table("dashboard") - sess.Join("LEFT", "dashboard_thumbnail", "dashboard.id = dashboard_thumbnail.dashboard_id AND dashboard_thumbnail.theme = ? AND dashboard_thumbnail.kind = ?", cmd.Theme, cmd.Kind) - sess.Where("dashboard.is_folder = ?", dialect.BooleanStr(false)) - - query := "(dashboard.version != dashboard_thumbnail.dashboard_version " + - "OR dashboard_thumbnail.state = ? " + - "OR dashboard_thumbnail.id IS NULL" - args := []interface{}{models.ThumbnailStateStale} - - if cmd.IncludeThumbnailsWithEmptyDsUIDs { - query += " OR dashboard_thumbnail.ds_uids = ? OR dashboard_thumbnail.ds_uids IS NULL" - args = append(args, "") - } - sess.Where(query+")", args...) - - if !cmd.IncludeManuallyUploadedThumbnails { - sess.Where("(dashboard_thumbnail.id is not null AND dashboard_thumbnail.dashboard_version != ?) "+ - "OR dashboard_thumbnail.id is null "+ - "OR dashboard_thumbnail.state = ?", models.DashboardVersionForManualThumbnailUpload, models.ThumbnailStateStale) - } - - sess.Where("(dashboard_thumbnail.id IS NULL OR dashboard_thumbnail.state != ?)", models.ThumbnailStateLocked) - - sess.Cols("dashboard.id", - "dashboard.uid", - "dashboard.org_id", - "dashboard.version", - "dashboard.slug") - - var result = make([]*models.DashboardWithStaleThumbnail, 0) - err := sess.Find(&result) - - if err != nil { - return err - } - cmd.Result = result - return err - }) - - return cmd.Result, err -} - -func findThumbnailByMeta(sess *DBSession, meta models.DashboardThumbnailMeta) (*models.DashboardThumbnail, error) { - result := &models.DashboardThumbnail{} - - sess.Table("dashboard_thumbnail") - sess.Join("INNER", "dashboard", "dashboard.id = dashboard_thumbnail.dashboard_id") - sess.Where("dashboard.uid = ? AND dashboard.org_id = ? AND panel_id = ? AND kind = ? AND theme = ?", meta.DashboardUID, meta.OrgId, meta.PanelID, meta.Kind, meta.Theme) - sess.Cols("dashboard_thumbnail.id", - "dashboard_thumbnail.dashboard_id", - "dashboard_thumbnail.panel_id", - "dashboard_thumbnail.image", - "dashboard_thumbnail.dashboard_version", - "dashboard_thumbnail.state", - "dashboard_thumbnail.kind", - "dashboard_thumbnail.ds_uids", - "dashboard_thumbnail.mime_type", - "dashboard_thumbnail.theme", - "dashboard_thumbnail.updated") - exists, err := sess.Get(result) - - if !exists { - return nil, dashboards.ErrDashboardThumbnailNotFound - } - - if err != nil { - return nil, err - } - - return result, nil -} - -type dash struct { - Id int64 -} - -func findDashboardIdByThumbMeta(sess *DBSession, meta models.DashboardThumbnailMeta) (*dash, error) { - result := &dash{} - - sess.Table("dashboard").Where("dashboard.uid = ? AND dashboard.org_id = ?", meta.DashboardUID, meta.OrgId).Cols("id") - exists, err := sess.Get(result) - - if err != nil { - return nil, err - } - if !exists { - return nil, dashboards.ErrDashboardNotFound - } - - return result, err -} diff --git a/pkg/services/sqlstore/dashboard_thumbs_test.go b/pkg/services/sqlstore/dashboard_thumbs_test.go deleted file mode 100644 index 7ce2ae68504..00000000000 --- a/pkg/services/sqlstore/dashboard_thumbs_test.go +++ /dev/null @@ -1,342 +0,0 @@ -package sqlstore - -import ( - "context" - "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/services/dashboards" - dashver "github.com/grafana/grafana/pkg/services/dashboardversion" - "github.com/grafana/grafana/pkg/util" -) - -var theme = models.ThemeDark -var kind = models.ThumbnailKindDefault - -func TestIntegrationSqlStorage(t *testing.T) { - if testing.Short() { - t.Skip("skipping integration test") - } - var sqlStore *SQLStore - var savedFolder *models.Dashboard - - setup := func() { - sqlStore = InitTestDB(t) - savedFolder = insertTestDashboard(t, sqlStore, "1 test dash folder", 1, 0, true, "prod", "webapp") - } - - t.Run("Should insert dashboard in default state", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version) - thumb := getThumbnail(t, sqlStore, dash.Uid, dash.OrgId) - - require.Positive(t, thumb.Id) - require.Equal(t, models.ThumbnailStateDefault, thumb.State) - require.Equal(t, dash.Version, thumb.DashboardVersion) - }) - - t.Run("Should be able to update the thumbnail", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version) - thumb := getThumbnail(t, sqlStore, dash.Uid, dash.OrgId) - - insertedThumbnailId := thumb.Id - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version+1) - - updatedThumb := getThumbnail(t, sqlStore, dash.Uid, dash.OrgId) - require.Equal(t, insertedThumbnailId, updatedThumb.Id) - require.Equal(t, dash.Version+1, updatedThumb.DashboardVersion) - }) - - t.Run("Should return empty array if all dashboards have thumbnails", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version) - - cmd := models.FindDashboardsWithStaleThumbnailsCommand{ - Kind: kind, - Theme: theme, - } - res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) - require.NoError(t, err) - require.Len(t, res, 0) - }) - - t.Run("Should return dashboards with thumbnails with empty ds_uids array", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version) - - cmd := models.FindDashboardsWithStaleThumbnailsCommand{ - Kind: kind, - IncludeThumbnailsWithEmptyDsUIDs: true, - Theme: theme, - } - res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) - require.NoError(t, err) - require.Len(t, res, 1) - require.Equal(t, dash.Id, res[0].Id) - }) - - t.Run("Should return dashboards with thumbnails marked as stale", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version) - updateThumbnailState(t, sqlStore, dash.Uid, dash.OrgId, models.ThumbnailStateStale) - - cmd := models.FindDashboardsWithStaleThumbnailsCommand{ - Kind: kind, - Theme: theme, - } - res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) - require.NoError(t, err) - require.Len(t, res, 1) - require.Equal(t, dash.Id, res[0].Id) - }) - - t.Run("Should not return dashboards with updated thumbnails that had been marked as stale", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version) - updateThumbnailState(t, sqlStore, dash.Uid, dash.OrgId, models.ThumbnailStateStale) - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version) - - cmd := models.FindDashboardsWithStaleThumbnailsCommand{ - Kind: kind, - Theme: theme, - } - res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) - require.NoError(t, err) - require.Len(t, res, 0) - }) - - t.Run("Should find dashboards without thumbnails", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - - cmd := models.FindDashboardsWithStaleThumbnailsCommand{ - Kind: kind, - Theme: theme, - } - res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) - require.NoError(t, err) - require.Len(t, res, 1) - require.Equal(t, dash.Id, res[0].Id) - }) - - t.Run("Should find dashboards with outdated thumbnails", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version) - - updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ - "tags": "different-tag", - }) - - cmd := models.FindDashboardsWithStaleThumbnailsCommand{ - Kind: kind, - Theme: theme, - } - res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) - require.NoError(t, err) - require.Len(t, res, 1) - require.Equal(t, dash.Id, res[0].Id) - }) - - t.Run("Should not return dashboards with locked thumbnails even if they are outdated", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version) - updateThumbnailState(t, sqlStore, dash.Uid, dash.OrgId, models.ThumbnailStateLocked) - - updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ - "tags": "different-tag", - }) - - cmd := models.FindDashboardsWithStaleThumbnailsCommand{ - Kind: kind, - Theme: theme, - } - res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) - require.NoError(t, err) - require.Len(t, res, 0) - }) - - t.Run("Should not return dashboards with manually uploaded thumbnails by default", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, models.DashboardVersionForManualThumbnailUpload) - - updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ - "tags": "different-tag", - }) - - cmd := models.FindDashboardsWithStaleThumbnailsCommand{ - Kind: kind, - Theme: theme, - } - res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) - require.NoError(t, err) - require.Len(t, res, 0) - }) - - t.Run("Should return dashboards with manually uploaded thumbnails if requested", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, models.DashboardVersionForManualThumbnailUpload) - - updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ - "tags": "different-tag", - }) - - cmd := models.FindDashboardsWithStaleThumbnailsCommand{ - Kind: kind, - Theme: theme, - IncludeManuallyUploadedThumbnails: true, - } - res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd) - require.NoError(t, err) - require.Len(t, res, 1) - require.Equal(t, dash.Id, res[0].Id) - }) - - t.Run("Should count all dashboard thumbnails", func(t *testing.T) { - setup() - dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, 1) - dash2 := insertTestDashboard(t, sqlStore, "test dash 23", 2, savedFolder.Id, false, "prod", "webapp") - upsertTestDashboardThumbnail(t, sqlStore, dash2.Uid, dash2.OrgId, 1) - - updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ - "tags": "different-tag", - }) - - cmd := models.FindDashboardThumbnailCountCommand{} - res, err := sqlStore.FindThumbnailCount(context.Background(), &cmd) - require.NoError(t, err) - require.Equal(t, res, int64(2)) - }) -} - -func getThumbnail(t *testing.T, sqlStore *SQLStore, dashboardUID string, orgId int64) *models.DashboardThumbnail { - t.Helper() - cmd := models.GetDashboardThumbnailCommand{ - DashboardThumbnailMeta: models.DashboardThumbnailMeta{ - DashboardUID: dashboardUID, - OrgId: orgId, - PanelID: 0, - Kind: kind, - Theme: theme, - }, - } - - thumb, err := sqlStore.GetThumbnail(context.Background(), &cmd) - require.NoError(t, err) - return thumb -} - -func upsertTestDashboardThumbnail(t *testing.T, sqlStore *SQLStore, dashboardUID string, orgId int64, dashboardVersion int) *models.DashboardThumbnail { - t.Helper() - cmd := models.SaveDashboardThumbnailCommand{ - DashboardThumbnailMeta: models.DashboardThumbnailMeta{ - DashboardUID: dashboardUID, - OrgId: orgId, - PanelID: 0, - Kind: kind, - Theme: theme, - }, - DashboardVersion: dashboardVersion, - Image: make([]byte, 0), - MimeType: "image/png", - } - dash, err := sqlStore.SaveThumbnail(context.Background(), &cmd) - require.NoError(t, err) - require.NotNil(t, dash) - - return dash -} - -func updateThumbnailState(t *testing.T, sqlStore *SQLStore, dashboardUID string, orgId int64, state models.ThumbnailState) { - t.Helper() - cmd := models.UpdateThumbnailStateCommand{ - DashboardThumbnailMeta: models.DashboardThumbnailMeta{ - DashboardUID: dashboardUID, - OrgId: orgId, - PanelID: 0, - Kind: kind, - Theme: theme, - }, - State: state, - } - err := sqlStore.UpdateThumbnailState(context.Background(), &cmd) - require.NoError(t, err) -} - -func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard, data map[string]interface{}) { - t.Helper() - - data["id"] = dashboard.Id - - parentVersion := dashboard.Version - - cmd := models.SaveDashboardCommand{ - OrgId: dashboard.OrgId, - Overwrite: true, - Dashboard: simplejson.NewFromAny(data), - } - var dash *models.Dashboard - err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { - var existing models.Dashboard - dash = cmd.GetDashboardModel() - dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing) - require.NoError(t, err) - require.True(t, dashWithIdExists) - - if dash.Version != existing.Version { - dash.SetVersion(existing.Version) - dash.Version = existing.Version - } - - dash.SetVersion(dash.Version + 1) - dash.Created = time.Now() - dash.Updated = time.Now() - dash.Id = dashboard.Id - dash.Uid = util.GenerateShortUID() - - _, err = sess.MustCols("folder_id").ID(dash.Id).Update(dash) - return err - }) - - require.Nil(t, err) - - err = sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { - dashVersion := &dashver.DashboardVersion{ - DashboardID: dash.Id, - ParentVersion: parentVersion, - RestoredFrom: cmd.RestoredFrom, - Version: dash.Version, - Created: time.Now(), - CreatedBy: dash.UpdatedBy, - Message: cmd.Message, - Data: dash.Data, - } - - if affectedRows, err := sess.Insert(dashVersion); err != nil { - return err - } else if affectedRows == 0 { - return dashboards.ErrDashboardNotFound - } - - return nil - }) - - require.NoError(t, err) -} diff --git a/pkg/services/thumbs/repo.go b/pkg/services/thumbs/repo.go index 1676783c703..8011abf414f 100644 --- a/pkg/services/thumbs/repo.go +++ b/pkg/services/thumbs/repo.go @@ -9,13 +9,13 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" + dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs" "github.com/grafana/grafana/pkg/services/searchV2" - "github.com/grafana/grafana/pkg/services/sqlstore" ) -func newThumbnailRepo(store *sqlstore.SQLStore, search searchV2.SearchService) thumbnailRepo { +func newThumbnailRepo(thumbsService dashboardthumbs.Service, search searchV2.SearchService) thumbnailRepo { repo := &sqlThumbnailRepository{ - store: store, + store: thumbsService, search: search, log: log.New("thumbnails_repo"), } @@ -23,7 +23,7 @@ func newThumbnailRepo(store *sqlstore.SQLStore, search searchV2.SearchService) t } type sqlThumbnailRepository struct { - store *sqlstore.SQLStore + store dashboardthumbs.Service search searchV2.SearchService log log.Logger } diff --git a/pkg/services/thumbs/service.go b/pkg/services/thumbs/service.go index 4ef988b7657..56741c5baed 100644 --- a/pkg/services/thumbs/service.go +++ b/pkg/services/thumbs/service.go @@ -8,6 +8,7 @@ import ( "net/http" "time" + dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs" "github.com/grafana/grafana/pkg/services/datasources/permissions" "github.com/grafana/grafana/pkg/services/searchV2" "github.com/segmentio/encoding/json" @@ -76,14 +77,14 @@ type crawlerScheduleOptions struct { 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, searchService searchV2.SearchService, + dashboardService dashboards.DashboardService, dashboardThumbsService dashboardthumbs.Service, searchService searchV2.SearchService, dsPermissionsService permissions.DatasourcePermissionsService, licensing models.Licensing) Service { if !features.IsEnabled(featuremgmt.FlagDashboardPreviews) { return &dummyService{} } logger := log.New("previews_service") - thumbnailRepo := newThumbnailRepo(store, searchService) + thumbnailRepo := newThumbnailRepo(dashboardThumbsService, searchService) canRunCrawler := true