mirror of
https://github.com/grafana/grafana.git
synced 2026-08-18 17:15:08 -05: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:
@@ -1 +0,0 @@
|
||||
package sqlstore
|
||||
@@ -1,118 +0,0 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
if !setting.SnapShotRemoveExpired {
|
||||
sqlog.Warn("[Deprecated] The snapshot_remove_expired setting is outdated. Please remove from your config.")
|
||||
return nil
|
||||
}
|
||||
|
||||
deleteExpiredSQL := "DELETE FROM dashboard_snapshot WHERE expires < ?"
|
||||
expiredResponse, err := sess.Exec(deleteExpiredSQL, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.DeletedRows, _ = expiredResponse.RowsAffected()
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (ss *SQLStore) CreateDashboardSnapshot(ctx context.Context, cmd *models.CreateDashboardSnapshotCommand) error {
|
||||
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||
// never
|
||||
var expires = time.Now().Add(time.Hour * 24 * 365 * 50)
|
||||
if cmd.Expires > 0 {
|
||||
expires = time.Now().Add(time.Second * time.Duration(cmd.Expires))
|
||||
}
|
||||
|
||||
snapshot := &models.DashboardSnapshot{
|
||||
Name: cmd.Name,
|
||||
Key: cmd.Key,
|
||||
DeleteKey: cmd.DeleteKey,
|
||||
OrgId: cmd.OrgId,
|
||||
UserId: cmd.UserId,
|
||||
External: cmd.External,
|
||||
ExternalUrl: cmd.ExternalUrl,
|
||||
ExternalDeleteUrl: cmd.ExternalDeleteUrl,
|
||||
Dashboard: simplejson.New(),
|
||||
DashboardEncrypted: cmd.DashboardEncrypted,
|
||||
Expires: expires,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
}
|
||||
_, err := sess.Insert(snapshot)
|
||||
cmd.Result = snapshot
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (ss *SQLStore) DeleteDashboardSnapshot(ctx context.Context, cmd *models.DeleteDashboardSnapshotCommand) error {
|
||||
return ss.WithTransactionalDbSession(ctx, func(sess *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 {
|
||||
snapshot := models.DashboardSnapshot{Key: query.Key, DeleteKey: query.DeleteKey}
|
||||
has, err := dbSess.Get(&snapshot)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return models.ErrDashboardSnapshotNotFound
|
||||
}
|
||||
|
||||
query.Result = &snapshot
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// 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 {
|
||||
var snapshots = make(models.DashboardSnapshotsList, 0)
|
||||
|
||||
sess := ss.NewSession(ctx)
|
||||
if query.Limit > 0 {
|
||||
sess.Limit(query.Limit)
|
||||
}
|
||||
sess.Table("dashboard_snapshot")
|
||||
|
||||
if query.Name != "" {
|
||||
sess.Where("name LIKE ?", query.Name)
|
||||
}
|
||||
|
||||
// admins can see all snapshots, everyone else can only see their own snapshots
|
||||
switch {
|
||||
case query.SignedInUser.OrgRole == models.ROLE_ADMIN:
|
||||
sess.Where("org_id = ?", query.OrgId)
|
||||
case !query.SignedInUser.IsAnonymous:
|
||||
sess.Where("org_id = ? AND user_id = ?", query.OrgId, query.SignedInUser.UserId)
|
||||
default:
|
||||
query.Result = snapshots
|
||||
return nil
|
||||
}
|
||||
|
||||
err := sess.Find(&snapshots)
|
||||
query.Result = snapshots
|
||||
return err
|
||||
})
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"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/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)
|
||||
|
||||
origSecret := setting.SecretKey
|
||||
setting.SecretKey = "dashboard_snapshot_testing"
|
||||
t.Cleanup(func() {
|
||||
setting.SecretKey = origSecret
|
||||
})
|
||||
secretsService := fakes.NewFakeSecretsService()
|
||||
dashboard := simplejson.NewFromAny(map[string]interface{}{"hello": "mupp"})
|
||||
|
||||
t.Run("Given saved snapshot", func(t *testing.T) {
|
||||
rawDashboard, err := dashboard.Encode()
|
||||
require.NoError(t, err)
|
||||
|
||||
encryptedDashboard, err := secretsService.Encrypt(context.Background(), rawDashboard, secrets.WithoutScope())
|
||||
require.NoError(t, err)
|
||||
|
||||
cmd := models.CreateDashboardSnapshotCommand{
|
||||
Key: "hej",
|
||||
DashboardEncrypted: encryptedDashboard,
|
||||
UserId: 1000,
|
||||
OrgId: 1,
|
||||
}
|
||||
|
||||
err = sqlstore.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)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, query.Result)
|
||||
|
||||
decryptedDashboard, err := secretsService.Decrypt(
|
||||
context.Background(),
|
||||
query.Result.DashboardEncrypted,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
dashboard, err := simplejson.NewJson(decryptedDashboard)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "mupp", dashboard.Get("hello").MustString())
|
||||
})
|
||||
|
||||
t.Run("And the user has the admin role", func(t *testing.T) {
|
||||
query := models.GetDashboardSnapshotsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_ADMIN},
|
||||
}
|
||||
err := sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should return all the snapshots", func(t *testing.T) {
|
||||
assert.NotNil(t, query.Result)
|
||||
assert.Len(t, query.Result, 1)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("And the user has the editor role and has created a snapshot", func(t *testing.T) {
|
||||
query := models.GetDashboardSnapshotsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR, UserId: 1000},
|
||||
}
|
||||
err := sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should return all the snapshots", func(t *testing.T) {
|
||||
require.NotNil(t, query.Result)
|
||||
assert.Len(t, query.Result, 1)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("And the user has the editor role and has not created any snapshot", func(t *testing.T) {
|
||||
query := models.GetDashboardSnapshotsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR, UserId: 2},
|
||||
}
|
||||
err := sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should not return any snapshots", func(t *testing.T) {
|
||||
require.NotNil(t, query.Result)
|
||||
assert.Empty(t, query.Result)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("And the user is anonymous", func(t *testing.T) {
|
||||
cmd := models.CreateDashboardSnapshotCommand{
|
||||
Key: "strangesnapshotwithuserid0",
|
||||
DeleteKey: "adeletekey",
|
||||
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
||||
"hello": "mupp",
|
||||
}),
|
||||
UserId: 0,
|
||||
OrgId: 1,
|
||||
}
|
||||
err := sqlstore.CreateDashboardSnapshot(context.Background(), &cmd)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should not return any snapshots", func(t *testing.T) {
|
||||
query := models.GetDashboardSnapshotsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR, IsAnonymous: true, UserId: 0},
|
||||
}
|
||||
err := sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, query.Result)
|
||||
assert.Empty(t, query.Result)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Should have encrypted dashboard data", func(t *testing.T) {
|
||||
decryptedDashboard, err := secretsService.Decrypt(
|
||||
context.Background(),
|
||||
cmd.Result.DashboardEncrypted,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, decryptedDashboard, rawDashboard)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntegrationDeleteExpiredSnapshots(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
sqlstore := InitTestDB(t)
|
||||
|
||||
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)
|
||||
|
||||
err := sqlstore.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)
|
||||
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{})
|
||||
require.NoError(t, err)
|
||||
|
||||
query = models.GetDashboardSnapshotsQuery{
|
||||
OrgId: 1,
|
||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_ADMIN},
|
||||
}
|
||||
err = sqlstore.SearchDashboardSnapshots(context.Background(), &query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, query.Result, 1)
|
||||
require.Equal(t, nonExpiredSnapshot.Key, query.Result[0].Key)
|
||||
})
|
||||
}
|
||||
|
||||
func createTestSnapshot(t *testing.T, sqlstore *SQLStore, key string, expires int64) *models.DashboardSnapshot {
|
||||
cmd := models.CreateDashboardSnapshotCommand{
|
||||
Key: key,
|
||||
DeleteKey: "delete" + key,
|
||||
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
||||
"hello": "mupp",
|
||||
}),
|
||||
UserId: 1000,
|
||||
OrgId: 1,
|
||||
Expires: expires,
|
||||
}
|
||||
err := sqlstore.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)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
return cmd.Result
|
||||
}
|
||||
@@ -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