mirror of
https://github.com/grafana/grafana.git
synced 2026-08-26 21:37:31 -05:00
CloudMigration: Provide a stats rollup in the GetSnapshot response (#90252)
* order session list descending * add snapshot status method to store * query stats while retrieving snapshot * return stats in dto * swagger * fix tests * commit results of bingo get * fix swagger * minor improvement * fix typo * forgot a file
This commit is contained in:
@@ -442,6 +442,17 @@ func (cma *CloudMigrationAPI) GetSnapshot(c *contextmodel.ReqContext) response.R
|
||||
}
|
||||
}
|
||||
|
||||
dtoStats := SnapshotResourceStats{
|
||||
Types: make(map[MigrateDataType]int, len(snapshot.StatsRollup.CountsByStatus)),
|
||||
Statuses: make(map[ItemStatus]int, len(snapshot.StatsRollup.CountsByType)),
|
||||
}
|
||||
for s, c := range snapshot.StatsRollup.CountsByStatus {
|
||||
dtoStats.Statuses[ItemStatus(s)] = c
|
||||
}
|
||||
for s, c := range snapshot.StatsRollup.CountsByType {
|
||||
dtoStats.Types[MigrateDataType(s)] = c
|
||||
}
|
||||
|
||||
respDto := GetSnapshotResponseDTO{
|
||||
SnapshotDTO: SnapshotDTO{
|
||||
SnapshotUID: snapshot.UID,
|
||||
@@ -450,7 +461,8 @@ func (cma *CloudMigrationAPI) GetSnapshot(c *contextmodel.ReqContext) response.R
|
||||
Created: snapshot.Created,
|
||||
Finished: snapshot.Finished,
|
||||
},
|
||||
Results: dtoResults,
|
||||
Results: dtoResults,
|
||||
StatsRollup: dtoStats,
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, respDto)
|
||||
|
||||
@@ -471,7 +471,7 @@ func TestCloudMigrationAPI_GetSnapshot(t *testing.T) {
|
||||
requestUrl: "/api/cloudmigration/migration/1234/snapshot/1",
|
||||
basicRole: org.RoleAdmin,
|
||||
expectedHttpResult: http.StatusOK,
|
||||
expectedBody: `{"uid":"fake_uid","status":"UNKNOWN","sessionUid":"1234","created":"0001-01-01T00:00:00Z","finished":"0001-01-01T00:00:00Z","results":[]}`,
|
||||
expectedBody: `{"uid":"fake_uid","status":"UNKNOWN","sessionUid":"1234","created":"0001-01-01T00:00:00Z","finished":"0001-01-01T00:00:00Z","results":[],"stats":{"types":{},"statuses":{}}}`,
|
||||
},
|
||||
{
|
||||
desc: "should return 403 if no used is not admin",
|
||||
|
||||
@@ -299,7 +299,13 @@ type GetSnapshotResponse struct {
|
||||
|
||||
type GetSnapshotResponseDTO struct {
|
||||
SnapshotDTO
|
||||
Results []MigrateDataResponseItemDTO `json:"results"`
|
||||
Results []MigrateDataResponseItemDTO `json:"results"`
|
||||
StatsRollup SnapshotResourceStats `json:"stats"`
|
||||
}
|
||||
|
||||
type SnapshotResourceStats struct {
|
||||
Types map[MigrateDataType]int `json:"types"`
|
||||
Statuses map[ItemStatus]int `json:"statuses"`
|
||||
}
|
||||
|
||||
// swagger:parameters getShapshotList
|
||||
|
||||
@@ -332,7 +332,7 @@ func (s *Service) GetSession(ctx context.Context, uid string) (*cloudmigration.C
|
||||
}
|
||||
|
||||
func (s *Service) GetSessionList(ctx context.Context) (*cloudmigration.CloudMigrationSessionListResponse, error) {
|
||||
values, err := s.store.GetAllCloudMigrationSessions(ctx)
|
||||
values, err := s.store.GetCloudMigrationSessionList(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
type store interface {
|
||||
CreateMigrationSession(ctx context.Context, session cloudmigration.CloudMigrationSession) (*cloudmigration.CloudMigrationSession, error)
|
||||
GetMigrationSessionByUID(ctx context.Context, uid string) (*cloudmigration.CloudMigrationSession, error)
|
||||
GetAllCloudMigrationSessions(ctx context.Context) ([]*cloudmigration.CloudMigrationSession, error)
|
||||
GetCloudMigrationSessionList(ctx context.Context) ([]*cloudmigration.CloudMigrationSession, error)
|
||||
DeleteMigrationSessionByUID(ctx context.Context, uid string) (*cloudmigration.CloudMigrationSession, error)
|
||||
|
||||
CreateMigrationRun(ctx context.Context, cmr cloudmigration.CloudMigrationSnapshot) (string, error)
|
||||
@@ -23,5 +23,6 @@ type store interface {
|
||||
|
||||
CreateUpdateSnapshotResources(ctx context.Context, snapshotUid string, resources []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)
|
||||
DeleteSnapshotResources(ctx context.Context, snapshotUid string) error
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ type sqlStore struct {
|
||||
secretsService secrets.Service
|
||||
}
|
||||
|
||||
const (
|
||||
tableName = "cloud_migration_resource"
|
||||
)
|
||||
|
||||
func (ss *sqlStore) GetMigrationSessionByUID(ctx context.Context, uid string) (*cloudmigration.CloudMigrationSession, error) {
|
||||
var cm cloudmigration.CloudMigrationSession
|
||||
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
@@ -78,9 +82,12 @@ func (ss *sqlStore) CreateMigrationSession(ctx context.Context, migration cloudm
|
||||
return &migration, nil
|
||||
}
|
||||
|
||||
func (ss *sqlStore) GetAllCloudMigrationSessions(ctx context.Context) ([]*cloudmigration.CloudMigrationSession, error) {
|
||||
func (ss *sqlStore) GetCloudMigrationSessionList(ctx context.Context) ([]*cloudmigration.CloudMigrationSession, error) {
|
||||
var migrations = make([]*cloudmigration.CloudMigrationSession, 0)
|
||||
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { return sess.Find(&migrations) })
|
||||
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
sess.OrderBy("created DESC")
|
||||
return sess.Find(&migrations)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -227,6 +234,10 @@ func (ss *sqlStore) GetSnapshotByUID(ctx context.Context, uid string, resultPage
|
||||
if err == nil {
|
||||
snapshot.Resources = resources
|
||||
}
|
||||
stats, err := ss.GetSnapshotResourceStats(ctx, uid)
|
||||
if err == nil {
|
||||
snapshot.StatsRollup = *stats
|
||||
}
|
||||
|
||||
return &snapshot, err
|
||||
}
|
||||
@@ -249,6 +260,12 @@ func (ss *sqlStore) GetSnapshotList(ctx context.Context, query cloudmigration.Li
|
||||
if err := ss.decryptKey(ctx, &snapshot); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stats, err := ss.GetSnapshotResourceStats(ctx, snapshot.UID); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
snapshot.StatsRollup = *stats
|
||||
}
|
||||
snapshots[i] = snapshot
|
||||
}
|
||||
return snapshots, nil
|
||||
@@ -309,6 +326,46 @@ func (ss *sqlStore) GetSnapshotResources(ctx context.Context, snapshotUid string
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
func (ss *sqlStore) GetSnapshotResourceStats(ctx context.Context, snapshotUid string) (*cloudmigration.SnapshotResourceStats, error) {
|
||||
typeCounts := make([]struct {
|
||||
Count int `json:"count"`
|
||||
Type string `json:"type"`
|
||||
}, 0)
|
||||
statusCounts := make([]struct {
|
||||
Count int `json:"count"`
|
||||
Status string `json:"status"`
|
||||
}, 0)
|
||||
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
sess.Select("count(uid) as 'count', resource_type as 'type'").
|
||||
Table(tableName).
|
||||
GroupBy("type").
|
||||
Where("snapshot_uid = ?", snapshotUid)
|
||||
if err := sess.Find(&typeCounts); err != nil {
|
||||
return err
|
||||
}
|
||||
sess.Select("count(uid) as 'count', status").
|
||||
Table(tableName).
|
||||
GroupBy("status").
|
||||
Where("snapshot_uid = ?", snapshotUid)
|
||||
return sess.Find(&statusCounts)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats := &cloudmigration.SnapshotResourceStats{
|
||||
CountsByType: make(map[cloudmigration.MigrateDataType]int, len(typeCounts)),
|
||||
CountsByStatus: make(map[cloudmigration.ItemStatus]int, len(statusCounts)),
|
||||
}
|
||||
for _, c := range typeCounts {
|
||||
stats.CountsByType[cloudmigration.MigrateDataType(c.Type)] = c.Count
|
||||
}
|
||||
for _, c := range statusCounts {
|
||||
stats.CountsByStatus[cloudmigration.ItemStatus(c.Status)] = c.Count
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func (ss *sqlStore) DeleteSnapshotResources(ctx context.Context, snapshotUid string) error {
|
||||
return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
_, err := sess.Delete(cloudmigration.CloudMigrationResource{
|
||||
|
||||
@@ -25,7 +25,7 @@ func Test_GetAllCloudMigrationSessions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("get all cloud_migration_session entries", func(t *testing.T) {
|
||||
value, err := s.GetAllCloudMigrationSessions(ctx)
|
||||
value, err := s.GetCloudMigrationSessionList(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 3, len(value))
|
||||
for _, m := range value {
|
||||
@@ -245,6 +245,19 @@ func Test_SnapshotResources(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// check stats
|
||||
stats, err := s.GetSnapshotResourceStats(ctx, "poiuy")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, map[cloudmigration.MigrateDataType]int{
|
||||
cloudmigration.DatasourceDataType: 2,
|
||||
cloudmigration.DashboardDataType: 1,
|
||||
cloudmigration.FolderDataType: 1,
|
||||
}, stats.CountsByType)
|
||||
assert.Equal(t, map[cloudmigration.ItemStatus]int{
|
||||
cloudmigration.ItemStatusOK: 3,
|
||||
cloudmigration.ItemStatusPending: 1,
|
||||
}, stats.CountsByStatus)
|
||||
|
||||
// delete snapshot resources
|
||||
err = s.DeleteSnapshotResources(ctx, "poiuy")
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -17,6 +17,8 @@ var (
|
||||
)
|
||||
|
||||
// CloudMigration domain structs
|
||||
|
||||
// CloudMigrationSession represents a configured migration token
|
||||
type CloudMigrationSession struct {
|
||||
ID int64 `xorm:"pk autoincr 'id'"`
|
||||
UID string `xorm:"uid"`
|
||||
@@ -29,6 +31,7 @@ type CloudMigrationSession struct {
|
||||
Updated time.Time
|
||||
}
|
||||
|
||||
// CloudMigrationSnapshot contains all of the metadata about a snapshot
|
||||
type CloudMigrationSnapshot struct {
|
||||
ID int64 `xorm:"pk autoincr 'id'"`
|
||||
UID string `xorm:"uid"`
|
||||
@@ -45,6 +48,8 @@ type CloudMigrationSnapshot struct {
|
||||
|
||||
// Stored in the cloud_migration_resource table
|
||||
Resources []CloudMigrationResource `xorm:"-"`
|
||||
// Derived by querying the cloud_migration_resource table
|
||||
StatsRollup SnapshotResourceStats `xorm:"-"`
|
||||
}
|
||||
|
||||
type SnapshotStatus string
|
||||
@@ -73,6 +78,28 @@ type CloudMigrationResource struct {
|
||||
SnapshotUID string `xorm:"snapshot_uid"`
|
||||
}
|
||||
|
||||
type MigrateDataType string
|
||||
|
||||
const (
|
||||
DashboardDataType MigrateDataType = "DASHBOARD"
|
||||
DatasourceDataType MigrateDataType = "DATASOURCE"
|
||||
FolderDataType MigrateDataType = "FOLDER"
|
||||
)
|
||||
|
||||
type ItemStatus string
|
||||
|
||||
const (
|
||||
ItemStatusOK ItemStatus = "OK"
|
||||
ItemStatusError ItemStatus = "ERROR"
|
||||
ItemStatusPending ItemStatus = "PENDING"
|
||||
ItemStatusUnknown ItemStatus = "UNKNOWN"
|
||||
)
|
||||
|
||||
type SnapshotResourceStats struct {
|
||||
CountsByType map[MigrateDataType]int
|
||||
CountsByStatus map[ItemStatus]int
|
||||
}
|
||||
|
||||
// Deprecated, use GetSnapshotResult for the async workflow
|
||||
func (s CloudMigrationSnapshot) GetResult() (*MigrateDataResponse, error) {
|
||||
result := MigrateDataResponse{
|
||||
@@ -154,14 +181,6 @@ type Base64HGInstance struct {
|
||||
|
||||
// GMS domain structs
|
||||
|
||||
type MigrateDataType string
|
||||
|
||||
const (
|
||||
DashboardDataType MigrateDataType = "DASHBOARD"
|
||||
DatasourceDataType MigrateDataType = "DATASOURCE"
|
||||
FolderDataType MigrateDataType = "FOLDER"
|
||||
)
|
||||
|
||||
type MigrateDataRequest struct {
|
||||
Items []MigrateDataRequestItem
|
||||
}
|
||||
@@ -173,15 +192,6 @@ type MigrateDataRequestItem struct {
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
type ItemStatus string
|
||||
|
||||
const (
|
||||
ItemStatusOK ItemStatus = "OK"
|
||||
ItemStatusError ItemStatus = "ERROR"
|
||||
ItemStatusPending ItemStatus = "PENDING"
|
||||
ItemStatusUnknown ItemStatus = "UNKNOWN"
|
||||
)
|
||||
|
||||
type MigrateDataResponse struct {
|
||||
RunUID string
|
||||
Items []CloudMigrationResource
|
||||
|
||||
Reference in New Issue
Block a user