mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Cloud migration: Refactor get by org ID to dashboard svc (#98646)
This commit is contained in:
parent
9b1ecaedda
commit
58ed8a9ec2
@ -399,18 +399,15 @@ func Test_OnlyQueriesStatusFromGMSWhenRequired(t *testing.T) {
|
|||||||
func Test_DeletedDashboardsNotMigrated(t *testing.T) {
|
func Test_DeletedDashboardsNotMigrated(t *testing.T) {
|
||||||
s := setUpServiceTest(t, false).(*Service)
|
s := setUpServiceTest(t, false).(*Service)
|
||||||
|
|
||||||
/** NOTE: this is not used at the moment since we changed the service
|
|
||||||
|
|
||||||
// modify what the mock returns for just this test case
|
// modify what the mock returns for just this test case
|
||||||
dashMock := s.dashboardService.(*dashboards.FakeDashboardService)
|
dashMock := s.dashboardService.(*dashboards.FakeDashboardService)
|
||||||
dashMock.On("GetAllDashboards", mock.Anything).Return(
|
dashMock.On("GetAllDashboardsByOrgId", mock.Anything).Return(
|
||||||
[]*dashboards.Dashboard{
|
[]*dashboards.Dashboard{
|
||||||
{UID: "1", OrgID: 1, Data: simplejson.New()},
|
{UID: "1", OrgID: 1, Data: simplejson.New()},
|
||||||
{UID: "2", OrgID: 1, Data: simplejson.New(), Deleted: time.Now()},
|
{UID: "2", OrgID: 1, Data: simplejson.New(), Deleted: time.Now()},
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
*/
|
|
||||||
|
|
||||||
data, err := s.getMigrationDataJSON(context.TODO(), &user.SignedInUser{OrgID: 1})
|
data, err := s.getMigrationDataJSON(context.TODO(), &user.SignedInUser{OrgID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -277,7 +277,7 @@ func (s *Service) getDashboardAndFolderCommands(ctx context.Context, signedInUse
|
|||||||
ctx, span := s.tracer.Start(ctx, "CloudMigrationService.getDashboardAndFolderCommands")
|
ctx, span := s.tracer.Start(ctx, "CloudMigrationService.getDashboardAndFolderCommands")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
dashs, err := s.store.GetAllDashboardsByOrgId(ctx, signedInUser.GetOrgID())
|
dashs, err := s.dashboardService.GetAllDashboardsByOrgId(ctx, signedInUser.GetOrgID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/cloudmigration"
|
"github.com/grafana/grafana/pkg/services/cloudmigration"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type store interface {
|
type store interface {
|
||||||
@ -26,7 +25,4 @@ type store interface {
|
|||||||
// - GetSnapshotResources(ctx context.Context, snapshotUid string, page int, limit int) ([]cloudmigration.CloudMigrationResource, error)
|
// - GetSnapshotResources(ctx context.Context, snapshotUid string, page int, limit int) ([]cloudmigration.CloudMigrationResource, error)
|
||||||
// - GetSnapshotResourceStats(ctx context.Context, snapshotUid string) (*cloudmigration.SnapshotResourceStats, error)
|
// - GetSnapshotResourceStats(ctx context.Context, snapshotUid string) (*cloudmigration.SnapshotResourceStats, error)
|
||||||
// - DeleteSnapshotResources(ctx context.Context, snapshotUid string) error
|
// - DeleteSnapshotResources(ctx context.Context, snapshotUid string) error
|
||||||
|
|
||||||
// TODO move this function dashboards/databases/databases.go
|
|
||||||
GetAllDashboardsByOrgId(ctx context.Context, orgID int64) ([]*dashboards.Dashboard, error)
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/services/cloudmigration"
|
"github.com/grafana/grafana/pkg/services/cloudmigration"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
||||||
"github.com/grafana/grafana/pkg/services/secrets"
|
"github.com/grafana/grafana/pkg/services/secrets"
|
||||||
secretskv "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
secretskv "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
@ -465,19 +464,3 @@ func (ss *sqlStore) decryptToken(ctx context.Context, cm *cloudmigration.CloudMi
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO move this function dashboards/databases/databases.go
|
|
||||||
func (ss *sqlStore) GetAllDashboardsByOrgId(ctx context.Context, orgID int64) ([]*dashboards.Dashboard, error) {
|
|
||||||
//ctx, span := tracer.Start(ctx, "dashboards.database.GetAllDashboardsByOrgId")
|
|
||||||
//defer span.End()
|
|
||||||
|
|
||||||
var dashs = make([]*dashboards.Dashboard, 0)
|
|
||||||
err := ss.db.WithDbSession(ctx, func(session *db.Session) error {
|
|
||||||
// "deleted IS NULL" is to avoid deleted dashboards
|
|
||||||
return session.Where("org_id = ? AND deleted IS NULL", orgID).Find(&dashs)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return dashs, nil
|
|
||||||
}
|
|
||||||
|
@ -31,6 +31,7 @@ type DashboardService interface {
|
|||||||
CountInFolders(ctx context.Context, orgID int64, folderUIDs []string, user identity.Requester) (int64, error)
|
CountInFolders(ctx context.Context, orgID int64, folderUIDs []string, user identity.Requester) (int64, error)
|
||||||
GetDashboardsSharedWithUser(ctx context.Context, user identity.Requester) ([]*Dashboard, error)
|
GetDashboardsSharedWithUser(ctx context.Context, user identity.Requester) ([]*Dashboard, error)
|
||||||
GetAllDashboards(ctx context.Context) ([]*Dashboard, error)
|
GetAllDashboards(ctx context.Context) ([]*Dashboard, error)
|
||||||
|
GetAllDashboardsByOrgId(ctx context.Context, orgID int64) ([]*Dashboard, error)
|
||||||
SoftDeleteDashboard(ctx context.Context, orgID int64, dashboardUid string) error
|
SoftDeleteDashboard(ctx context.Context, orgID int64, dashboardUid string) error
|
||||||
RestoreDashboard(ctx context.Context, dashboard *Dashboard, user identity.Requester, optionalFolderUID string) error
|
RestoreDashboard(ctx context.Context, dashboard *Dashboard, user identity.Requester, optionalFolderUID string) error
|
||||||
CleanUpDeletedDashboards(ctx context.Context) (int64, error)
|
CleanUpDeletedDashboards(ctx context.Context) (int64, error)
|
||||||
@ -86,6 +87,7 @@ type Store interface {
|
|||||||
DeleteDashboardsInFolders(ctx context.Context, request *DeleteDashboardsInFolderRequest) error
|
DeleteDashboardsInFolders(ctx context.Context, request *DeleteDashboardsInFolderRequest) error
|
||||||
|
|
||||||
GetAllDashboards(ctx context.Context) ([]*Dashboard, error)
|
GetAllDashboards(ctx context.Context) ([]*Dashboard, error)
|
||||||
|
GetAllDashboardsByOrgId(ctx context.Context, orgID int64) ([]*Dashboard, error)
|
||||||
GetSoftDeletedExpiredDashboards(ctx context.Context, duration time.Duration) ([]*Dashboard, error)
|
GetSoftDeletedExpiredDashboards(ctx context.Context, duration time.Duration) ([]*Dashboard, error)
|
||||||
SoftDeleteDashboard(ctx context.Context, orgID int64, dashboardUid string) error
|
SoftDeleteDashboard(ctx context.Context, orgID int64, dashboardUid string) error
|
||||||
SoftDeleteDashboardsInFolders(ctx context.Context, orgID int64, folderUids []string) error
|
SoftDeleteDashboardsInFolders(ctx context.Context, orgID int64, folderUids []string) error
|
||||||
|
@ -198,6 +198,36 @@ func (_m *FakeDashboardService) GetAllDashboards(ctx context.Context) ([]*Dashbo
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (_m *FakeDashboardService) GetAllDashboardsByOrgId(ctx context.Context, orgID int64) ([]*Dashboard, error) {
|
||||||
|
ret := _m.Called(ctx)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GetAllDashboardsByOrgId")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*Dashboard
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, int64) ([]*Dashboard, error)); ok {
|
||||||
|
return rf(ctx, orgID)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, int64) []*Dashboard); ok {
|
||||||
|
r0 = rf(ctx, orgID)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*Dashboard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
|
||||||
|
r1 = rf(ctx, orgID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GetDashboard provides a mock function with given fields: ctx, query
|
// GetDashboard provides a mock function with given fields: ctx, query
|
||||||
func (_m *FakeDashboardService) GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error) {
|
func (_m *FakeDashboardService) GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error) {
|
||||||
ret := _m.Called(ctx, query)
|
ret := _m.Called(ctx, query)
|
||||||
|
@ -1048,6 +1048,21 @@ func (d *dashboardStore) GetAllDashboards(ctx context.Context) ([]*dashboards.Da
|
|||||||
return dashboards, nil
|
return dashboards, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dashboardStore) GetAllDashboardsByOrgId(ctx context.Context, orgID int64) ([]*dashboards.Dashboard, error) {
|
||||||
|
ctx, span := tracer.Start(ctx, "dashboards.database.GetAllDashboardsByOrgId")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
var dashs = make([]*dashboards.Dashboard, 0)
|
||||||
|
err := d.store.WithDbSession(ctx, func(session *db.Session) error {
|
||||||
|
// "deleted IS NULL" is to avoid deleted dashboards
|
||||||
|
return session.Where("org_id = ? AND deleted IS NULL", orgID).Find(&dashs)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dashs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *dashboardStore) GetSoftDeletedExpiredDashboards(ctx context.Context, duration time.Duration) ([]*dashboards.Dashboard, error) {
|
func (d *dashboardStore) GetSoftDeletedExpiredDashboards(ctx context.Context, duration time.Duration) ([]*dashboards.Dashboard, error) {
|
||||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetSoftDeletedExpiredDashboards")
|
ctx, span := tracer.Start(ctx, "dashboards.database.GetSoftDeletedExpiredDashboards")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
@ -266,6 +266,32 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
|
|||||||
assert.Equal(t, len(queryResult), 1)
|
assert.Equal(t, len(queryResult), 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to get all dashboards for an org", func(t *testing.T) {
|
||||||
|
setup()
|
||||||
|
dash1 := insertTestDashboard(t, dashboardStore, "org3test1", 3, 0, "", false, "org 1 test 1")
|
||||||
|
dash2 := insertTestDashboard(t, dashboardStore, "org3test2", 3, 0, "", false, "org 1 test 2")
|
||||||
|
dash3 := insertTestDashboard(t, dashboardStore, "org4test1", 4, 0, "", false, "org 2 test 1")
|
||||||
|
|
||||||
|
dashs, err := dashboardStore.GetAllDashboardsByOrgId(context.Background(), 3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(dashs), 2)
|
||||||
|
uids := []string{}
|
||||||
|
for _, d := range dashs {
|
||||||
|
uids = append(uids, d.UID)
|
||||||
|
}
|
||||||
|
require.Contains(t, uids, dash1.UID)
|
||||||
|
require.Contains(t, uids, dash2.UID)
|
||||||
|
|
||||||
|
dashs, err = dashboardStore.GetAllDashboardsByOrgId(context.Background(), 4)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(dashs), 1)
|
||||||
|
require.Equal(t, dash3.UID, dashs[0].UID)
|
||||||
|
|
||||||
|
dashs, err = dashboardStore.GetAllDashboardsByOrgId(context.Background(), 5)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(dashs), 0)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("Should be able to create dashboard", func(t *testing.T) {
|
t.Run("Should be able to create dashboard", func(t *testing.T) {
|
||||||
setup()
|
setup()
|
||||||
cmd := dashboards.SaveDashboardCommand{
|
cmd := dashboards.SaveDashboardCommand{
|
||||||
|
@ -903,6 +903,14 @@ func (dr *DashboardServiceImpl) GetAllDashboards(ctx context.Context) ([]*dashbo
|
|||||||
return dr.dashboardStore.GetAllDashboards(ctx)
|
return dr.dashboardStore.GetAllDashboards(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dr *DashboardServiceImpl) GetAllDashboardsByOrgId(ctx context.Context, orgID int64) ([]*dashboards.Dashboard, error) {
|
||||||
|
if dr.features.IsEnabledGlobally(featuremgmt.FlagKubernetesCliDashboards) {
|
||||||
|
return dr.listDashboardsThroughK8s(ctx, orgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dr.dashboardStore.GetAllDashboardsByOrgId(ctx, orgID)
|
||||||
|
}
|
||||||
|
|
||||||
func getHitType(item dashboards.DashboardSearchProjection) model.HitType {
|
func getHitType(item dashboards.DashboardSearchProjection) model.HitType {
|
||||||
var hitType model.HitType
|
var hitType model.HitType
|
||||||
if item.IsFolder {
|
if item.IsFolder {
|
||||||
|
@ -515,6 +515,58 @@ func TestGetAllDashboards(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetAllDashboardsByOrgId(t *testing.T) {
|
||||||
|
fakeStore := dashboards.FakeDashboardStore{}
|
||||||
|
defer fakeStore.AssertExpectations(t)
|
||||||
|
service := &DashboardServiceImpl{
|
||||||
|
cfg: setting.NewCfg(),
|
||||||
|
dashboardStore: &fakeStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Should fallback to dashboard store if Kubernetes feature flags are not enabled", func(t *testing.T) {
|
||||||
|
service.features = featuremgmt.WithFeatures()
|
||||||
|
fakeStore.On("GetAllDashboardsByOrgId", mock.Anything).Return([]*dashboards.Dashboard{}, nil).Once()
|
||||||
|
dashboard, err := service.GetAllDashboardsByOrgId(context.Background(), 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, dashboard)
|
||||||
|
fakeStore.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should use Kubernetes client if feature flags are enabled", func(t *testing.T) {
|
||||||
|
ctx, k8sClientMock, k8sResourceMock := setupK8sDashboardTests(service)
|
||||||
|
|
||||||
|
dashboardUnstructured := unstructured.Unstructured{Object: map[string]any{
|
||||||
|
"metadata": map[string]any{
|
||||||
|
"name": "uid",
|
||||||
|
},
|
||||||
|
"spec": map[string]any{
|
||||||
|
"test": "test",
|
||||||
|
"version": int64(1),
|
||||||
|
"title": "testing slugify",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
dashboardExpected := dashboards.Dashboard{
|
||||||
|
UID: "uid", // uid is the name of the k8s object
|
||||||
|
Title: "testing slugify",
|
||||||
|
Slug: "testing-slugify", // slug is taken from title
|
||||||
|
OrgID: 1, // orgID is populated from the query
|
||||||
|
Version: 1, // default to version 1
|
||||||
|
Data: simplejson.NewFromAny(map[string]any{"test": "test", "title": "testing slugify", "uid": "uid", "version": int64(1)}),
|
||||||
|
}
|
||||||
|
|
||||||
|
k8sClientMock.On("getClient", mock.Anything, int64(1)).Return(k8sResourceMock, true).Once()
|
||||||
|
k8sResourceMock.On("List", mock.Anything, mock.Anything).Return(&unstructured.UnstructuredList{Items: []unstructured.Unstructured{dashboardUnstructured}}, nil).Once()
|
||||||
|
|
||||||
|
dashes, err := service.GetAllDashboardsByOrgId(ctx, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, dashes)
|
||||||
|
k8sClientMock.AssertExpectations(t)
|
||||||
|
// make sure the conversion is working
|
||||||
|
require.True(t, reflect.DeepEqual(dashes, []*dashboards.Dashboard{&dashboardExpected}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestSaveDashboard(t *testing.T) {
|
func TestSaveDashboard(t *testing.T) {
|
||||||
fakeStore := dashboards.FakeDashboardStore{}
|
fakeStore := dashboards.FakeDashboardStore{}
|
||||||
defer fakeStore.AssertExpectations(t)
|
defer fakeStore.AssertExpectations(t)
|
||||||
|
@ -208,6 +208,38 @@ func (_m *FakeDashboardStore) GetAllDashboards(ctx context.Context) ([]*Dashboar
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GetAllDashboardsByOrgId provides a mock function with given fields: ctx
|
||||||
|
func (_m *FakeDashboardStore) GetAllDashboardsByOrgId(ctx context.Context, orgID int64) ([]*Dashboard, error) {
|
||||||
|
ret := _m.Called(ctx)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GetAllDashboardsByOrgId")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*Dashboard
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, int64) ([]*Dashboard, error)); ok {
|
||||||
|
return rf(ctx, orgID)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, int64) []*Dashboard); ok {
|
||||||
|
r0 = rf(ctx, orgID)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*Dashboard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
|
||||||
|
r1 = rf(ctx, orgID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// GetDashboard provides a mock function with given fields: ctx, query
|
// GetDashboard provides a mock function with given fields: ctx, query
|
||||||
func (_m *FakeDashboardStore) GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error) {
|
func (_m *FakeDashboardStore) GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error) {
|
||||||
ret := _m.Called(ctx, query)
|
ret := _m.Called(ctx, query)
|
||||||
|
Loading…
Reference in New Issue
Block a user