StoreSplit: move dashboard thumbs into thumbs service (#55800)

* move dashboard thumbs into thumbs service

* rename some variables
This commit is contained in:
ying-jeanne
2022-09-27 08:46:03 -04:00
committed by GitHub
parent 169df2fe90
commit b96a3832d0
14 changed files with 290 additions and 305 deletions
+2 -3
View File
@@ -45,7 +45,6 @@ import (
"github.com/grafana/grafana/pkg/services/comments" "github.com/grafana/grafana/pkg/services/comments"
"github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/services/correlations" "github.com/grafana/grafana/pkg/services/correlations"
dashboardThumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboardsnapshots" "github.com/grafana/grafana/pkg/services/dashboardsnapshots"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion" dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
@@ -193,7 +192,7 @@ type HTTPServer struct {
userService user.Service userService user.Service
tempUserService tempUser.Service tempUserService tempUser.Service
dashboardThumbsService dashboardThumbs.Service dashboardThumbsService thumbs.DashboardThumbService
loginAttemptService loginAttempt.Service loginAttemptService loginAttempt.Service
orgService org.Service orgService org.Service
teamService team.Service teamService team.Service
@@ -240,7 +239,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
secretsPluginMigrator spm.SecretMigrationProvider, secretsStore secretsKV.SecretsKVStore, secretsPluginMigrator spm.SecretMigrationProvider, secretsStore secretsKV.SecretsKVStore,
publicDashboardsApi *publicdashboardsApi.Api, userService user.Service, tempUserService tempUser.Service, publicDashboardsApi *publicdashboardsApi.Api, userService user.Service, tempUserService tempUser.Service,
loginAttemptService loginAttempt.Service, orgService org.Service, teamService team.Service, loginAttemptService loginAttempt.Service, orgService org.Service, teamService team.Service,
accesscontrolService accesscontrol.Service, dashboardThumbsService dashboardThumbs.Service, navTreeService navtree.Service, accesscontrolService accesscontrol.Service, dashboardThumbsService thumbs.DashboardThumbService, navTreeService navtree.Service,
annotationRepo annotations.Repository, tagService tag.Service, searchv2HTTPService searchV2.SearchHTTPService, annotationRepo annotations.Repository, tagService tag.Service, searchv2HTTPService searchV2.SearchHTTPService,
userAuthService userauth.Service, userAuthService userauth.Service,
) (*HTTPServer, error) { ) (*HTTPServer, error) {
+2 -2
View File
@@ -54,7 +54,6 @@ import (
"github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy" "github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
"github.com/grafana/grafana/pkg/services/correlations" "github.com/grafana/grafana/pkg/services/correlations"
"github.com/grafana/grafana/pkg/services/dashboard_thumbs/dashboardthumbsimpl"
"github.com/grafana/grafana/pkg/services/dashboardimport" "github.com/grafana/grafana/pkg/services/dashboardimport"
dashboardimportservice "github.com/grafana/grafana/pkg/services/dashboardimport/service" dashboardimportservice "github.com/grafana/grafana/pkg/services/dashboardimport/service"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
@@ -132,6 +131,7 @@ import (
tempuser "github.com/grafana/grafana/pkg/services/temp_user" tempuser "github.com/grafana/grafana/pkg/services/temp_user"
"github.com/grafana/grafana/pkg/services/temp_user/tempuserimpl" "github.com/grafana/grafana/pkg/services/temp_user/tempuserimpl"
"github.com/grafana/grafana/pkg/services/thumbs" "github.com/grafana/grafana/pkg/services/thumbs"
"github.com/grafana/grafana/pkg/services/thumbs/dashboardthumbsimpl"
"github.com/grafana/grafana/pkg/services/updatechecker" "github.com/grafana/grafana/pkg/services/updatechecker"
"github.com/grafana/grafana/pkg/services/user/userimpl" "github.com/grafana/grafana/pkg/services/user/userimpl"
"github.com/grafana/grafana/pkg/services/userauth/userauthimpl" "github.com/grafana/grafana/pkg/services/userauth/userauthimpl"
@@ -177,6 +177,7 @@ var wireBasicSet = wire.NewSet(
hooks.ProvideService, hooks.ProvideService,
kvstore.ProvideService, kvstore.ProvideService,
localcache.ProvideService, localcache.ProvideService,
dashboardthumbsimpl.ProvideService,
updatechecker.ProvideGrafanaService, updatechecker.ProvideGrafanaService,
updatechecker.ProvidePluginsService, updatechecker.ProvidePluginsService,
uss.ProvideService, uss.ProvideService,
@@ -345,7 +346,6 @@ var wireBasicSet = wire.NewSet(
grpcserver.ProvideHealthService, grpcserver.ProvideHealthService,
teamimpl.ProvideService, teamimpl.ProvideService,
tempuserimpl.ProvideService, tempuserimpl.ProvideService,
dashboardthumbsimpl.ProvideService,
loginattemptimpl.ProvideService, loginattemptimpl.ProvideService,
userauthimpl.ProvideService, userauthimpl.ProvideService,
secretsMigrations.ProvideDataSourceMigrationService, secretsMigrations.ProvideDataSourceMigrationService,
@@ -1,45 +0,0 @@
package dashboardthumbsimpl
import (
"context"
dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs"
"github.com/grafana/grafana/pkg/services/sqlstore/db"
)
type Service struct {
store store
}
func ProvideService(
db db.DB,
) dashboardthumbs.Service {
return &Service{
store: &xormStore{db: db},
}
}
func (s *Service) GetThumbnail(ctx context.Context, query *dashboardthumbs.GetDashboardThumbnailCommand) (*dashboardthumbs.DashboardThumbnail, error) {
dt, err := s.store.Get(ctx, query)
return dt, err
}
func (s *Service) SaveThumbnail(ctx context.Context, cmd *dashboardthumbs.SaveDashboardThumbnailCommand) (*dashboardthumbs.DashboardThumbnail, error) {
dt, err := s.store.Save(ctx, cmd)
return dt, err
}
func (s *Service) UpdateThumbnailState(ctx context.Context, cmd *dashboardthumbs.UpdateThumbnailStateCommand) error {
err := s.store.UpdateState(ctx, cmd)
return err
}
func (s *Service) FindThumbnailCount(ctx context.Context, cmd *dashboardthumbs.FindDashboardThumbnailCountCommand) (int64, error) {
n, err := s.store.Count(ctx, cmd)
return n, err
}
func (s *Service) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand) ([]*dashboardthumbs.DashboardWithStaleThumbnail, error) {
thumbs, err := s.store.FindDashboardsWithStaleThumbnails(ctx, cmd)
return thumbs, err
}
@@ -1,15 +0,0 @@
package dashboardthumbsimpl
import (
"context"
dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs"
)
type store interface {
Get(ctx context.Context, query *dashboardthumbs.GetDashboardThumbnailCommand) (*dashboardthumbs.DashboardThumbnail, error)
Save(ctx context.Context, cmd *dashboardthumbs.SaveDashboardThumbnailCommand) (*dashboardthumbs.DashboardThumbnail, error)
UpdateState(ctx context.Context, cmd *dashboardthumbs.UpdateThumbnailStateCommand) error
Count(ctx context.Context, cmd *dashboardthumbs.FindDashboardThumbnailCountCommand) (int64, error)
FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand) ([]*dashboardthumbs.DashboardWithStaleThumbnail, error)
}
-148
View File
@@ -1,148 +0,0 @@
package dashboardthumbs
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/grafana/grafana/pkg/models"
)
type ThumbnailKind string
type ThumbnailState string
type CrawlerMode string
const (
// ThumbnailKindDefault is a small 320x240 preview
ThumbnailKindDefault ThumbnailKind = "thumb"
// unsupported for now
// - ThumbnailKindLarge ThumbnailKind = "large"
// - ThumbnailKindTall ThumbnailKind = "tall"
)
const (
// ThumbnailStateDefault is the initial state for all thumbnails. Thumbnails in the "default" state will be considered stale,
// and thus refreshed by the crawler, if the dashboard version from the time of taking the thumbnail is different from the current dashboard version
ThumbnailStateDefault ThumbnailState = "default"
// ThumbnailStateStale is a manually assigned state. Thumbnails in the "stale" state will be refreshed on the next crawler run
ThumbnailStateStale ThumbnailState = "stale"
// ThumbnailStateLocked is a manually assigned state. Thumbnails in the "locked" state will not be refreshed by the crawler as long as they remain in the "locked" state.
ThumbnailStateLocked ThumbnailState = "locked"
)
func (s ThumbnailState) IsValid() bool {
return s == ThumbnailStateDefault || s == ThumbnailStateStale || s == ThumbnailStateLocked
}
func (s *ThumbnailState) UnmarshalJSON(data []byte) error {
var str string
err := json.Unmarshal(data, &str)
if err != nil {
return err
}
*s = ThumbnailState(str)
if !s.IsValid() {
if (*s) != "" {
return fmt.Errorf("JSON validation error: invalid thumbnail state value: %s", *s)
}
*s = ThumbnailStateDefault
}
return nil
}
// IsKnownThumbnailKind checks if the value is supported
func (p ThumbnailKind) IsKnownThumbnailKind() bool {
switch p {
case
ThumbnailKindDefault:
return true
}
return false
}
func ParseThumbnailKind(str string) (ThumbnailKind, error) {
switch str {
case string(ThumbnailKindDefault):
return ThumbnailKindDefault, nil
}
return ThumbnailKindDefault, errors.New("unknown thumbnail kind " + str)
}
// A DashboardThumbnail includes all metadata for a dashboard thumbnail
type DashboardThumbnail struct {
Id int64 `json:"id"`
DashboardId int64 `json:"dashboardId"`
DashboardVersion int `json:"dashboardVersion"`
State ThumbnailState `json:"state"`
PanelId int64 `json:"panelId,omitempty"`
Kind ThumbnailKind `json:"kind"`
Theme models.Theme `json:"theme"`
Image []byte `json:"image"`
MimeType string `json:"mimeType"`
Updated time.Time `json:"updated"`
DsUIDs string `json:"-" xorm:"ds_uids"`
}
//
// Commands
//
// DashboardThumbnailMeta uniquely identifies a thumbnail; a natural key
type DashboardThumbnailMeta struct {
DashboardUID string
OrgId int64
PanelID int64
Kind ThumbnailKind
Theme models.Theme
}
type GetDashboardThumbnailCommand struct {
DashboardThumbnailMeta
Result *DashboardThumbnail
}
const DashboardVersionForManualThumbnailUpload = -1
type DashboardWithStaleThumbnail struct {
Id int64
OrgId int64
Uid string
Version int
Slug string
}
type FindDashboardThumbnailCountCommand struct {
Result int64
}
type FindDashboardsWithStaleThumbnailsCommand struct {
IncludeManuallyUploadedThumbnails bool
IncludeThumbnailsWithEmptyDsUIDs bool
Theme models.Theme
Kind ThumbnailKind
Result []*DashboardWithStaleThumbnail
}
type SaveDashboardThumbnailCommand struct {
DashboardThumbnailMeta
DashboardVersion int
Image []byte
MimeType string
DatasourceUIDs []string
Result *DashboardThumbnail
}
type UpdateThumbnailStateCommand struct {
State ThumbnailState
DashboardThumbnailMeta
}
+6 -7
View File
@@ -15,7 +15,6 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs"
"github.com/grafana/grafana/pkg/services/live" "github.com/grafana/grafana/pkg/services/live"
"github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/services/rendering"
) )
@@ -29,12 +28,12 @@ type simpleCrawler struct {
glive *live.GrafanaLive glive *live.GrafanaLive
thumbnailRepo thumbnailRepo thumbnailRepo thumbnailRepo
mode CrawlerMode mode CrawlerMode
thumbnailKind dashboardthumbs.ThumbnailKind thumbnailKind ThumbnailKind
auth CrawlerAuth auth CrawlerAuth
opts rendering.Opts opts rendering.Opts
status crawlStatus status crawlStatus
statusMutex sync.RWMutex statusMutex sync.RWMutex
queue []*dashboardthumbs.DashboardWithStaleThumbnail queue []*DashboardWithStaleThumbnail
queueMutex sync.Mutex queueMutex sync.Mutex
log log.Logger log log.Logger
renderingSessionByOrgId map[int64]rendering.Session renderingSessionByOrgId map[int64]rendering.Session
@@ -65,7 +64,7 @@ func newSimpleCrawler(renderService rendering.Service, gl *live.GrafanaLive, rep
return c return c
} }
func (r *simpleCrawler) next(ctx context.Context) (*dashboardthumbs.DashboardWithStaleThumbnail, rendering.Session, rendering.AuthOpts, error) { func (r *simpleCrawler) next(ctx context.Context) (*DashboardWithStaleThumbnail, rendering.Session, rendering.AuthOpts, error) {
r.queueMutex.Lock() r.queueMutex.Lock()
defer r.queueMutex.Unlock() defer r.queueMutex.Unlock()
@@ -117,13 +116,13 @@ func (r *simpleCrawler) broadcastStatus() {
} }
} }
type byOrgId []*dashboardthumbs.DashboardWithStaleThumbnail type byOrgId []*DashboardWithStaleThumbnail
func (d byOrgId) Len() int { return len(d) } func (d byOrgId) Len() int { return len(d) }
func (d byOrgId) Less(i, j int) bool { return d[i].OrgId > d[j].OrgId } func (d byOrgId) Less(i, j int) bool { return d[i].OrgId > d[j].OrgId }
func (d byOrgId) Swap(i, j int) { d[i], d[j] = d[j], d[i] } func (d byOrgId) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (r *simpleCrawler) Run(ctx context.Context, auth CrawlerAuth, mode CrawlerMode, theme models.Theme, thumbnailKind dashboardthumbs.ThumbnailKind) error { func (r *simpleCrawler) Run(ctx context.Context, auth CrawlerAuth, mode CrawlerMode, theme models.Theme, thumbnailKind ThumbnailKind) error {
res, err := r.renderService.HasCapability(ctx, rendering.ScalingDownImages) res, err := r.renderService.HasCapability(ctx, rendering.ScalingDownImages)
if err != nil { if err != nil {
return err return err
@@ -326,7 +325,7 @@ func (r *simpleCrawler) walk(ctx context.Context, id int) {
} }
}() }()
thumbnailId, err := r.thumbnailRepo.saveFromFile(ctx, res.FilePath, dashboardthumbs.DashboardThumbnailMeta{ thumbnailId, err := r.thumbnailRepo.saveFromFile(ctx, res.FilePath, DashboardThumbnailMeta{
DashboardUID: item.Uid, DashboardUID: item.Uid,
OrgId: item.OrgId, OrgId: item.OrgId,
Theme: r.opts.Theme, Theme: r.opts.Theme,
@@ -1,10 +1,10 @@
package dashboardthumbs package thumbs
import ( import (
"context" "context"
) )
type Service interface { type DashboardThumbService interface {
GetThumbnail(ctx context.Context, query *GetDashboardThumbnailCommand) (*DashboardThumbnail, error) GetThumbnail(ctx context.Context, query *GetDashboardThumbnailCommand) (*DashboardThumbnail, error)
SaveThumbnail(ctx context.Context, cmd *SaveDashboardThumbnailCommand) (*DashboardThumbnail, error) SaveThumbnail(ctx context.Context, cmd *SaveDashboardThumbnailCommand) (*DashboardThumbnail, error)
UpdateThumbnailState(ctx context.Context, cmd *UpdateThumbnailStateCommand) error UpdateThumbnailState(ctx context.Context, cmd *UpdateThumbnailStateCommand) error
@@ -0,0 +1,43 @@
package dashboardthumbsimpl
import (
"context"
"github.com/grafana/grafana/pkg/services/sqlstore/db"
"github.com/grafana/grafana/pkg/services/thumbs"
)
type Service struct {
store store
}
func ProvideService(db db.DB) thumbs.DashboardThumbService {
return &Service{
store: &xormStore{db: db},
}
}
func (s *Service) GetThumbnail(ctx context.Context, query *thumbs.GetDashboardThumbnailCommand) (*thumbs.DashboardThumbnail, error) {
dt, err := s.store.Get(ctx, query)
return dt, err
}
func (s *Service) SaveThumbnail(ctx context.Context, cmd *thumbs.SaveDashboardThumbnailCommand) (*thumbs.DashboardThumbnail, error) {
dt, err := s.store.Save(ctx, cmd)
return dt, err
}
func (s *Service) UpdateThumbnailState(ctx context.Context, cmd *thumbs.UpdateThumbnailStateCommand) error {
err := s.store.UpdateState(ctx, cmd)
return err
}
func (s *Service) FindThumbnailCount(ctx context.Context, cmd *thumbs.FindDashboardThumbnailCountCommand) (int64, error) {
n, err := s.store.Count(ctx, cmd)
return n, err
}
func (s *Service) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *thumbs.FindDashboardsWithStaleThumbnailsCommand) ([]*thumbs.DashboardWithStaleThumbnail, error) {
thumbs, err := s.store.FindDashboardsWithStaleThumbnails(ctx, cmd)
return thumbs, err
}
@@ -0,0 +1,15 @@
package dashboardthumbsimpl
import (
"context"
"github.com/grafana/grafana/pkg/services/thumbs"
)
type store interface {
Get(ctx context.Context, query *thumbs.GetDashboardThumbnailCommand) (*thumbs.DashboardThumbnail, error)
Save(ctx context.Context, cmd *thumbs.SaveDashboardThumbnailCommand) (*thumbs.DashboardThumbnail, error)
UpdateState(ctx context.Context, cmd *thumbs.UpdateThumbnailStateCommand) error
Count(ctx context.Context, cmd *thumbs.FindDashboardThumbnailCountCommand) (int64, error)
FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *thumbs.FindDashboardsWithStaleThumbnailsCommand) ([]*thumbs.DashboardWithStaleThumbnail, error)
}
@@ -7,16 +7,16 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion" dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/thumbs"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
var theme = models.ThemeDark var theme = models.ThemeDark
var kind = dashboardthumbs.ThumbnailKindDefault var kind = thumbs.ThumbnailKindDefault
func TestIntegrationSqlStorage(t *testing.T) { func TestIntegrationSqlStorage(t *testing.T) {
if testing.Short() { if testing.Short() {
@@ -39,7 +39,7 @@ func TestIntegrationSqlStorage(t *testing.T) {
thumb := getThumbnail(t, store, dash.Uid, dash.OrgId) thumb := getThumbnail(t, store, dash.Uid, dash.OrgId)
require.Positive(t, thumb.Id) require.Positive(t, thumb.Id)
require.Equal(t, dashboardthumbs.ThumbnailStateDefault, thumb.State) require.Equal(t, thumbs.ThumbnailStateDefault, thumb.State)
require.Equal(t, dash.Version, thumb.DashboardVersion) require.Equal(t, dash.Version, thumb.DashboardVersion)
}) })
@@ -63,7 +63,7 @@ func TestIntegrationSqlStorage(t *testing.T) {
upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version)
cmd := dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ cmd := thumbs.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind, Kind: kind,
Theme: theme, Theme: theme,
} }
@@ -78,7 +78,7 @@ func TestIntegrationSqlStorage(t *testing.T) {
upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version)
cmd := dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ cmd := thumbs.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind, Kind: kind,
IncludeThumbnailsWithEmptyDsUIDs: true, IncludeThumbnailsWithEmptyDsUIDs: true,
Theme: theme, Theme: theme,
@@ -93,9 +93,9 @@ func TestIntegrationSqlStorage(t *testing.T) {
setup() setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version)
updateThumbnailState(t, store, dash.Uid, dash.OrgId, dashboardthumbs.ThumbnailStateStale) updateThumbnailState(t, store, dash.Uid, dash.OrgId, thumbs.ThumbnailStateStale)
cmd := dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ cmd := thumbs.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind, Kind: kind,
Theme: theme, Theme: theme,
} }
@@ -109,10 +109,10 @@ func TestIntegrationSqlStorage(t *testing.T) {
setup() setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version)
updateThumbnailState(t, store, dash.Uid, dash.OrgId, dashboardthumbs.ThumbnailStateStale) updateThumbnailState(t, store, dash.Uid, dash.OrgId, thumbs.ThumbnailStateStale)
upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version)
cmd := dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ cmd := thumbs.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind, Kind: kind,
Theme: theme, Theme: theme,
} }
@@ -125,7 +125,7 @@ func TestIntegrationSqlStorage(t *testing.T) {
setup() setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
cmd := dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ cmd := thumbs.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind, Kind: kind,
Theme: theme, Theme: theme,
} }
@@ -144,7 +144,7 @@ func TestIntegrationSqlStorage(t *testing.T) {
"tags": "different-tag", "tags": "different-tag",
}) })
cmd := dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ cmd := thumbs.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind, Kind: kind,
Theme: theme, Theme: theme,
} }
@@ -158,13 +158,13 @@ func TestIntegrationSqlStorage(t *testing.T) {
setup() setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version) upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dash.Version)
updateThumbnailState(t, store, dash.Uid, dash.OrgId, dashboardthumbs.ThumbnailStateLocked) updateThumbnailState(t, store, dash.Uid, dash.OrgId, thumbs.ThumbnailStateLocked)
updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ updateTestDashboard(t, sqlStore, dash, map[string]interface{}{
"tags": "different-tag", "tags": "different-tag",
}) })
cmd := dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ cmd := thumbs.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind, Kind: kind,
Theme: theme, Theme: theme,
} }
@@ -176,13 +176,13 @@ func TestIntegrationSqlStorage(t *testing.T) {
t.Run("Should not return dashboards with manually uploaded thumbnails by default", func(t *testing.T) { t.Run("Should not return dashboards with manually uploaded thumbnails by default", func(t *testing.T) {
setup() setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dashboardthumbs.DashboardVersionForManualThumbnailUpload) upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, thumbs.DashboardVersionForManualThumbnailUpload)
updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ updateTestDashboard(t, sqlStore, dash, map[string]interface{}{
"tags": "different-tag", "tags": "different-tag",
}) })
cmd := dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ cmd := thumbs.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind, Kind: kind,
Theme: theme, Theme: theme,
} }
@@ -194,13 +194,13 @@ func TestIntegrationSqlStorage(t *testing.T) {
t.Run("Should return dashboards with manually uploaded thumbnails if requested", func(t *testing.T) { t.Run("Should return dashboards with manually uploaded thumbnails if requested", func(t *testing.T) {
setup() setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp") dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, dashboardthumbs.DashboardVersionForManualThumbnailUpload) upsertTestDashboardThumbnail(t, store, dash.Uid, dash.OrgId, thumbs.DashboardVersionForManualThumbnailUpload)
updateTestDashboard(t, sqlStore, dash, map[string]interface{}{ updateTestDashboard(t, sqlStore, dash, map[string]interface{}{
"tags": "different-tag", "tags": "different-tag",
}) })
cmd := dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ cmd := thumbs.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind, Kind: kind,
Theme: theme, Theme: theme,
IncludeManuallyUploadedThumbnails: true, IncludeManuallyUploadedThumbnails: true,
@@ -222,17 +222,17 @@ func TestIntegrationSqlStorage(t *testing.T) {
"tags": "different-tag", "tags": "different-tag",
}) })
cmd := dashboardthumbs.FindDashboardThumbnailCountCommand{} cmd := thumbs.FindDashboardThumbnailCountCommand{}
res, err := store.Count(context.Background(), &cmd) res, err := store.Count(context.Background(), &cmd)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, res, int64(2)) require.Equal(t, res, int64(2))
}) })
} }
func getThumbnail(t *testing.T, store store, dashboardUID string, orgId int64) *dashboardthumbs.DashboardThumbnail { func getThumbnail(t *testing.T, store store, dashboardUID string, orgId int64) *thumbs.DashboardThumbnail {
t.Helper() t.Helper()
cmd := dashboardthumbs.GetDashboardThumbnailCommand{ cmd := thumbs.GetDashboardThumbnailCommand{
DashboardThumbnailMeta: dashboardthumbs.DashboardThumbnailMeta{ DashboardThumbnailMeta: thumbs.DashboardThumbnailMeta{
DashboardUID: dashboardUID, DashboardUID: dashboardUID,
OrgId: orgId, OrgId: orgId,
PanelID: 0, PanelID: 0,
@@ -246,10 +246,10 @@ func getThumbnail(t *testing.T, store store, dashboardUID string, orgId int64) *
return thumb return thumb
} }
func upsertTestDashboardThumbnail(t *testing.T, store store, dashboardUID string, orgId int64, dashboardVersion int) *dashboardthumbs.DashboardThumbnail { func upsertTestDashboardThumbnail(t *testing.T, store store, dashboardUID string, orgId int64, dashboardVersion int) *thumbs.DashboardThumbnail {
t.Helper() t.Helper()
cmd := dashboardthumbs.SaveDashboardThumbnailCommand{ cmd := thumbs.SaveDashboardThumbnailCommand{
DashboardThumbnailMeta: dashboardthumbs.DashboardThumbnailMeta{ DashboardThumbnailMeta: thumbs.DashboardThumbnailMeta{
DashboardUID: dashboardUID, DashboardUID: dashboardUID,
OrgId: orgId, OrgId: orgId,
PanelID: 0, PanelID: 0,
@@ -267,10 +267,10 @@ func upsertTestDashboardThumbnail(t *testing.T, store store, dashboardUID string
return dash return dash
} }
func updateThumbnailState(t *testing.T, store store, dashboardUID string, orgId int64, state dashboardthumbs.ThumbnailState) { func updateThumbnailState(t *testing.T, store store, dashboardUID string, orgId int64, state thumbs.ThumbnailState) {
t.Helper() t.Helper()
cmd := dashboardthumbs.UpdateThumbnailStateCommand{ cmd := thumbs.UpdateThumbnailStateCommand{
DashboardThumbnailMeta: dashboardthumbs.DashboardThumbnailMeta{ DashboardThumbnailMeta: thumbs.DashboardThumbnailMeta{
DashboardUID: dashboardUID, DashboardUID: dashboardUID,
OrgId: orgId, OrgId: orgId,
PanelID: 0, PanelID: 0,
@@ -6,17 +6,17 @@ import (
"errors" "errors"
"time" "time"
dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/db" "github.com/grafana/grafana/pkg/services/sqlstore/db"
"github.com/grafana/grafana/pkg/services/thumbs"
) )
type xormStore struct { type xormStore struct {
db db.DB db db.DB
} }
func (ss *xormStore) Get(ctx context.Context, query *dashboardthumbs.GetDashboardThumbnailCommand) (*dashboardthumbs.DashboardThumbnail, error) { func (ss *xormStore) Get(ctx context.Context, query *thumbs.GetDashboardThumbnailCommand) (*thumbs.DashboardThumbnail, error) {
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
result, err := findThumbnailByMeta(sess, query.DashboardThumbnailMeta) result, err := findThumbnailByMeta(sess, query.DashboardThumbnailMeta)
if err != nil { if err != nil {
@@ -41,7 +41,7 @@ func marshalDatasourceUids(dsUids []string) (string, error) {
return string(b), nil return string(b), nil
} }
func (ss *xormStore) Save(ctx context.Context, cmd *dashboardthumbs.SaveDashboardThumbnailCommand) (*dashboardthumbs.DashboardThumbnail, error) { func (ss *xormStore) Save(ctx context.Context, cmd *thumbs.SaveDashboardThumbnailCommand) (*thumbs.DashboardThumbnail, error) {
err := ss.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error { err := ss.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
existing, err := findThumbnailByMeta(sess, cmd.DashboardThumbnailMeta) existing, err := findThumbnailByMeta(sess, cmd.DashboardThumbnailMeta)
@@ -60,13 +60,13 @@ func (ss *xormStore) Save(ctx context.Context, cmd *dashboardthumbs.SaveDashboar
existing.Updated = time.Now() existing.Updated = time.Now()
existing.DashboardVersion = cmd.DashboardVersion existing.DashboardVersion = cmd.DashboardVersion
existing.DsUIDs = dsUids existing.DsUIDs = dsUids
existing.State = dashboardthumbs.ThumbnailStateDefault existing.State = thumbs.ThumbnailStateDefault
_, err = sess.ID(existing.Id).Update(existing) _, err = sess.ID(existing.Id).Update(existing)
cmd.Result = existing cmd.Result = existing
return err return err
} }
thumb := &dashboardthumbs.DashboardThumbnail{} thumb := &thumbs.DashboardThumbnail{}
dash, err := findDashboardIdByThumbMeta(sess, cmd.DashboardThumbnailMeta) dash, err := findDashboardIdByThumbMeta(sess, cmd.DashboardThumbnailMeta)
@@ -82,7 +82,7 @@ func (ss *xormStore) Save(ctx context.Context, cmd *dashboardthumbs.SaveDashboar
thumb.MimeType = cmd.MimeType thumb.MimeType = cmd.MimeType
thumb.DashboardId = dash.Id thumb.DashboardId = dash.Id
thumb.DashboardVersion = cmd.DashboardVersion thumb.DashboardVersion = cmd.DashboardVersion
thumb.State = dashboardthumbs.ThumbnailStateDefault thumb.State = thumbs.ThumbnailStateDefault
thumb.PanelId = cmd.PanelID thumb.PanelId = cmd.PanelID
_, err = sess.Insert(thumb) _, err = sess.Insert(thumb)
cmd.Result = thumb cmd.Result = thumb
@@ -92,7 +92,7 @@ func (ss *xormStore) Save(ctx context.Context, cmd *dashboardthumbs.SaveDashboar
return cmd.Result, err return cmd.Result, err
} }
func (ss *xormStore) UpdateState(ctx context.Context, cmd *dashboardthumbs.UpdateThumbnailStateCommand) error { func (ss *xormStore) UpdateState(ctx context.Context, cmd *thumbs.UpdateThumbnailStateCommand) error {
err := ss.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error { err := ss.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
existing, err := findThumbnailByMeta(sess, cmd.DashboardThumbnailMeta) existing, err := findThumbnailByMeta(sess, cmd.DashboardThumbnailMeta)
@@ -108,9 +108,9 @@ func (ss *xormStore) UpdateState(ctx context.Context, cmd *dashboardthumbs.Updat
return err return err
} }
func (ss *xormStore) Count(ctx context.Context, cmd *dashboardthumbs.FindDashboardThumbnailCountCommand) (int64, error) { func (ss *xormStore) Count(ctx context.Context, cmd *thumbs.FindDashboardThumbnailCountCommand) (int64, error) {
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
count, err := sess.Count(&dashboardthumbs.DashboardThumbnail{}) count, err := sess.Count(&thumbs.DashboardThumbnail{})
if err != nil { if err != nil {
return err return err
} }
@@ -122,7 +122,7 @@ func (ss *xormStore) Count(ctx context.Context, cmd *dashboardthumbs.FindDashboa
return cmd.Result, err return cmd.Result, err
} }
func (ss *xormStore) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand) ([]*dashboardthumbs.DashboardWithStaleThumbnail, error) { func (ss *xormStore) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd *thumbs.FindDashboardsWithStaleThumbnailsCommand) ([]*thumbs.DashboardWithStaleThumbnail, error) {
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
sess.Table("dashboard") 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.Join("LEFT", "dashboard_thumbnail", "dashboard.id = dashboard_thumbnail.dashboard_id AND dashboard_thumbnail.theme = ? AND dashboard_thumbnail.kind = ?", cmd.Theme, cmd.Kind)
@@ -131,7 +131,7 @@ func (ss *xormStore) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd
query := "(dashboard.version != dashboard_thumbnail.dashboard_version " + query := "(dashboard.version != dashboard_thumbnail.dashboard_version " +
"OR dashboard_thumbnail.state = ? " + "OR dashboard_thumbnail.state = ? " +
"OR dashboard_thumbnail.id IS NULL" "OR dashboard_thumbnail.id IS NULL"
args := []interface{}{dashboardthumbs.ThumbnailStateStale} args := []interface{}{thumbs.ThumbnailStateStale}
if cmd.IncludeThumbnailsWithEmptyDsUIDs { if cmd.IncludeThumbnailsWithEmptyDsUIDs {
query += " OR dashboard_thumbnail.ds_uids = ? OR dashboard_thumbnail.ds_uids IS NULL" query += " OR dashboard_thumbnail.ds_uids = ? OR dashboard_thumbnail.ds_uids IS NULL"
@@ -142,10 +142,10 @@ func (ss *xormStore) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd
if !cmd.IncludeManuallyUploadedThumbnails { if !cmd.IncludeManuallyUploadedThumbnails {
sess.Where("(dashboard_thumbnail.id is not null AND dashboard_thumbnail.dashboard_version != ?) "+ sess.Where("(dashboard_thumbnail.id is not null AND dashboard_thumbnail.dashboard_version != ?) "+
"OR dashboard_thumbnail.id is null "+ "OR dashboard_thumbnail.id is null "+
"OR dashboard_thumbnail.state = ?", dashboardthumbs.DashboardVersionForManualThumbnailUpload, dashboardthumbs.ThumbnailStateStale) "OR dashboard_thumbnail.state = ?", thumbs.DashboardVersionForManualThumbnailUpload, thumbs.ThumbnailStateStale)
} }
sess.Where("(dashboard_thumbnail.id IS NULL OR dashboard_thumbnail.state != ?)", dashboardthumbs.ThumbnailStateLocked) sess.Where("(dashboard_thumbnail.id IS NULL OR dashboard_thumbnail.state != ?)", thumbs.ThumbnailStateLocked)
sess.Cols("dashboard.id", sess.Cols("dashboard.id",
"dashboard.uid", "dashboard.uid",
@@ -153,7 +153,7 @@ func (ss *xormStore) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd
"dashboard.version", "dashboard.version",
"dashboard.slug") "dashboard.slug")
var result = make([]*dashboardthumbs.DashboardWithStaleThumbnail, 0) var result = make([]*thumbs.DashboardWithStaleThumbnail, 0)
err := sess.Find(&result) err := sess.Find(&result)
if err != nil { if err != nil {
@@ -166,8 +166,8 @@ func (ss *xormStore) FindDashboardsWithStaleThumbnails(ctx context.Context, cmd
return cmd.Result, err return cmd.Result, err
} }
func findThumbnailByMeta(sess *sqlstore.DBSession, meta dashboardthumbs.DashboardThumbnailMeta) (*dashboardthumbs.DashboardThumbnail, error) { func findThumbnailByMeta(sess *sqlstore.DBSession, meta thumbs.DashboardThumbnailMeta) (*thumbs.DashboardThumbnail, error) {
result := &dashboardthumbs.DashboardThumbnail{} result := &thumbs.DashboardThumbnail{}
sess.Table("dashboard_thumbnail") sess.Table("dashboard_thumbnail")
sess.Join("INNER", "dashboard", "dashboard.id = dashboard_thumbnail.dashboard_id") sess.Join("INNER", "dashboard", "dashboard.id = dashboard_thumbnail.dashboard_id")
@@ -200,7 +200,7 @@ type dash struct {
Id int64 Id int64
} }
func findDashboardIdByThumbMeta(sess *sqlstore.DBSession, meta dashboardthumbs.DashboardThumbnailMeta) (*dash, error) { func findDashboardIdByThumbMeta(sess *sqlstore.DBSession, meta thumbs.DashboardThumbnailMeta) (*dash, error) {
result := &dash{} result := &dash{}
sess.Table("dashboard").Where("dashboard.uid = ? AND dashboard.org_id = ?", meta.DashboardUID, meta.OrgId).Cols("id") sess.Table("dashboard").Where("dashboard.uid = ? AND dashboard.org_id = ?", meta.DashboardUID, meta.OrgId).Cols("id")
+150 -11
View File
@@ -2,10 +2,12 @@ package thumbs
import ( import (
"context" "context"
"encoding/json"
"errors"
"fmt"
"time" "time"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs"
) )
type CrawlerMode string type CrawlerMode string
@@ -32,10 +34,10 @@ const (
) )
type previewRequest struct { type previewRequest struct {
OrgID int64 `json:"orgId"` OrgID int64 `json:"orgId"`
UID string `json:"uid"` UID string `json:"uid"`
Kind dashboardthumbs.ThumbnailKind `json:"kind"` Kind ThumbnailKind `json:"kind"`
Theme models.Theme `json:"theme"` Theme models.Theme `json:"theme"`
} }
type crawlCmd struct { type crawlCmd struct {
@@ -63,10 +65,147 @@ type dashboardPreviewsSetupConfig struct {
ThumbnailsExist bool `json:"thumbnailsExist"` ThumbnailsExist bool `json:"thumbnailsExist"`
} }
type ThumbnailKind string
type ThumbnailState string
const (
// ThumbnailKindDefault is a small 320x240 preview
ThumbnailKindDefault ThumbnailKind = "thumb"
// unsupported for now
// - ThumbnailKindLarge ThumbnailKind = "large"
// - ThumbnailKindTall ThumbnailKind = "tall"
)
const (
// ThumbnailStateDefault is the initial state for all thumbnails. Thumbnails in the "default" state will be considered stale,
// and thus refreshed by the crawler, if the dashboard version from the time of taking the thumbnail is different from the current dashboard version
ThumbnailStateDefault ThumbnailState = "default"
// ThumbnailStateStale is a manually assigned state. Thumbnails in the "stale" state will be refreshed on the next crawler run
ThumbnailStateStale ThumbnailState = "stale"
// ThumbnailStateLocked is a manually assigned state. Thumbnails in the "locked" state will not be refreshed by the crawler as long as they remain in the "locked" state.
ThumbnailStateLocked ThumbnailState = "locked"
)
func (s ThumbnailState) IsValid() bool {
return s == ThumbnailStateDefault || s == ThumbnailStateStale || s == ThumbnailStateLocked
}
func (s *ThumbnailState) UnmarshalJSON(data []byte) error {
var str string
err := json.Unmarshal(data, &str)
if err != nil {
return err
}
*s = ThumbnailState(str)
if !s.IsValid() {
if (*s) != "" {
return fmt.Errorf("JSON validation error: invalid thumbnail state value: %s", *s)
}
*s = ThumbnailStateDefault
}
return nil
}
// IsKnownThumbnailKind checks if the value is supported
func (p ThumbnailKind) IsKnownThumbnailKind() bool {
switch p {
case
ThumbnailKindDefault:
return true
}
return false
}
func ParseThumbnailKind(str string) (ThumbnailKind, error) {
switch str {
case string(ThumbnailKindDefault):
return ThumbnailKindDefault, nil
}
return ThumbnailKindDefault, errors.New("unknown thumbnail kind " + str)
}
// A DashboardThumbnail includes all metadata for a dashboard thumbnail
type DashboardThumbnail struct {
Id int64 `json:"id"`
DashboardId int64 `json:"dashboardId"`
DashboardVersion int `json:"dashboardVersion"`
State ThumbnailState `json:"state"`
PanelId int64 `json:"panelId,omitempty"`
Kind ThumbnailKind `json:"kind"`
Theme models.Theme `json:"theme"`
Image []byte `json:"image"`
MimeType string `json:"mimeType"`
Updated time.Time `json:"updated"`
DsUIDs string `json:"-" xorm:"ds_uids"`
}
//
// Commands
//
// DashboardThumbnailMeta uniquely identifies a thumbnail; a natural key
type DashboardThumbnailMeta struct {
DashboardUID string
OrgId int64
PanelID int64
Kind ThumbnailKind
Theme models.Theme
}
type GetDashboardThumbnailCommand struct {
DashboardThumbnailMeta
Result *DashboardThumbnail
}
const DashboardVersionForManualThumbnailUpload = -1
type DashboardWithStaleThumbnail struct {
Id int64
OrgId int64
Uid string
Version int
Slug string
}
type FindDashboardThumbnailCountCommand struct {
Result int64
}
type FindDashboardsWithStaleThumbnailsCommand struct {
IncludeManuallyUploadedThumbnails bool
IncludeThumbnailsWithEmptyDsUIDs bool
Theme models.Theme
Kind ThumbnailKind
Result []*DashboardWithStaleThumbnail
}
type SaveDashboardThumbnailCommand struct {
DashboardThumbnailMeta
DashboardVersion int
Image []byte
MimeType string
DatasourceUIDs []string
Result *DashboardThumbnail
}
type UpdateThumbnailStateCommand struct {
State ThumbnailState
DashboardThumbnailMeta
}
type dashRenderer interface { type dashRenderer interface {
// Run Assumes you have already authenticated as admin. // Run Assumes you have already authenticated as admin.
Run(ctx context.Context, auth CrawlerAuth, mode CrawlerMode, theme models.Theme, kind dashboardthumbs.ThumbnailKind) error Run(ctx context.Context, auth CrawlerAuth, mode CrawlerMode, theme models.Theme, kind ThumbnailKind) error
// Assumes you have already authenticated as admin. // Assumes you have already authenticated as admin.
Stop() (crawlStatus, error) Stop() (crawlStatus, error)
@@ -78,10 +217,10 @@ type dashRenderer interface {
} }
type thumbnailRepo interface { type thumbnailRepo interface {
updateThumbnailState(ctx context.Context, state dashboardthumbs.ThumbnailState, meta dashboardthumbs.DashboardThumbnailMeta) error updateThumbnailState(ctx context.Context, state ThumbnailState, meta DashboardThumbnailMeta) error
doThumbnailsExist(ctx context.Context) (bool, error) doThumbnailsExist(ctx context.Context) (bool, error)
saveFromFile(ctx context.Context, filePath string, meta dashboardthumbs.DashboardThumbnailMeta, dashboardVersion int, dsUids []string) (int64, error) saveFromFile(ctx context.Context, filePath string, meta DashboardThumbnailMeta, dashboardVersion int, dsUids []string) (int64, error)
saveFromBytes(ctx context.Context, bytes []byte, mimeType string, meta dashboardthumbs.DashboardThumbnailMeta, dashboardVersion int, dsUids []string) (int64, error) saveFromBytes(ctx context.Context, bytes []byte, mimeType string, meta DashboardThumbnailMeta, dashboardVersion int, dsUids []string) (int64, error)
getThumbnail(ctx context.Context, meta dashboardthumbs.DashboardThumbnailMeta) (*dashboardthumbs.DashboardThumbnail, error) getThumbnail(ctx context.Context, meta DashboardThumbnailMeta) (*DashboardThumbnail, error)
findDashboardsWithStaleThumbnails(ctx context.Context, theme models.Theme, thumbnailKind dashboardthumbs.ThumbnailKind) ([]*dashboardthumbs.DashboardWithStaleThumbnail, error) findDashboardsWithStaleThumbnails(ctx context.Context, theme models.Theme, thumbnailKind ThumbnailKind) ([]*DashboardWithStaleThumbnail, error)
} }
+12 -13
View File
@@ -9,11 +9,10 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "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/searchV2"
) )
func newThumbnailRepo(thumbsService dashboardthumbs.Service, search searchV2.SearchService) thumbnailRepo { func newThumbnailRepo(thumbsService DashboardThumbService, search searchV2.SearchService) thumbnailRepo {
repo := &sqlThumbnailRepository{ repo := &sqlThumbnailRepository{
store: thumbsService, store: thumbsService,
search: search, search: search,
@@ -23,12 +22,12 @@ func newThumbnailRepo(thumbsService dashboardthumbs.Service, search searchV2.Sea
} }
type sqlThumbnailRepository struct { type sqlThumbnailRepository struct {
store dashboardthumbs.Service store DashboardThumbService
search searchV2.SearchService search searchV2.SearchService
log log.Logger log log.Logger
} }
func (r *sqlThumbnailRepository) saveFromFile(ctx context.Context, filePath string, meta dashboardthumbs.DashboardThumbnailMeta, dashboardVersion int, dsUids []string) (int64, error) { func (r *sqlThumbnailRepository) saveFromFile(ctx context.Context, filePath string, meta DashboardThumbnailMeta, dashboardVersion int, dsUids []string) (int64, error) {
// the filePath variable is never set by the user. it refers to a temporary file created either in // the filePath variable is never set by the user. it refers to a temporary file created either in
// 1. thumbs/service.go, when user uploads a thumbnail // 1. thumbs/service.go, when user uploads a thumbnail
// 2. the rendering service, when image-renderer returns a screenshot // 2. the rendering service, when image-renderer returns a screenshot
@@ -56,8 +55,8 @@ func getMimeType(filePath string) string {
return "image/png" return "image/png"
} }
func (r *sqlThumbnailRepository) saveFromBytes(ctx context.Context, content []byte, mimeType string, meta dashboardthumbs.DashboardThumbnailMeta, dashboardVersion int, dsUids []string) (int64, error) { func (r *sqlThumbnailRepository) saveFromBytes(ctx context.Context, content []byte, mimeType string, meta DashboardThumbnailMeta, dashboardVersion int, dsUids []string) (int64, error) {
cmd := &dashboardthumbs.SaveDashboardThumbnailCommand{ cmd := &SaveDashboardThumbnailCommand{
DashboardThumbnailMeta: meta, DashboardThumbnailMeta: meta,
Image: content, Image: content,
MimeType: mimeType, MimeType: mimeType,
@@ -74,22 +73,22 @@ func (r *sqlThumbnailRepository) saveFromBytes(ctx context.Context, content []by
return cmd.Result.Id, nil return cmd.Result.Id, nil
} }
func (r *sqlThumbnailRepository) updateThumbnailState(ctx context.Context, state dashboardthumbs.ThumbnailState, meta dashboardthumbs.DashboardThumbnailMeta) error { func (r *sqlThumbnailRepository) updateThumbnailState(ctx context.Context, state ThumbnailState, meta DashboardThumbnailMeta) error {
return r.store.UpdateThumbnailState(ctx, &dashboardthumbs.UpdateThumbnailStateCommand{ return r.store.UpdateThumbnailState(ctx, &UpdateThumbnailStateCommand{
State: state, State: state,
DashboardThumbnailMeta: meta, DashboardThumbnailMeta: meta,
}) })
} }
func (r *sqlThumbnailRepository) getThumbnail(ctx context.Context, meta dashboardthumbs.DashboardThumbnailMeta) (*dashboardthumbs.DashboardThumbnail, error) { func (r *sqlThumbnailRepository) getThumbnail(ctx context.Context, meta DashboardThumbnailMeta) (*DashboardThumbnail, error) {
query := &dashboardthumbs.GetDashboardThumbnailCommand{ query := &GetDashboardThumbnailCommand{
DashboardThumbnailMeta: meta, DashboardThumbnailMeta: meta,
} }
return r.store.GetThumbnail(ctx, query) return r.store.GetThumbnail(ctx, query)
} }
func (r *sqlThumbnailRepository) findDashboardsWithStaleThumbnails(ctx context.Context, theme models.Theme, kind dashboardthumbs.ThumbnailKind) ([]*dashboardthumbs.DashboardWithStaleThumbnail, error) { func (r *sqlThumbnailRepository) findDashboardsWithStaleThumbnails(ctx context.Context, theme models.Theme, kind ThumbnailKind) ([]*DashboardWithStaleThumbnail, error) {
return r.store.FindDashboardsWithStaleThumbnails(ctx, &dashboardthumbs.FindDashboardsWithStaleThumbnailsCommand{ return r.store.FindDashboardsWithStaleThumbnails(ctx, &FindDashboardsWithStaleThumbnailsCommand{
IncludeManuallyUploadedThumbnails: false, IncludeManuallyUploadedThumbnails: false,
IncludeThumbnailsWithEmptyDsUIDs: !r.search.IsDisabled(), IncludeThumbnailsWithEmptyDsUIDs: !r.search.IsDisabled(),
Theme: theme, Theme: theme,
@@ -98,7 +97,7 @@ func (r *sqlThumbnailRepository) findDashboardsWithStaleThumbnails(ctx context.C
} }
func (r *sqlThumbnailRepository) doThumbnailsExist(ctx context.Context) (bool, error) { func (r *sqlThumbnailRepository) doThumbnailsExist(ctx context.Context) (bool, error) {
cmd := &dashboardthumbs.FindDashboardThumbnailCountCommand{} cmd := &FindDashboardThumbnailCountCommand{}
count, err := r.store.FindThumbnailCount(ctx, cmd) count, err := r.store.FindThumbnailCount(ctx, cmd)
if err != nil { if err != nil {
r.log.Error("Error finding thumbnails", "err", err) r.log.Error("Error finding thumbnails", "err", err)
+14 -15
View File
@@ -8,7 +8,6 @@ import (
"net/http" "net/http"
"time" "time"
dashboardthumbs "github.com/grafana/grafana/pkg/services/dashboard_thumbs"
"github.com/grafana/grafana/pkg/services/datasources/permissions" "github.com/grafana/grafana/pkg/services/datasources/permissions"
"github.com/grafana/grafana/pkg/services/searchV2" "github.com/grafana/grafana/pkg/services/searchV2"
"github.com/segmentio/encoding/json" "github.com/segmentio/encoding/json"
@@ -69,7 +68,7 @@ type crawlerScheduleOptions struct {
tickerInterval time.Duration tickerInterval time.Duration
maxCrawlDuration time.Duration maxCrawlDuration time.Duration
crawlerMode CrawlerMode crawlerMode CrawlerMode
thumbnailKind dashboardthumbs.ThumbnailKind thumbnailKind ThumbnailKind
themes []models.Theme themes []models.Theme
auth CrawlerAuth auth CrawlerAuth
} }
@@ -77,7 +76,7 @@ type crawlerScheduleOptions struct {
func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles,
lockService *serverlock.ServerLockService, renderService rendering.Service, lockService *serverlock.ServerLockService, renderService rendering.Service,
gl *live.GrafanaLive, store *sqlstore.SQLStore, authSetupService CrawlerAuthSetupService, gl *live.GrafanaLive, store *sqlstore.SQLStore, authSetupService CrawlerAuthSetupService,
dashboardService dashboards.DashboardService, dashboardThumbsService dashboardthumbs.Service, searchService searchV2.SearchService, dashboardService dashboards.DashboardService, dashboardThumbsService DashboardThumbService, searchService searchV2.SearchService,
dsPermissionsService permissions.DatasourcePermissionsService, licensing models.Licensing) Service { dsPermissionsService permissions.DatasourcePermissionsService, licensing models.Licensing) Service {
if !features.IsEnabled(featuremgmt.FlagDashboardPreviews) { if !features.IsEnabled(featuremgmt.FlagDashboardPreviews) {
return &dummyService{} return &dummyService{}
@@ -124,7 +123,7 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles,
crawlInterval: cfg.DashboardPreviews.SchedulerInterval, crawlInterval: cfg.DashboardPreviews.SchedulerInterval,
maxCrawlDuration: cfg.DashboardPreviews.MaxCrawlDuration, maxCrawlDuration: cfg.DashboardPreviews.MaxCrawlDuration,
crawlerMode: CrawlerModeThumbs, crawlerMode: CrawlerModeThumbs,
thumbnailKind: dashboardthumbs.ThumbnailKindDefault, thumbnailKind: ThumbnailKindDefault,
themes: []models.Theme{models.ThemeDark, models.ThemeLight}, themes: []models.Theme{models.ThemeDark, models.ThemeLight},
auth: crawlerAuth, auth: crawlerAuth,
}, },
@@ -157,7 +156,7 @@ func (hs *thumbService) Enabled() bool {
func (hs *thumbService) parseImageReq(c *models.ReqContext, checkSave bool) *previewRequest { func (hs *thumbService) parseImageReq(c *models.ReqContext, checkSave bool) *previewRequest {
params := web.Params(c.Req) params := web.Params(c.Req)
kind, err := dashboardthumbs.ParseThumbnailKind(params[":kind"]) kind, err := ParseThumbnailKind(params[":kind"])
if err != nil { if err != nil {
c.JSON(400, map[string]string{"error": "invalid size"}) c.JSON(400, map[string]string{"error": "invalid size"})
return nil return nil
@@ -191,7 +190,7 @@ func (hs *thumbService) parseImageReq(c *models.ReqContext, checkSave bool) *pre
} }
type updateThumbnailStateRequest struct { type updateThumbnailStateRequest struct {
State dashboardthumbs.ThumbnailState `json:"state" binding:"Required"` State ThumbnailState `json:"state" binding:"Required"`
} }
func (hs *thumbService) UpdateThumbnailState(c *models.ReqContext) { func (hs *thumbService) UpdateThumbnailState(c *models.ReqContext) {
@@ -209,11 +208,11 @@ func (hs *thumbService) UpdateThumbnailState(c *models.ReqContext) {
return return
} }
err = hs.thumbnailRepo.updateThumbnailState(c.Req.Context(), body.State, dashboardthumbs.DashboardThumbnailMeta{ err = hs.thumbnailRepo.updateThumbnailState(c.Req.Context(), body.State, DashboardThumbnailMeta{
DashboardUID: req.UID, DashboardUID: req.UID,
OrgId: req.OrgID, OrgId: req.OrgID,
Theme: req.Theme, Theme: req.Theme,
Kind: dashboardthumbs.ThumbnailKindDefault, Kind: ThumbnailKindDefault,
}) })
if err != nil { if err != nil {
@@ -232,11 +231,11 @@ func (hs *thumbService) GetImage(c *models.ReqContext) {
return // already returned value return // already returned value
} }
res, err := hs.thumbnailRepo.getThumbnail(c.Req.Context(), dashboardthumbs.DashboardThumbnailMeta{ res, err := hs.thumbnailRepo.getThumbnail(c.Req.Context(), DashboardThumbnailMeta{
DashboardUID: req.UID, DashboardUID: req.UID,
OrgId: req.OrgID, OrgId: req.OrgID,
Theme: req.Theme, Theme: req.Theme,
Kind: dashboardthumbs.ThumbnailKindDefault, Kind: ThumbnailKindDefault,
}) })
if errors.Is(err, dashboards.ErrDashboardThumbnailNotFound) { if errors.Is(err, dashboards.ErrDashboardThumbnailNotFound) {
@@ -269,7 +268,7 @@ func (hs *thumbService) GetImage(c *models.ReqContext) {
} }
} }
func (hs *thumbService) hasAccessToPreview(c *models.ReqContext, res *dashboardthumbs.DashboardThumbnail, req *previewRequest) bool { func (hs *thumbService) hasAccessToPreview(c *models.ReqContext, res *DashboardThumbnail, req *previewRequest) bool {
if !hs.licensing.FeatureEnabled("accesscontrol.enforcement") { if !hs.licensing.FeatureEnabled("accesscontrol.enforcement") {
return true return true
} }
@@ -402,12 +401,12 @@ func (hs *thumbService) SetImage(c *models.ReqContext) {
return return
} }
_, err = hs.thumbnailRepo.saveFromBytes(c.Req.Context(), fileBytes, getMimeType(handler.Filename), dashboardthumbs.DashboardThumbnailMeta{ _, err = hs.thumbnailRepo.saveFromBytes(c.Req.Context(), fileBytes, getMimeType(handler.Filename), DashboardThumbnailMeta{
DashboardUID: req.UID, DashboardUID: req.UID,
OrgId: req.OrgID, OrgId: req.OrgID,
Theme: req.Theme, Theme: req.Theme,
Kind: req.Kind, Kind: req.Kind,
}, dashboardthumbs.DashboardVersionForManualThumbnailUpload, dsUids) }, DashboardVersionForManualThumbnailUpload, dsUids)
if err != nil { if err != nil {
c.JSON(400, map[string]string{"error": "error saving thumbnail file"}) c.JSON(400, map[string]string{"error": "error saving thumbnail file"})
@@ -432,7 +431,7 @@ func (hs *thumbService) StartCrawler(c *models.ReqContext) response.Response {
cmd.Mode = CrawlerModeThumbs cmd.Mode = CrawlerModeThumbs
} }
go hs.runOnDemandCrawl(context.Background(), cmd.Theme, cmd.Mode, dashboardthumbs.ThumbnailKindDefault, rendering.AuthOpts{ go hs.runOnDemandCrawl(context.Background(), cmd.Theme, cmd.Mode, ThumbnailKindDefault, rendering.AuthOpts{
OrgID: c.OrgID, OrgID: c.OrgID,
UserID: c.UserID, UserID: c.UserID,
OrgRole: c.OrgRole, OrgRole: c.OrgRole,
@@ -494,7 +493,7 @@ func (hs *thumbService) getDashboardId(c *models.ReqContext, uid string) (int64,
return query.Result.Id, nil return query.Result.Id, nil
} }
func (hs *thumbService) runOnDemandCrawl(parentCtx context.Context, theme models.Theme, mode CrawlerMode, kind dashboardthumbs.ThumbnailKind, authOpts rendering.AuthOpts) { func (hs *thumbService) runOnDemandCrawl(parentCtx context.Context, theme models.Theme, mode CrawlerMode, kind ThumbnailKind, authOpts rendering.AuthOpts) {
if !hs.canRunCrawler { if !hs.canRunCrawler {
return return
} }