mirror of
https://github.com/grafana/grafana.git
synced 2025-09-19 22:34:09 +08:00
backend/sqlstore split: move dashboard snapshot funcs to dashboardsnapshotservice (#50727)
* backend/sqlstore split: move dashboard snapshot funcs to dashboardsnapshotservice This commit moves the dashboard snapshot related sql functions in the dashboardsnapshots service. I split the dashboards package up so the interfaces live in dashboarsnapshots and the store and service implementations are in their own packages. This took some minor refactoring, but none of the actual underlying code has changed, just where it lives.
This commit is contained in:
@ -133,7 +133,7 @@ func (hs *HTTPServer) CreateDashboardSnapshot(c *models.ReqContext) response.Res
|
||||
metrics.MApiDashboardSnapshotCreate.Inc()
|
||||
}
|
||||
|
||||
if err := hs.DashboardsnapshotsService.CreateDashboardSnapshot(c.Req.Context(), &cmd); err != nil {
|
||||
if err := hs.dashboardsnapshotsService.CreateDashboardSnapshot(c.Req.Context(), &cmd); err != nil {
|
||||
c.JsonApiErr(500, "Failed to create snapshot", err)
|
||||
return nil
|
||||
}
|
||||
@ -157,7 +157,7 @@ func (hs *HTTPServer) GetDashboardSnapshot(c *models.ReqContext) response.Respon
|
||||
|
||||
query := &models.GetDashboardSnapshotQuery{Key: key}
|
||||
|
||||
err := hs.DashboardsnapshotsService.GetDashboardSnapshot(c.Req.Context(), query)
|
||||
err := hs.dashboardsnapshotsService.GetDashboardSnapshot(c.Req.Context(), query)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed to get dashboard snapshot", err)
|
||||
}
|
||||
@ -224,7 +224,7 @@ func (hs *HTTPServer) DeleteDashboardSnapshotByDeleteKey(c *models.ReqContext) r
|
||||
}
|
||||
|
||||
query := &models.GetDashboardSnapshotQuery{DeleteKey: key}
|
||||
err := hs.DashboardsnapshotsService.GetDashboardSnapshot(c.Req.Context(), query)
|
||||
err := hs.dashboardsnapshotsService.GetDashboardSnapshot(c.Req.Context(), query)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed to get dashboard snapshot", err)
|
||||
}
|
||||
@ -238,7 +238,7 @@ func (hs *HTTPServer) DeleteDashboardSnapshotByDeleteKey(c *models.ReqContext) r
|
||||
|
||||
cmd := &models.DeleteDashboardSnapshotCommand{DeleteKey: query.Result.DeleteKey}
|
||||
|
||||
if err := hs.DashboardsnapshotsService.DeleteDashboardSnapshot(c.Req.Context(), cmd); err != nil {
|
||||
if err := hs.dashboardsnapshotsService.DeleteDashboardSnapshot(c.Req.Context(), cmd); err != nil {
|
||||
return response.Error(500, "Failed to delete dashboard snapshot", err)
|
||||
}
|
||||
|
||||
@ -257,7 +257,7 @@ func (hs *HTTPServer) DeleteDashboardSnapshot(c *models.ReqContext) response.Res
|
||||
|
||||
query := &models.GetDashboardSnapshotQuery{Key: key}
|
||||
|
||||
err := hs.DashboardsnapshotsService.GetDashboardSnapshot(c.Req.Context(), query)
|
||||
err := hs.dashboardsnapshotsService.GetDashboardSnapshot(c.Req.Context(), query)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed to get dashboard snapshot", err)
|
||||
}
|
||||
@ -286,7 +286,7 @@ func (hs *HTTPServer) DeleteDashboardSnapshot(c *models.ReqContext) response.Res
|
||||
|
||||
cmd := &models.DeleteDashboardSnapshotCommand{DeleteKey: query.Result.DeleteKey}
|
||||
|
||||
if err := hs.DashboardsnapshotsService.DeleteDashboardSnapshot(c.Req.Context(), cmd); err != nil {
|
||||
if err := hs.dashboardsnapshotsService.DeleteDashboardSnapshot(c.Req.Context(), cmd); err != nil {
|
||||
return response.Error(500, "Failed to delete dashboard snapshot", err)
|
||||
}
|
||||
|
||||
@ -312,7 +312,7 @@ func (hs *HTTPServer) SearchDashboardSnapshots(c *models.ReqContext) response.Re
|
||||
SignedInUser: c.SignedInUser,
|
||||
}
|
||||
|
||||
err := hs.DashboardsnapshotsService.SearchDashboardSnapshots(c.Req.Context(), &searchQuery)
|
||||
err := hs.dashboardsnapshotsService.SearchDashboardSnapshots(c.Req.Context(), &searchQuery)
|
||||
if err != nil {
|
||||
return response.Error(500, "Search failed", err)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
|
||||
dashboardsnapshots "github.com/grafana/grafana/pkg/services/dashboardsnapshots/service"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||
)
|
||||
@ -35,7 +35,8 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
|
||||
sqlmock := mockstore.NewSQLStoreMock()
|
||||
dashSvc := &dashboards.FakeDashboardService{}
|
||||
dashSvc.On("GetDashboardAclInfoList", mock.Anything, mock.AnythingOfType("*models.GetDashboardAclInfoListQuery")).Return(nil)
|
||||
hs := &HTTPServer{DashboardsnapshotsService: &dashboardsnapshots.Service{SQLStore: sqlmock}}
|
||||
dashSnapSvc := dashboardsnapshots.ProvideService(sqlmock, nil)
|
||||
hs := &HTTPServer{dashboardsnapshotsService: dashSnapSvc}
|
||||
|
||||
setUpSnapshotTest := func(t *testing.T) *models.DashboardSnapshot {
|
||||
t.Helper()
|
||||
|
@ -151,7 +151,7 @@ type HTTPServer struct {
|
||||
DatasourcePermissionsService permissions.DatasourcePermissionsService
|
||||
commentsService *comments.Service
|
||||
AlertNotificationService *alerting.AlertNotificationService
|
||||
DashboardsnapshotsService *dashboardsnapshots.Service
|
||||
dashboardsnapshotsService dashboardsnapshots.Service
|
||||
PluginSettings *pluginSettings.Service
|
||||
AvatarCacheServer *avatar.AvatarCacheServer
|
||||
preferenceService pref.Service
|
||||
@ -191,7 +191,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
||||
notificationService *notifications.NotificationService, dashboardService dashboards.DashboardService,
|
||||
dashboardProvisioningService dashboards.DashboardProvisioningService, folderService dashboards.FolderService,
|
||||
datasourcePermissionsService permissions.DatasourcePermissionsService, alertNotificationService *alerting.AlertNotificationService,
|
||||
dashboardsnapshotsService *dashboardsnapshots.Service, commentsService *comments.Service, pluginSettings *pluginSettings.Service,
|
||||
dashboardsnapshotsService dashboardsnapshots.Service, commentsService *comments.Service, pluginSettings *pluginSettings.Service,
|
||||
avatarCacheServer *avatar.AvatarCacheServer, preferenceService pref.Service, entityEventsService store.EntityEventsService,
|
||||
teamsPermissionsService accesscontrol.TeamPermissionsService, folderPermissionsService accesscontrol.FolderPermissionsService,
|
||||
dashboardPermissionsService accesscontrol.DashboardPermissionsService, dashboardVersionService dashver.Service,
|
||||
@ -266,7 +266,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
||||
commentsService: commentsService,
|
||||
teamPermissionsService: teamsPermissionsService,
|
||||
AlertNotificationService: alertNotificationService,
|
||||
DashboardsnapshotsService: dashboardsnapshotsService,
|
||||
dashboardsnapshotsService: dashboardsnapshotsService,
|
||||
PluginSettings: pluginSettings,
|
||||
AvatarCacheServer: avatarCacheServer,
|
||||
preferenceService: preferenceService,
|
||||
|
@ -39,7 +39,7 @@ func ProvideBackgroundServiceRegistry(
|
||||
secretsService *secretsManager.SecretsService, remoteCache *remotecache.RemoteCache,
|
||||
thumbnailsService thumbs.Service, StorageService store.StorageService, searchService searchV2.SearchService, entityEventsService store.EntityEventsService,
|
||||
// Need to make sure these are initialized, is there a better place to put them?
|
||||
_ *dashboardsnapshots.Service, _ *alerting.AlertNotificationService,
|
||||
_ dashboardsnapshots.Service, _ *alerting.AlertNotificationService,
|
||||
_ serviceaccounts.Service, _ *guardian.Provider,
|
||||
_ *plugindashboardsservice.DashboardUpdater,
|
||||
) *BackgroundServiceRegistry {
|
||||
|
@ -6,6 +6,7 @@ package server
|
||||
import (
|
||||
"github.com/google/wire"
|
||||
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api"
|
||||
"github.com/grafana/grafana/pkg/api/avatar"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
@ -49,6 +50,8 @@ import (
|
||||
dashboardstore "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||
dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
|
||||
dashsnapstore "github.com/grafana/grafana/pkg/services/dashboardsnapshots/database"
|
||||
dashsnapsvc "github.com/grafana/grafana/pkg/services/dashboardsnapshots/service"
|
||||
"github.com/grafana/grafana/pkg/services/dashboardversion/dashverimpl"
|
||||
"github.com/grafana/grafana/pkg/services/datasourceproxy"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
@ -217,7 +220,10 @@ var wireBasicSet = wire.NewSet(
|
||||
secretsDatabase.ProvideSecretsStore,
|
||||
wire.Bind(new(secrets.Store), new(*secretsDatabase.SecretsStoreImpl)),
|
||||
grafanads.ProvideService,
|
||||
dashboardsnapshots.ProvideService,
|
||||
wire.Bind(new(dashboardsnapshots.Store), new(*dashsnapstore.DashboardSnapshotStore)),
|
||||
dashsnapstore.ProvideStore,
|
||||
wire.Bind(new(dashboardsnapshots.Service), new(*dashsnapsvc.ServiceImpl)),
|
||||
dashsnapsvc.ProvideService,
|
||||
datasourceservice.ProvideService,
|
||||
wire.Bind(new(datasources.DataSourceService), new(*datasourceservice.Service)),
|
||||
pluginSettings.ProvideService,
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
|
||||
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
||||
"github.com/grafana/grafana/pkg/services/queryhistory"
|
||||
"github.com/grafana/grafana/pkg/services/shorturls"
|
||||
@ -22,7 +23,7 @@ import (
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, serverLockService *serverlock.ServerLockService,
|
||||
shortURLService shorturls.Service, store sqlstore.Store, queryHistoryService queryhistory.Service,
|
||||
dashboardVersionService dashver.Service) *CleanUpService {
|
||||
dashboardVersionService dashver.Service, dashSnapSvc dashboardsnapshots.Service) *CleanUpService {
|
||||
s := &CleanUpService{
|
||||
Cfg: cfg,
|
||||
ServerLockService: serverLockService,
|
||||
@ -31,6 +32,7 @@ func ProvideService(cfg *setting.Cfg, serverLockService *serverlock.ServerLockSe
|
||||
store: store,
|
||||
log: log.New("cleanup"),
|
||||
dashboardVersionService: dashboardVersionService,
|
||||
dashboardSnapshotService: dashSnapSvc,
|
||||
}
|
||||
return s
|
||||
}
|
||||
@ -43,6 +45,7 @@ type CleanUpService struct {
|
||||
ShortURLService shorturls.Service
|
||||
QueryHistoryService queryhistory.Service
|
||||
dashboardVersionService dashver.Service
|
||||
dashboardSnapshotService dashboardsnapshots.Service
|
||||
}
|
||||
|
||||
func (srv *CleanUpService) Run(ctx context.Context) error {
|
||||
@ -137,7 +140,7 @@ func (srv *CleanUpService) shouldCleanupTempFile(filemtime time.Time, now time.T
|
||||
|
||||
func (srv *CleanUpService) deleteExpiredSnapshots(ctx context.Context) {
|
||||
cmd := models.DeleteExpiredSnapshotsCommand{}
|
||||
if err := srv.store.DeleteExpiredSnapshots(ctx, &cmd); err != nil {
|
||||
if err := srv.dashboardSnapshotService.DeleteExpiredSnapshots(ctx, &cmd); err != nil {
|
||||
srv.log.Error("Failed to delete expired snapshots", "error", err.Error())
|
||||
} else {
|
||||
srv.log.Debug("Deleted expired snapshots", "rows affected", cmd.DeletedRows)
|
||||
|
@ -1,75 +0,0 @@
|
||||
package dashboardsnapshots
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
SQLStore sqlstore.Store
|
||||
SecretsService secrets.Service
|
||||
}
|
||||
|
||||
func ProvideService(store sqlstore.Store, secretsService secrets.Service) *Service {
|
||||
s := &Service{
|
||||
SQLStore: store,
|
||||
SecretsService: secretsService,
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Service) CreateDashboardSnapshot(ctx context.Context, cmd *models.CreateDashboardSnapshotCommand) error {
|
||||
marshalledData, err := cmd.Dashboard.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encryptedDashboard, err := s.SecretsService.Encrypt(ctx, marshalledData, secrets.WithoutScope())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.DashboardEncrypted = encryptedDashboard
|
||||
|
||||
return s.SQLStore.CreateDashboardSnapshot(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s *Service) GetDashboardSnapshot(ctx context.Context, query *models.GetDashboardSnapshotQuery) error {
|
||||
err := s.SQLStore.GetDashboardSnapshot(ctx, query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if query.Result.DashboardEncrypted != nil {
|
||||
decryptedDashboard, err := s.SecretsService.Decrypt(ctx, query.Result.DashboardEncrypted)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dashboard, err := simplejson.NewJson(decryptedDashboard)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query.Result.Dashboard = dashboard
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) DeleteDashboardSnapshot(ctx context.Context, cmd *models.DeleteDashboardSnapshotCommand) error {
|
||||
return s.SQLStore.DeleteDashboardSnapshot(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s *Service) SearchDashboardSnapshots(ctx context.Context, query *models.GetDashboardSnapshotsQuery) error {
|
||||
return s.SQLStore.SearchDashboardSnapshots(ctx, query)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteExpiredSnapshots(ctx context.Context, cmd *models.DeleteExpiredSnapshotsCommand) error {
|
||||
return s.SQLStore.DeleteExpiredSnapshots(ctx, cmd)
|
||||
}
|
@ -1,21 +1,37 @@
|
||||
package sqlstore
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/db"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
type DashboardSnapshotStore struct {
|
||||
store db.DB
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
// DashboardStore implements the Store interface
|
||||
var _ dashboardsnapshots.Store = (*DashboardSnapshotStore)(nil)
|
||||
|
||||
func ProvideStore(db db.DB) *DashboardSnapshotStore {
|
||||
return &DashboardSnapshotStore{store: db, log: log.New("dashboardsnapshot.store")}
|
||||
}
|
||||
|
||||
// DeleteExpiredSnapshots removes snapshots with old expiry dates.
|
||||
// SnapShotRemoveExpired is deprecated and should be removed in the future.
|
||||
// Snapshot expiry is decided by the user when they share the snapshot.
|
||||
func (ss *SQLStore) DeleteExpiredSnapshots(ctx context.Context, cmd *models.DeleteExpiredSnapshotsCommand) error {
|
||||
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||
func (d *DashboardSnapshotStore) DeleteExpiredSnapshots(ctx context.Context, cmd *models.DeleteExpiredSnapshotsCommand) error {
|
||||
return d.store.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
if !setting.SnapShotRemoveExpired {
|
||||
sqlog.Warn("[Deprecated] The snapshot_remove_expired setting is outdated. Please remove from your config.")
|
||||
d.log.Warn("[Deprecated] The snapshot_remove_expired setting is outdated. Please remove from your config.")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -30,8 +46,8 @@ func (ss *SQLStore) DeleteExpiredSnapshots(ctx context.Context, cmd *models.Dele
|
||||
})
|
||||
}
|
||||
|
||||
func (ss *SQLStore) CreateDashboardSnapshot(ctx context.Context, cmd *models.CreateDashboardSnapshotCommand) error {
|
||||
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||
func (d *DashboardSnapshotStore) CreateDashboardSnapshot(ctx context.Context, cmd *models.CreateDashboardSnapshotCommand) error {
|
||||
return d.store.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
// never
|
||||
var expires = time.Now().Add(time.Hour * 24 * 365 * 50)
|
||||
if cmd.Expires > 0 {
|
||||
@ -60,16 +76,16 @@ func (ss *SQLStore) CreateDashboardSnapshot(ctx context.Context, cmd *models.Cre
|
||||
})
|
||||
}
|
||||
|
||||
func (ss *SQLStore) DeleteDashboardSnapshot(ctx context.Context, cmd *models.DeleteDashboardSnapshotCommand) error {
|
||||
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||
func (d *DashboardSnapshotStore) DeleteDashboardSnapshot(ctx context.Context, cmd *models.DeleteDashboardSnapshotCommand) error {
|
||||
return d.store.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
var rawSQL = "DELETE FROM dashboard_snapshot WHERE delete_key=?"
|
||||
_, err := sess.Exec(rawSQL, cmd.DeleteKey)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (ss *SQLStore) GetDashboardSnapshot(ctx context.Context, query *models.GetDashboardSnapshotQuery) error {
|
||||
return ss.WithDbSession(ctx, func(dbSess *DBSession) error {
|
||||
func (d *DashboardSnapshotStore) GetDashboardSnapshot(ctx context.Context, query *models.GetDashboardSnapshotQuery) error {
|
||||
return d.store.WithDbSession(ctx, func(dbSess *sqlstore.DBSession) error {
|
||||
snapshot := models.DashboardSnapshot{Key: query.Key, DeleteKey: query.DeleteKey}
|
||||
has, err := dbSess.Get(&snapshot)
|
||||
|
||||
@ -86,11 +102,9 @@ func (ss *SQLStore) GetDashboardSnapshot(ctx context.Context, query *models.GetD
|
||||
|
||||
// SearchDashboardSnapshots returns a list of all snapshots for admins
|
||||
// for other roles, it returns snapshots created by the user
|
||||
func (ss *SQLStore) SearchDashboardSnapshots(ctx context.Context, query *models.GetDashboardSnapshotsQuery) error {
|
||||
return ss.WithDbSession(ctx, func(dbSess *DBSession) error {
|
||||
func (d *DashboardSnapshotStore) SearchDashboardSnapshots(ctx context.Context, query *models.GetDashboardSnapshotsQuery) error {
|
||||
return d.store.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
var snapshots = make(models.DashboardSnapshotsList, 0)
|
||||
|
||||
sess := ss.NewSession(ctx)
|
||||
if query.Limit > 0 {
|
||||
sess.Limit(query.Limit)
|
||||
}
|
@ -1,24 +1,27 @@
|
||||
package sqlstore
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIntegrationDashboardSnapshotDBAccess(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
sqlstore := InitTestDB(t)
|
||||
sqlstore := sqlstore.InitTestDB(t)
|
||||
dashStore := ProvideStore(sqlstore)
|
||||
|
||||
origSecret := setting.SecretKey
|
||||
setting.SecretKey = "dashboard_snapshot_testing"
|
||||
@ -42,12 +45,12 @@ func TestIntegrationDashboardSnapshotDBAccess(t *testing.T) {
|
||||
OrgId: 1,
|
||||
}
|
||||
|
||||
err = sqlstore.CreateDashboardSnapshot(context.Background(), &cmd)
|
||||
err = dashStore.CreateDashboardSnapshot(context.Background(), &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should be able to get snapshot by key", func(t *testing.T) {
|
||||
query := models.GetDashboardSnapshotQuery{Key: "hej"}
|
||||
err := sqlstore.GetDashboardSnapshot(context.Background(), &query)
|
||||
err := dashStore.GetDashboardSnapshot(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, query.Result)
|
||||
@ -69,7 +72,7 @@ func TestIntegrationDashboardSnapshotDBAccess(t *testing.T) {
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_ADMIN},
|
||||
}
|
||||
err := sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
err := dashStore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should return all the snapshots", func(t *testing.T) {
|
||||
@ -83,7 +86,7 @@ func TestIntegrationDashboardSnapshotDBAccess(t *testing.T) {
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR, UserId: 1000},
|
||||
}
|
||||
err := sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
err := dashStore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should return all the snapshots", func(t *testing.T) {
|
||||
@ -97,7 +100,7 @@ func TestIntegrationDashboardSnapshotDBAccess(t *testing.T) {
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR, UserId: 2},
|
||||
}
|
||||
err := sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
err := dashStore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should not return any snapshots", func(t *testing.T) {
|
||||
@ -116,7 +119,7 @@ func TestIntegrationDashboardSnapshotDBAccess(t *testing.T) {
|
||||
UserId: 0,
|
||||
OrgId: 1,
|
||||
}
|
||||
err := sqlstore.CreateDashboardSnapshot(context.Background(), &cmd)
|
||||
err := dashStore.CreateDashboardSnapshot(context.Background(), &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should not return any snapshots", func(t *testing.T) {
|
||||
@ -124,7 +127,7 @@ func TestIntegrationDashboardSnapshotDBAccess(t *testing.T) {
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR, IsAnonymous: true, UserId: 0},
|
||||
}
|
||||
err := sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
err := dashStore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, query.Result)
|
||||
@ -148,36 +151,37 @@ func TestIntegrationDeleteExpiredSnapshots(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
sqlstore := InitTestDB(t)
|
||||
sqlstore := sqlstore.InitTestDB(t)
|
||||
dashStore := ProvideStore(sqlstore)
|
||||
|
||||
t.Run("Testing dashboard snapshots clean up", func(t *testing.T) {
|
||||
setting.SnapShotRemoveExpired = true
|
||||
|
||||
nonExpiredSnapshot := createTestSnapshot(t, sqlstore, "key1", 48000)
|
||||
createTestSnapshot(t, sqlstore, "key2", -1200)
|
||||
createTestSnapshot(t, sqlstore, "key3", -1200)
|
||||
nonExpiredSnapshot := createTestSnapshot(t, dashStore, "key1", 48000)
|
||||
createTestSnapshot(t, dashStore, "key2", -1200)
|
||||
createTestSnapshot(t, dashStore, "key3", -1200)
|
||||
|
||||
err := sqlstore.DeleteExpiredSnapshots(context.Background(), &models.DeleteExpiredSnapshotsCommand{})
|
||||
err := dashStore.DeleteExpiredSnapshots(context.Background(), &models.DeleteExpiredSnapshotsCommand{})
|
||||
require.NoError(t, err)
|
||||
|
||||
query := models.GetDashboardSnapshotsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_ADMIN},
|
||||
}
|
||||
err = sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
err = dashStore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, query.Result, 1)
|
||||
assert.Equal(t, nonExpiredSnapshot.Key, query.Result[0].Key)
|
||||
|
||||
err = sqlstore.DeleteExpiredSnapshots(context.Background(), &models.DeleteExpiredSnapshotsCommand{})
|
||||
err = dashStore.DeleteExpiredSnapshots(context.Background(), &models.DeleteExpiredSnapshotsCommand{})
|
||||
require.NoError(t, err)
|
||||
|
||||
query = models.GetDashboardSnapshotsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_ADMIN},
|
||||
}
|
||||
err = sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
err = dashStore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, query.Result, 1)
|
||||
@ -185,7 +189,7 @@ func TestIntegrationDeleteExpiredSnapshots(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func createTestSnapshot(t *testing.T, sqlstore *SQLStore, key string, expires int64) *models.DashboardSnapshot {
|
||||
func createTestSnapshot(t *testing.T, dashStore *DashboardSnapshotStore, key string, expires int64) *models.DashboardSnapshot {
|
||||
cmd := models.CreateDashboardSnapshotCommand{
|
||||
Key: key,
|
||||
DeleteKey: "delete" + key,
|
||||
@ -196,13 +200,16 @@ func createTestSnapshot(t *testing.T, sqlstore *SQLStore, key string, expires in
|
||||
OrgId: 1,
|
||||
Expires: expires,
|
||||
}
|
||||
err := sqlstore.CreateDashboardSnapshot(context.Background(), &cmd)
|
||||
err := dashStore.CreateDashboardSnapshot(context.Background(), &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set expiry date manually - to be able to create expired snapshots
|
||||
if expires < 0 {
|
||||
expireDate := time.Now().Add(time.Second * time.Duration(expires))
|
||||
_, err = sqlstore.engine.Exec("UPDATE dashboard_snapshot SET expires = ? WHERE id = ?", expireDate, cmd.Result.Id)
|
||||
err = dashStore.store.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||
_, err := sess.Exec("UPDATE dashboard_snapshot SET expires = ? WHERE id = ?", expireDate, cmd.Result.Id)
|
||||
return err
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
15
pkg/services/dashboardsnapshots/service.go
Normal file
15
pkg/services/dashboardsnapshots/service.go
Normal file
@ -0,0 +1,15 @@
|
||||
package dashboardsnapshots
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
CreateDashboardSnapshot(context.Context, *models.CreateDashboardSnapshotCommand) error
|
||||
DeleteDashboardSnapshot(context.Context, *models.DeleteDashboardSnapshotCommand) error
|
||||
DeleteExpiredSnapshots(context.Context, *models.DeleteExpiredSnapshotsCommand) error
|
||||
GetDashboardSnapshot(context.Context, *models.GetDashboardSnapshotQuery) error
|
||||
SearchDashboardSnapshots(context.Context, *models.GetDashboardSnapshotsQuery) error
|
||||
}
|
78
pkg/services/dashboardsnapshots/service/service.go
Normal file
78
pkg/services/dashboardsnapshots/service/service.go
Normal file
@ -0,0 +1,78 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
)
|
||||
|
||||
type ServiceImpl struct {
|
||||
store dashboardsnapshots.Store
|
||||
secretsService secrets.Service
|
||||
}
|
||||
|
||||
// ServiceImpl implements the dashboardsnapshots Service interface
|
||||
var _ dashboardsnapshots.Service = (*ServiceImpl)(nil)
|
||||
|
||||
func ProvideService(store dashboardsnapshots.Store, secretsService secrets.Service) *ServiceImpl {
|
||||
s := &ServiceImpl{
|
||||
store: store,
|
||||
secretsService: secretsService,
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) CreateDashboardSnapshot(ctx context.Context, cmd *models.CreateDashboardSnapshotCommand) error {
|
||||
marshalledData, err := cmd.Dashboard.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encryptedDashboard, err := s.secretsService.Encrypt(ctx, marshalledData, secrets.WithoutScope())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.DashboardEncrypted = encryptedDashboard
|
||||
|
||||
return s.store.CreateDashboardSnapshot(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) GetDashboardSnapshot(ctx context.Context, query *models.GetDashboardSnapshotQuery) error {
|
||||
err := s.store.GetDashboardSnapshot(ctx, query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if query.Result.DashboardEncrypted != nil {
|
||||
decryptedDashboard, err := s.secretsService.Decrypt(ctx, query.Result.DashboardEncrypted)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dashboard, err := simplejson.NewJson(decryptedDashboard)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query.Result.Dashboard = dashboard
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) DeleteDashboardSnapshot(ctx context.Context, cmd *models.DeleteDashboardSnapshotCommand) error {
|
||||
return s.store.DeleteDashboardSnapshot(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) SearchDashboardSnapshots(ctx context.Context, query *models.GetDashboardSnapshotsQuery) error {
|
||||
return s.store.SearchDashboardSnapshots(ctx, query)
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) DeleteExpiredSnapshots(ctx context.Context, cmd *models.DeleteExpiredSnapshotsCommand) error {
|
||||
return s.store.DeleteExpiredSnapshots(ctx, cmd)
|
||||
}
|
@ -1,27 +1,25 @@
|
||||
package dashboardsnapshots
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/secrets/database"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
dashsnapdb "github.com/grafana/grafana/pkg/services/dashboardsnapshots/database"
|
||||
"github.com/grafana/grafana/pkg/services/secrets/database"
|
||||
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDashboardSnapshotsService(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dsStore := dashsnapdb.ProvideStore(sqlStore)
|
||||
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
|
||||
|
||||
s := &Service{
|
||||
SQLStore: sqlStore,
|
||||
SecretsService: secretsService,
|
||||
}
|
||||
s := ProvideService(dsStore, secretsService)
|
||||
|
||||
origSecret := setting.SecretKey
|
||||
setting.SecretKey = "dashboard_snapshot_service_test"
|
||||
@ -47,7 +45,7 @@ func TestDashboardSnapshotsService(t *testing.T) {
|
||||
err = s.CreateDashboardSnapshot(ctx, &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
decrypted, err := s.SecretsService.Decrypt(ctx, cmd.Result.DashboardEncrypted)
|
||||
decrypted, err := s.secretsService.Decrypt(ctx, cmd.Result.DashboardEncrypted)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, rawDashboard, decrypted)
|
15
pkg/services/dashboardsnapshots/store.go
Normal file
15
pkg/services/dashboardsnapshots/store.go
Normal file
@ -0,0 +1,15 @@
|
||||
package dashboardsnapshots
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type Store interface {
|
||||
CreateDashboardSnapshot(context.Context, *models.CreateDashboardSnapshotCommand) error
|
||||
DeleteDashboardSnapshot(context.Context, *models.DeleteDashboardSnapshotCommand) error
|
||||
DeleteExpiredSnapshots(context.Context, *models.DeleteExpiredSnapshotsCommand) error
|
||||
GetDashboardSnapshot(context.Context, *models.GetDashboardSnapshotQuery) error
|
||||
SearchDashboardSnapshots(context.Context, *models.GetDashboardSnapshotsQuery) error
|
||||
}
|
@ -1 +0,0 @@
|
||||
package sqlstore
|
@ -12,11 +12,6 @@ type Store interface {
|
||||
GetDataSourceStats(ctx context.Context, query *models.GetDataSourceStatsQuery) error
|
||||
GetDataSourceAccessStats(ctx context.Context, query *models.GetDataSourceAccessStatsQuery) error
|
||||
GetSystemStats(ctx context.Context, query *models.GetSystemStatsQuery) error
|
||||
DeleteExpiredSnapshots(ctx context.Context, cmd *models.DeleteExpiredSnapshotsCommand) error
|
||||
CreateDashboardSnapshot(ctx context.Context, cmd *models.CreateDashboardSnapshotCommand) error
|
||||
DeleteDashboardSnapshot(ctx context.Context, cmd *models.DeleteDashboardSnapshotCommand) error
|
||||
GetDashboardSnapshot(ctx context.Context, query *models.GetDashboardSnapshotQuery) error
|
||||
SearchDashboardSnapshots(ctx context.Context, query *models.GetDashboardSnapshotsQuery) error
|
||||
GetOrgByName(name string) (*models.Org, error)
|
||||
CreateOrg(ctx context.Context, cmd *models.CreateOrgCommand) error
|
||||
CreateOrgWithMember(name string, userID int64) (models.Org, error)
|
||||
|
Reference in New Issue
Block a user