diff --git a/pkg/services/cloudmigration/api/api.go b/pkg/services/cloudmigration/api/api.go index c7188fbb86f..053b4c2bd7f 100644 --- a/pkg/services/cloudmigration/api/api.go +++ b/pkg/services/cloudmigration/api/api.go @@ -1,9 +1,7 @@ package api import ( - "fmt" "net/http" - "strconv" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/routing" @@ -12,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/services/cloudmigration" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" + "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/web" ) @@ -37,17 +36,17 @@ func RegisterApi( return api } -// RegisterAPIEndpoints Registers Endpoints on Grafana Router +// registerEndpoints Registers Endpoints on Grafana Router func (cma *CloudMigrationAPI) registerEndpoints() { cma.routeRegister.Group("/api/cloudmigration", func(cloudMigrationRoute routing.RouteRegister) { // migration cloudMigrationRoute.Get("/migration", routing.Wrap(cma.GetMigrationList)) cloudMigrationRoute.Post("/migration", routing.Wrap(cma.CreateMigration)) - cloudMigrationRoute.Get("/migration/:id", routing.Wrap(cma.GetMigration)) - cloudMigrationRoute.Delete("/migration/:id", routing.Wrap(cma.DeleteMigration)) - cloudMigrationRoute.Post("/migration/:id/run", routing.Wrap(cma.RunMigration)) - cloudMigrationRoute.Get("/migration/:id/run", routing.Wrap(cma.GetMigrationRunList)) - cloudMigrationRoute.Get("/migration/:id/run/:runID", routing.Wrap(cma.GetMigrationRun)) + cloudMigrationRoute.Get("/migration/:uid", routing.Wrap(cma.GetMigration)) + cloudMigrationRoute.Delete("/migration/:uid", routing.Wrap(cma.DeleteMigration)) + cloudMigrationRoute.Post("/migration/:uid/run", routing.Wrap(cma.RunMigration)) + cloudMigrationRoute.Get("/migration/:uid/run", routing.Wrap(cma.GetMigrationRunList)) + cloudMigrationRoute.Get("/migration/run/:runUID", routing.Wrap(cma.GetMigrationRun)) cloudMigrationRoute.Post("/token", routing.Wrap(cma.CreateToken)) }, middleware.ReqOrgAdmin) } @@ -97,7 +96,7 @@ func (cma *CloudMigrationAPI) GetMigrationList(c *contextmodel.ReqContext) respo return response.JSON(http.StatusOK, cloudMigrations) } -// swagger:route GET /cloudmigration/migration/{id} migrations getCloudMigration +// swagger:route GET /cloudmigration/migration/{uid} migrations getCloudMigration // // Get a cloud migration. // @@ -112,11 +111,12 @@ func (cma *CloudMigrationAPI) GetMigration(c *contextmodel.ReqContext) response. ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.GetMigration") defer span.End() - id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64) - if err != nil { - return response.Error(http.StatusBadRequest, "id is invalid", err) + uid := web.Params(c.Req)[":uid"] + if err := util.ValidateUID(uid); err != nil { + return response.Error(http.StatusBadRequest, "invalid migration uid", err) } - cloudMigration, err := cma.cloudMigrationService.GetMigration(ctx, id) + + cloudMigration, err := cma.cloudMigrationService.GetMigration(ctx, uid) if err != nil { return response.Error(http.StatusNotFound, "migration not found", err) } @@ -125,10 +125,10 @@ func (cma *CloudMigrationAPI) GetMigration(c *contextmodel.ReqContext) response. // swagger:parameters getCloudMigration type GetCloudMigrationRequest struct { - // ID of an migration + // UID of a migration // // in: path - ID int64 `json:"id"` + UID string `json:"uid"` } // swagger:route POST /cloudmigration/migration migrations createMigration @@ -155,7 +155,7 @@ func (cma *CloudMigrationAPI) CreateMigration(c *contextmodel.ReqContext) respon return response.JSON(http.StatusOK, cloudMigration) } -// swagger:route POST /cloudmigration/migration/{id}/run migrations runCloudMigration +// swagger:route POST /cloudmigration/migration/{uid}/run migrations runCloudMigration // // Trigger the run of a migration to the Grafana Cloud. // @@ -170,13 +170,12 @@ func (cma *CloudMigrationAPI) RunMigration(c *contextmodel.ReqContext) response. ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.RunMigration") defer span.End() - stringID := web.Params(c.Req)[":id"] - id, err := strconv.ParseInt(stringID, 10, 64) - if err != nil { - return response.Error(http.StatusBadRequest, "id is invalid", err) + uid := web.Params(c.Req)[":uid"] + if err := util.ValidateUID(uid); err != nil { + return response.Error(http.StatusBadRequest, "invalid migration uid", err) } - result, err := cma.cloudMigrationService.RunMigration(ctx, id) + result, err := cma.cloudMigrationService.RunMigration(ctx, uid) if err != nil { return response.Error(http.StatusInternalServerError, "migration run error", err) } @@ -186,13 +185,13 @@ func (cma *CloudMigrationAPI) RunMigration(c *contextmodel.ReqContext) response. // swagger:parameters runCloudMigration type RunCloudMigrationRequest struct { - // ID of an migration + // UID of a migration // // in: path - ID int64 `json:"id"` + UID string `json:"uid"` } -// swagger:route GET /cloudmigration/migration/{id}/run/{runID} migrations getCloudMigrationRun +// swagger:route GET /cloudmigration/migration/run/{runUID} migrations getCloudMigrationRun // // Get the result of a single migration run. // @@ -205,7 +204,12 @@ func (cma *CloudMigrationAPI) GetMigrationRun(c *contextmodel.ReqContext) respon ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.GetMigrationRun") defer span.End() - migrationStatus, err := cma.cloudMigrationService.GetMigrationStatus(ctx, web.Params(c.Req)[":id"], web.Params(c.Req)[":runID"]) + runUid := web.Params(c.Req)[":runUID"] + if err := util.ValidateUID(runUid); err != nil { + return response.Error(http.StatusBadRequest, "invalid runUID", err) + } + + migrationStatus, err := cma.cloudMigrationService.GetMigrationStatus(ctx, runUid) if err != nil { return response.Error(http.StatusInternalServerError, "migration status error", err) } @@ -221,18 +225,13 @@ func (cma *CloudMigrationAPI) GetMigrationRun(c *contextmodel.ReqContext) respon // swagger:parameters getCloudMigrationRun type GetMigrationRunParams struct { - // ID of an migration + // RunUID of a migration run // // in: path - ID int64 `json:"id"` - - // Run ID of a migration run - // - // in: path - RunID int64 `json:"runID"` + RunUID string `json:"runUID"` } -// swagger:route GET /cloudmigration/migration/{id}/run migrations getCloudMigrationRunList +// swagger:route GET /cloudmigration/migration/{uid}/run migrations getCloudMigrationRunList // // Get a list of migration runs for a migration. // @@ -245,7 +244,12 @@ func (cma *CloudMigrationAPI) GetMigrationRunList(c *contextmodel.ReqContext) re ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.GetMigrationRunList") defer span.End() - runList, err := cma.cloudMigrationService.GetMigrationRunList(ctx, web.Params(c.Req)[":id"]) + uid := web.Params(c.Req)[":uid"] + if err := util.ValidateUID(uid); err != nil { + return response.Error(http.StatusBadRequest, "invalid migration uid", err) + } + + runList, err := cma.cloudMigrationService.GetMigrationRunList(ctx, uid) if err != nil { return response.Error(http.StatusInternalServerError, "list migration status error", err) } @@ -255,13 +259,13 @@ func (cma *CloudMigrationAPI) GetMigrationRunList(c *contextmodel.ReqContext) re // swagger:parameters getCloudMigrationRunList type GetCloudMigrationRunList struct { - // ID of an migration + // UID of a migration // // in: path - ID int64 `json:"id"` + UID string `json:"uid"` } -// swagger:route DELETE /cloudmigration/migration/{id} migrations deleteCloudMigration +// swagger:route DELETE /cloudmigration/migration/{uid} migrations deleteCloudMigration // // Delete a migration. // @@ -274,15 +278,12 @@ func (cma *CloudMigrationAPI) DeleteMigration(c *contextmodel.ReqContext) respon ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.DeleteMigration") defer span.End() - idStr := web.Params(c.Req)[":id"] - if idStr == "" { - return response.Error(http.StatusBadRequest, "missing migration id", fmt.Errorf("missing migration id")) + uid := web.Params(c.Req)[":uid"] + if err := util.ValidateUID(uid); err != nil { + return response.Error(http.StatusBadRequest, "invalid migration uid", err) } - id, err := strconv.ParseInt(idStr, 10, 64) - if err != nil { - return response.Error(http.StatusBadRequest, "migration id should be numeric", fmt.Errorf("migration id should be numeric")) - } - _, err = cma.cloudMigrationService.DeleteMigration(ctx, id) + + _, err := cma.cloudMigrationService.DeleteMigration(ctx, uid) if err != nil { return response.Error(http.StatusInternalServerError, "migration delete error", err) } @@ -291,10 +292,10 @@ func (cma *CloudMigrationAPI) DeleteMigration(c *contextmodel.ReqContext) respon // swagger:parameters deleteCloudMigration type DeleteMigrationRequest struct { - // ID of an migration + // UID of a migration // // in: path - ID int64 `json:"id"` + UID string `json:"uid"` } // swagger:response cloudMigrationRunResponse diff --git a/pkg/services/cloudmigration/cloudmigration.go b/pkg/services/cloudmigration/cloudmigration.go index 7fdf5fff4d8..ea21b691ca9 100644 --- a/pkg/services/cloudmigration/cloudmigration.go +++ b/pkg/services/cloudmigration/cloudmigration.go @@ -9,13 +9,13 @@ type Service interface { ValidateToken(context.Context, CloudMigration) error CreateMigration(context.Context, CloudMigrationRequest) (*CloudMigrationResponse, error) - GetMigration(context.Context, int64) (*CloudMigration, error) - DeleteMigration(context.Context, int64) (*CloudMigration, error) - UpdateMigration(context.Context, int64, CloudMigrationRequest) (*CloudMigrationResponse, error) + GetMigration(ctx context.Context, uid string) (*CloudMigration, error) + DeleteMigration(ctx context.Context, uid string) (*CloudMigration, error) + UpdateMigration(ctx context.Context, uid string, request CloudMigrationRequest) (*CloudMigrationResponse, error) GetMigrationList(context.Context) (*CloudMigrationListResponse, error) - RunMigration(context.Context, int64) (*MigrateDataResponseDTO, error) - SaveMigrationRun(context.Context, *CloudMigrationRun) (int64, error) - GetMigrationStatus(context.Context, string, string) (*CloudMigrationRun, error) + RunMigration(ctx context.Context, uid string) (*MigrateDataResponseDTO, error) + CreateMigrationRun(context.Context, CloudMigrationRun) (string, error) + GetMigrationStatus(ctx context.Context, runUID string) (*CloudMigrationRun, error) GetMigrationRunList(context.Context, string) (*CloudMigrationRunList, error) } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go index f0cd9b4d789..413f65f7f17 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go @@ -6,7 +6,6 @@ import ( "encoding/json" "fmt" "net/http" - "strconv" "time" "github.com/grafana/grafana/pkg/api/response" @@ -238,10 +237,10 @@ func (s *Service) ValidateToken(ctx context.Context, cm cloudmigration.CloudMigr return nil } -func (s *Service) GetMigration(ctx context.Context, id int64) (*cloudmigration.CloudMigration, error) { +func (s *Service) GetMigration(ctx context.Context, uid string) (*cloudmigration.CloudMigration, error) { ctx, span := s.tracer.Start(ctx, "CloudMigrationService.GetMigration") defer span.End() - migration, err := s.store.GetMigration(ctx, id) + migration, err := s.store.GetMigrationByUID(ctx, uid) if err != nil { return nil, err } @@ -258,7 +257,7 @@ func (s *Service) GetMigrationList(ctx context.Context) (*cloudmigration.CloudMi migrations := make([]cloudmigration.CloudMigrationResponse, 0) for _, v := range values { migrations = append(migrations, cloudmigration.CloudMigrationResponse{ - ID: v.ID, + UID: v.UID, Stack: v.Stack, Created: v.Created, Updated: v.Updated, @@ -293,21 +292,21 @@ func (s *Service) CreateMigration(ctx context.Context, cmd cloudmigration.CloudM } return &cloudmigration.CloudMigrationResponse{ - ID: cm.ID, + UID: cm.UID, Stack: token.Instance.Slug, Created: cm.Created, Updated: cm.Updated, }, nil } -func (s *Service) UpdateMigration(ctx context.Context, id int64, cm cloudmigration.CloudMigrationRequest) (*cloudmigration.CloudMigrationResponse, error) { +func (s *Service) UpdateMigration(ctx context.Context, uid string, request cloudmigration.CloudMigrationRequest) (*cloudmigration.CloudMigrationResponse, error) { // TODO: Implement method return nil, nil } -func (s *Service) RunMigration(ctx context.Context, id int64) (*cloudmigration.MigrateDataResponseDTO, error) { +func (s *Service) RunMigration(ctx context.Context, uid string) (*cloudmigration.MigrateDataResponseDTO, error) { // Get migration to read the auth token - migration, err := s.GetMigration(ctx, id) + migration, err := s.GetMigration(ctx, uid) if err != nil { return nil, fmt.Errorf("migration get error: %w", err) } @@ -334,15 +333,15 @@ func (s *Service) RunMigration(ctx context.Context, id int64) (*cloudmigration.M } // save the result of the migration - runID, err := s.SaveMigrationRun(ctx, &cloudmigration.CloudMigrationRun{ - CloudMigrationUID: strconv.Itoa(int(id)), + runUID, err := s.CreateMigrationRun(ctx, cloudmigration.CloudMigrationRun{ + CloudMigrationUID: migration.UID, Result: respData, }) if err != nil { response.Error(http.StatusInternalServerError, "migration run save error", err) } - resp.RunID = runID + resp.RunUID = runUID return resp, nil } @@ -470,29 +469,25 @@ func (s *Service) getDashboards(ctx context.Context) ([]dashboards.Dashboard, er return result, nil } -func (s *Service) SaveMigrationRun(ctx context.Context, cmr *cloudmigration.CloudMigrationRun) (int64, error) { - cmr.Created = time.Now() - cmr.Updated = time.Now() - cmr.Finished = time.Now() - err := s.store.SaveMigrationRun(ctx, cmr) +func (s *Service) CreateMigrationRun(ctx context.Context, cmr cloudmigration.CloudMigrationRun) (string, error) { + uid, err := s.store.CreateMigrationRun(ctx, cmr) if err != nil { s.log.Error("Failed to save migration run", "err", err) - return -1, err + return "", err } - return cmr.ID, nil + return uid, nil } -func (s *Service) GetMigrationStatus(ctx context.Context, id string, runID string) (*cloudmigration.CloudMigrationRun, error) { - cmr, err := s.store.GetMigrationStatus(ctx, id, runID) +func (s *Service) GetMigrationStatus(ctx context.Context, runUID string) (*cloudmigration.CloudMigrationRun, error) { + cmr, err := s.store.GetMigrationStatus(ctx, runUID) if err != nil { return nil, fmt.Errorf("retrieving migration status from db: %w", err) } - return cmr, nil } -func (s *Service) GetMigrationRunList(ctx context.Context, migrationID string) (*cloudmigration.CloudMigrationRunList, error) { - runs, err := s.store.GetMigrationStatusList(ctx, migrationID) +func (s *Service) GetMigrationRunList(ctx context.Context, migUID string) (*cloudmigration.CloudMigrationRunList, error) { + runs, err := s.store.GetMigrationStatusList(ctx, migUID) if err != nil { return nil, fmt.Errorf("retrieving migration statuses from db: %w", err) } @@ -500,15 +495,15 @@ func (s *Service) GetMigrationRunList(ctx context.Context, migrationID string) ( runList := &cloudmigration.CloudMigrationRunList{Runs: []cloudmigration.MigrateDataResponseListDTO{}} for _, s := range runs { runList.Runs = append(runList.Runs, cloudmigration.MigrateDataResponseListDTO{ - RunID: s.ID, + RunUID: s.UID, }) } return runList, nil } -func (s *Service) DeleteMigration(ctx context.Context, id int64) (*cloudmigration.CloudMigration, error) { - c, err := s.store.DeleteMigration(ctx, id) +func (s *Service) DeleteMigration(ctx context.Context, uid string) (*cloudmigration.CloudMigration, error) { + c, err := s.store.DeleteMigration(ctx, uid) if err != nil { return c, fmt.Errorf("deleting migration from db: %w", err) } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go index 5f6e73d7f30..46bf9107ba2 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go @@ -6,7 +6,7 @@ import ( "github.com/grafana/grafana/pkg/services/cloudmigration" ) -// CloudMigrationsServiceImpl Define the Service Implementation. +// NoopServiceImpl Define the Service Implementation. type NoopServiceImpl struct{} var _ cloudmigration.Service = (*NoopServiceImpl)(nil) @@ -22,7 +22,7 @@ func (s *NoopServiceImpl) ValidateToken(ctx context.Context, cm cloudmigration.C return cloudmigration.ErrFeatureDisabledError } -func (s *NoopServiceImpl) GetMigration(ctx context.Context, id int64) (*cloudmigration.CloudMigration, error) { +func (s *NoopServiceImpl) GetMigration(ctx context.Context, uid string) (*cloudmigration.CloudMigration, error) { return nil, cloudmigration.ErrFeatureDisabledError } @@ -34,26 +34,26 @@ func (s *NoopServiceImpl) CreateMigration(ctx context.Context, cm cloudmigration return nil, cloudmigration.ErrFeatureDisabledError } -func (s *NoopServiceImpl) UpdateMigration(ctx context.Context, id int64, cm cloudmigration.CloudMigrationRequest) (*cloudmigration.CloudMigrationResponse, error) { +func (s *NoopServiceImpl) UpdateMigration(ctx context.Context, uid string, cm cloudmigration.CloudMigrationRequest) (*cloudmigration.CloudMigrationResponse, error) { return nil, cloudmigration.ErrFeatureDisabledError } -func (s *NoopServiceImpl) GetMigrationStatus(ctx context.Context, id string, runID string) (*cloudmigration.CloudMigrationRun, error) { +func (s *NoopServiceImpl) GetMigrationStatus(ctx context.Context, runUID string) (*cloudmigration.CloudMigrationRun, error) { return nil, cloudmigration.ErrFeatureDisabledError } -func (s *NoopServiceImpl) GetMigrationRunList(ctx context.Context, id string) (*cloudmigration.CloudMigrationRunList, error) { +func (s *NoopServiceImpl) GetMigrationRunList(ctx context.Context, uid string) (*cloudmigration.CloudMigrationRunList, error) { return nil, cloudmigration.ErrFeatureDisabledError } -func (s *NoopServiceImpl) DeleteMigration(ctx context.Context, id int64) (*cloudmigration.CloudMigration, error) { +func (s *NoopServiceImpl) DeleteMigration(ctx context.Context, uid string) (*cloudmigration.CloudMigration, error) { return nil, cloudmigration.ErrFeatureDisabledError } -func (s *NoopServiceImpl) SaveMigrationRun(ctx context.Context, cmr *cloudmigration.CloudMigrationRun) (int64, error) { - return -1, cloudmigration.ErrInternalNotImplementedError +func (s *NoopServiceImpl) CreateMigrationRun(context.Context, cloudmigration.CloudMigrationRun) (string, error) { + return "", cloudmigration.ErrInternalNotImplementedError } -func (s *NoopServiceImpl) RunMigration(context.Context, int64) (*cloudmigration.MigrateDataResponseDTO, error) { +func (s *NoopServiceImpl) RunMigration(context.Context, string) (*cloudmigration.MigrateDataResponseDTO, error) { return nil, cloudmigration.ErrFeatureDisabledError } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/store.go b/pkg/services/cloudmigration/cloudmigrationimpl/store.go index 01cd94022e6..45f66bb85f2 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/store.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/store.go @@ -8,11 +8,11 @@ import ( type store interface { CreateMigration(ctx context.Context, token cloudmigration.CloudMigration) (*cloudmigration.CloudMigration, error) - GetMigration(context.Context, int64) (*cloudmigration.CloudMigration, error) + GetMigrationByUID(ctx context.Context, uid string) (*cloudmigration.CloudMigration, error) GetAllCloudMigrations(ctx context.Context) ([]*cloudmigration.CloudMigration, error) - DeleteMigration(ctx context.Context, id int64) (*cloudmigration.CloudMigration, error) + DeleteMigration(ctx context.Context, uid string) (*cloudmigration.CloudMigration, error) - SaveMigrationRun(ctx context.Context, cmr *cloudmigration.CloudMigrationRun) error - GetMigrationStatus(ctx context.Context, id string, runID string) (*cloudmigration.CloudMigrationRun, error) - GetMigrationStatusList(ctx context.Context, migrationID string) ([]*cloudmigration.CloudMigrationRun, error) + CreateMigrationRun(ctx context.Context, cmr cloudmigration.CloudMigrationRun) (string, error) + GetMigrationStatus(ctx context.Context, cmrUID string) (*cloudmigration.CloudMigrationRun, error) + GetMigrationStatusList(ctx context.Context, migrationUID string) ([]*cloudmigration.CloudMigrationRun, error) } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go index 0223ce6d9a9..03515604971 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go @@ -4,25 +4,26 @@ import ( "context" "encoding/base64" "fmt" - "strconv" "time" - "github.com/grafana/grafana/pkg/services/secrets" - "github.com/grafana/grafana/pkg/services/sqlstore" - "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/cloudmigration" + "github.com/grafana/grafana/pkg/services/secrets" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/util" ) +var _ store = (*sqlStore)(nil) + type sqlStore struct { db db.DB secretsService secrets.Service } -func (ss *sqlStore) GetMigration(ctx context.Context, id int64) (*cloudmigration.CloudMigration, error) { +func (ss *sqlStore) GetMigrationByUID(ctx context.Context, uid string) (*cloudmigration.CloudMigration, error) { var cm cloudmigration.CloudMigration err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { - exist, err := sess.ID(id).Get(&cm) + exist, err := sess.Where("uid=?", uid).Get(&cm) if err != nil { return err } @@ -39,11 +40,20 @@ func (ss *sqlStore) GetMigration(ctx context.Context, id int64) (*cloudmigration return &cm, err } -func (ss *sqlStore) SaveMigrationRun(ctx context.Context, cmr *cloudmigration.CloudMigrationRun) error { - return ss.db.WithDbSession(ctx, func(sess *db.Session) error { - _, err := sess.Insert(cmr) +func (ss *sqlStore) CreateMigrationRun(ctx context.Context, cmr cloudmigration.CloudMigrationRun) (string, error) { + err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { + cmr.Created = time.Now() + cmr.Updated = time.Now() + cmr.Finished = time.Now() + cmr.UID = util.GenerateShortUID() + + _, err := sess.Insert(&cmr) return err }) + if err != nil { + return "", err + } + return cmr.UID, nil } func (ss *sqlStore) CreateMigration(ctx context.Context, migration cloudmigration.CloudMigration) (*cloudmigration.CloudMigration, error) { @@ -54,6 +64,8 @@ func (ss *sqlStore) CreateMigration(ctx context.Context, migration cloudmigratio err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { migration.Created = time.Now() migration.Updated = time.Now() + migration.UID = util.GenerateShortUID() + _, err := sess.Insert(&migration) if err != nil { return err @@ -83,16 +95,17 @@ func (ss *sqlStore) GetAllCloudMigrations(ctx context.Context) ([]*cloudmigratio return migrations, nil } -func (ss *sqlStore) DeleteMigration(ctx context.Context, id int64) (*cloudmigration.CloudMigration, error) { +func (ss *sqlStore) DeleteMigration(ctx context.Context, uid string) (*cloudmigration.CloudMigration, error) { var c cloudmigration.CloudMigration err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { - exist, err := sess.ID(id).Get(&c) + exist, err := sess.Where("uid=?", uid).Get(&c) if err != nil { return err } if !exist { return cloudmigration.ErrMigrationNotFound } + id := c.ID affected, err := sess.Delete(&cloudmigration.CloudMigration{ ID: id, }) @@ -105,17 +118,10 @@ func (ss *sqlStore) DeleteMigration(ctx context.Context, id int64) (*cloudmigrat return &c, err } -func (ss *sqlStore) GetMigrationStatus(ctx context.Context, migrationID string, runID string) (*cloudmigration.CloudMigrationRun, error) { - id, err := strconv.ParseInt(runID, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid runID: %s", runID) - } - cm := cloudmigration.CloudMigrationRun{ - ID: id, - CloudMigrationUID: migrationID, - } - err = ss.db.WithDbSession(ctx, func(sess *db.Session) error { - exist, err := sess.Get(&cm) +func (ss *sqlStore) GetMigrationStatus(ctx context.Context, cmrUID string) (*cloudmigration.CloudMigrationRun, error) { + var c cloudmigration.CloudMigrationRun + err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { + exist, err := sess.Where("uid=?", cmrUID).Get(&c) if err != nil { return err } @@ -124,21 +130,19 @@ func (ss *sqlStore) GetMigrationStatus(ctx context.Context, migrationID string, } return nil }) - - return &cm, err + return &c, err } -func (ss *sqlStore) GetMigrationStatusList(ctx context.Context, migrationID string) ([]*cloudmigration.CloudMigrationRun, error) { +func (ss *sqlStore) GetMigrationStatusList(ctx context.Context, migrationUID string) ([]*cloudmigration.CloudMigrationRun, error) { var runs = make([]*cloudmigration.CloudMigrationRun, 0) err := ss.db.WithDbSession(ctx, func(sess *db.Session) error { return sess.Find(&runs, &cloudmigration.CloudMigrationRun{ - CloudMigrationUID: migrationID, + CloudMigrationUID: migrationUID, }) }) if err != nil { return nil, err } - return runs, nil } diff --git a/pkg/services/cloudmigration/model.go b/pkg/services/cloudmigration/model.go index 3e34dab4b97..b9c78dca4a1 100644 --- a/pkg/services/cloudmigration/model.go +++ b/pkg/services/cloudmigration/model.go @@ -16,9 +16,10 @@ var ( ErrMigrationNotDeleted = errutil.Internal("cloudmigrations.migrationNotDeleted", errutil.WithPublicMessage("Migration not deleted")) ) -// cloud migration api dtos +// CloudMigration api dtos type CloudMigration struct { ID int64 `json:"id" xorm:"pk autoincr 'id'"` + UID string `json:"uid" xorm:"uid"` AuthToken string `json:"-"` Stack string `json:"stack"` StackID int `json:"stackID" xorm:"stack_id"` @@ -48,7 +49,8 @@ type MigratedResource struct { type CloudMigrationRun struct { ID int64 `json:"id" xorm:"pk autoincr 'id'"` - CloudMigrationUID string `json:"uid" xorm:"cloud_migration_uid"` + UID string `json:"uid" xorm:"uid"` + CloudMigrationUID string `json:"migrationUid" xorm:"cloud_migration_uid"` Result []byte `json:"result"` //store raw cms response body Created time.Time `json:"created"` Updated time.Time `json:"updated"` @@ -61,7 +63,7 @@ func (r CloudMigrationRun) ToResponse() (*MigrateDataResponseDTO, error) { if err != nil { return nil, errors.New("could not parse result of run") } - result.RunID = r.ID + result.RunUID = r.UID return &result, nil } @@ -81,7 +83,7 @@ type CloudMigrationRequest struct { } type CloudMigrationResponse struct { - ID int64 `json:"id"` + UID string `json:"uid"` Stack string `json:"stack"` Created time.Time `json:"created"` Updated time.Time `json:"updated"` @@ -172,12 +174,12 @@ const ( ) type MigrateDataResponseDTO struct { - RunID int64 `json:"id"` - Items []MigrateDataResponseItemDTO `json:"items"` + RunUID string `json:"uid"` + Items []MigrateDataResponseItemDTO `json:"items"` } type MigrateDataResponseListDTO struct { - RunID int64 `json:"id"` + RunUID string `json:"uid"` } type MigrateDataResponseItemDTO struct { diff --git a/pkg/services/sqlstore/migrations/cloud_migrations.go b/pkg/services/sqlstore/migrations/cloud_migrations.go index 231e687b0ac..1f3cffd6ed6 100644 --- a/pkg/services/sqlstore/migrations/cloud_migrations.go +++ b/pkg/services/sqlstore/migrations/cloud_migrations.go @@ -37,4 +37,30 @@ func addCloudMigrationsMigrations(mg *Migrator) { mg.AddMigration("add stack_id column", NewAddColumnMigration(migrationTable, &stackIDColumn)) mg.AddMigration("add region_slug column", NewAddColumnMigration(migrationTable, ®ionSlugColumn)) mg.AddMigration("add cluster_slug column", NewAddColumnMigration(migrationTable, &clusterSlugColumn)) + + // --- adding uid to migration + migUidColumn := Column{Name: "uid", Type: DB_NVarchar, Length: 40, Nullable: true} + mg.AddMigration("add migration uid column", NewAddColumnMigration(migrationTable, &migUidColumn)) + + mg.AddMigration("Update uid column values for migration", NewRawSQLMigration(""). + SQLite("UPDATE cloud_migration SET uid=printf('u%09d',id) WHERE uid IS NULL;"). + Postgres("UPDATE `cloud_migration` SET uid='u' || lpad('' || id::text,9,'0') WHERE uid IS NULL;"). + Mysql("UPDATE cloud_migration SET uid=concat('u',lpad(id,9,'0')) WHERE uid IS NULL;")) + + mg.AddMigration("Add unique index migration_uid", NewAddIndexMigration(migrationTable, &Index{ + Cols: []string{"uid"}, Type: UniqueIndex, + })) + + // --- adding uid to migration run + runUidColumn := Column{Name: "uid", Type: DB_NVarchar, Length: 40, Nullable: true} + mg.AddMigration("add migration run uid column", NewAddColumnMigration(migrationRunTable, &runUidColumn)) + + mg.AddMigration("Update uid column values for migration run", NewRawSQLMigration(""). + SQLite("UPDATE cloud_migration_run SET uid=printf('u%09d',id) WHERE uid IS NULL;"). + Postgres("UPDATE `cloud_migration_run` SET uid='u' || lpad('' || id::text,9,'0') WHERE uid IS NULL;"). + Mysql("UPDATE cloud_migration_run SET uid=concat('u',lpad(id,9,'0')) WHERE uid IS NULL;")) + + mg.AddMigration("Add unique index migration_run_uid", NewAddIndexMigration(migrationRunTable, &Index{ + Cols: []string{"uid"}, Type: UniqueIndex, + })) } diff --git a/public/api-enterprise-spec.json b/public/api-enterprise-spec.json index c539729cf4c..aed0c6c4d92 100644 --- a/public/api-enterprise-spec.json +++ b/public/api-enterprise-spec.json @@ -3070,13 +3070,12 @@ "type": "string", "format": "date-time" }, - "id": { - "type": "integer", - "format": "int64" - }, "stack": { "type": "string" }, + "uid": { + "type": "string" + }, "updated": { "type": "string", "format": "date-time" @@ -3089,7 +3088,7 @@ "runs": { "type": "array", "items": { - "$ref": "#/definitions/MigrateDataResponseDTO" + "$ref": "#/definitions/MigrateDataResponseListDTO" } } } @@ -5166,15 +5165,14 @@ "MigrateDataResponseDTO": { "type": "object", "properties": { - "id": { - "type": "integer", - "format": "int64" - }, "items": { "type": "array", "items": { "$ref": "#/definitions/MigrateDataResponseItemDTO" } + }, + "uid": { + "type": "string" } } }, @@ -5209,6 +5207,14 @@ } } }, + "MigrateDataResponseListDTO": { + "type": "object", + "properties": { + "uid": { + "type": "string" + } + } + }, "MoveFolderCommand": { "description": "MoveFolderCommand captures the information required by the folder service\nto move a folder.", "type": "object", diff --git a/public/api-merged.json b/public/api-merged.json index 62858e50006..b62fb2d60c6 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -2348,7 +2348,39 @@ } } }, - "/cloudmigration/migration/{id}": { + "/cloudmigration/migration/run/{runUID}": { + "get": { + "tags": [ + "migrations" + ], + "summary": "Get the result of a single migration run.", + "operationId": "getCloudMigrationRun", + "parameters": [ + { + "type": "string", + "description": "RunUID of a migration run", + "name": "runUID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/cloudMigrationRunResponse" + }, + "401": { + "$ref": "#/responses/unauthorisedError" + }, + "403": { + "$ref": "#/responses/forbiddenError" + }, + "500": { + "$ref": "#/responses/internalServerError" + } + } + } + }, + "/cloudmigration/migration/{uid}": { "get": { "description": "It returns migrations that has been created.", "tags": [ @@ -2358,10 +2390,9 @@ "operationId": "getCloudMigration", "parameters": [ { - "type": "integer", - "format": "int64", - "description": "ID of an migration", - "name": "id", + "type": "string", + "description": "UID of a migration", + "name": "uid", "in": "path", "required": true } @@ -2389,10 +2420,9 @@ "operationId": "deleteCloudMigration", "parameters": [ { - "type": "integer", - "format": "int64", - "description": "ID of an migration", - "name": "id", + "type": "string", + "description": "UID of a migration", + "name": "uid", "in": "path", "required": true } @@ -2410,7 +2440,7 @@ } } }, - "/cloudmigration/migration/{id}/run": { + "/cloudmigration/migration/{uid}/run": { "get": { "tags": [ "migrations" @@ -2419,10 +2449,9 @@ "operationId": "getCloudMigrationRunList", "parameters": [ { - "type": "integer", - "format": "int64", - "description": "ID of an migration", - "name": "id", + "type": "string", + "description": "UID of a migration", + "name": "uid", "in": "path", "required": true } @@ -2451,51 +2480,9 @@ "operationId": "runCloudMigration", "parameters": [ { - "type": "integer", - "format": "int64", - "description": "ID of an migration", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "$ref": "#/responses/cloudMigrationRunResponse" - }, - "401": { - "$ref": "#/responses/unauthorisedError" - }, - "403": { - "$ref": "#/responses/forbiddenError" - }, - "500": { - "$ref": "#/responses/internalServerError" - } - } - } - }, - "/cloudmigration/migration/{id}/run/{runID}": { - "get": { - "tags": [ - "migrations" - ], - "summary": "Get the result of a single migration run.", - "operationId": "getCloudMigrationRun", - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "ID of an migration", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "integer", - "format": "int64", - "description": "Run ID of a migration run", - "name": "runID", + "type": "string", + "description": "UID of a migration", + "name": "uid", "in": "path", "required": true } @@ -13048,13 +13035,12 @@ "type": "string", "format": "date-time" }, - "id": { - "type": "integer", - "format": "int64" - }, "stack": { "type": "string" }, + "uid": { + "type": "string" + }, "updated": { "type": "string", "format": "date-time" @@ -16216,15 +16202,14 @@ "MigrateDataResponseDTO": { "type": "object", "properties": { - "id": { - "type": "integer", - "format": "int64" - }, "items": { "type": "array", "items": { "$ref": "#/definitions/MigrateDataResponseItemDTO" } + }, + "uid": { + "type": "string" } } }, @@ -16262,9 +16247,8 @@ "MigrateDataResponseListDTO": { "type": "object", "properties": { - "id": { - "type": "integer", - "format": "int64" + "uid": { + "type": "string" } } }, diff --git a/public/app/features/migrate-to-cloud/api/endpoints.gen.ts b/public/app/features/migrate-to-cloud/api/endpoints.gen.ts index 84a8bbafab1..d05960fa5d8 100644 --- a/public/app/features/migrate-to-cloud/api/endpoints.gen.ts +++ b/public/app/features/migrate-to-cloud/api/endpoints.gen.ts @@ -7,20 +7,20 @@ const injectedRtkApi = api.injectEndpoints({ createMigration: build.mutation({ query: (queryArg) => ({ url: `/cloudmigration/migration`, method: 'POST', body: queryArg.cloudMigrationRequest }), }), + getCloudMigrationRun: build.query({ + query: (queryArg) => ({ url: `/cloudmigration/migration/run/${queryArg.runUid}` }), + }), deleteCloudMigration: build.mutation({ - query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.id}`, method: 'DELETE' }), + query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.uid}`, method: 'DELETE' }), }), getCloudMigration: build.query({ - query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.id}` }), + query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.uid}` }), }), getCloudMigrationRunList: build.query({ - query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.id}/run` }), + query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.uid}/run` }), }), runCloudMigration: build.mutation({ - query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.id}/run`, method: 'POST' }), - }), - getCloudMigrationRun: build.query({ - query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.id}/run/${queryArg.runId}` }), + query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.uid}/run`, method: 'POST' }), }), createCloudMigrationToken: build.mutation({ query: () => ({ url: `/cloudmigration/token`, method: 'POST' }), @@ -38,32 +38,30 @@ export type CreateMigrationApiResponse = /** status 200 (empty) */ CloudMigratio export type CreateMigrationApiArg = { cloudMigrationRequest: CloudMigrationRequest; }; +export type GetCloudMigrationRunApiResponse = /** status 200 (empty) */ MigrateDataResponseDto; +export type GetCloudMigrationRunApiArg = { + /** RunUID of a migration run */ + runUid: string; +}; export type DeleteCloudMigrationApiResponse = unknown; export type DeleteCloudMigrationApiArg = { - /** ID of an migration */ - id: number; + /** UID of a migration */ + uid: string; }; export type GetCloudMigrationApiResponse = /** status 200 (empty) */ CloudMigrationResponse; export type GetCloudMigrationApiArg = { - /** ID of an migration */ - id: number; + /** UID of a migration */ + uid: string; }; export type GetCloudMigrationRunListApiResponse = /** status 200 (empty) */ CloudMigrationRunList; export type GetCloudMigrationRunListApiArg = { - /** ID of an migration */ - id: number; + /** UID of a migration */ + uid: string; }; export type RunCloudMigrationApiResponse = /** status 200 (empty) */ MigrateDataResponseDto; export type RunCloudMigrationApiArg = { - /** ID of an migration */ - id: number; -}; -export type GetCloudMigrationRunApiResponse = /** status 200 (empty) */ MigrateDataResponseDto; -export type GetCloudMigrationRunApiArg = { - /** ID of an migration */ - id: number; - /** Run ID of a migration run */ - runId: number; + /** UID of a migration */ + uid: string; }; export type CreateCloudMigrationTokenApiResponse = /** status 200 (empty) */ CreateAccessTokenResponseDto; export type CreateCloudMigrationTokenApiArg = void; @@ -73,8 +71,8 @@ export type GetDashboardByUidApiArg = { }; export type CloudMigrationResponse = { created?: string; - id?: number; stack?: string; + uid?: string; updated?: string; }; export type CloudMigrationListResponse = { @@ -100,11 +98,14 @@ export type MigrateDataResponseItemDto = { type: 'DASHBOARD' | 'DATASOURCE' | 'FOLDER'; }; export type MigrateDataResponseDto = { - id?: number; items?: MigrateDataResponseItemDto[]; + uid?: string; +}; +export type MigrateDataResponseListDto = { + uid?: string; }; export type CloudMigrationRunList = { - runs?: MigrateDataResponseDto[]; + runs?: MigrateDataResponseListDto[]; }; export type CreateAccessTokenResponseDto = { token?: string; @@ -156,11 +157,11 @@ export type DashboardFullWithMeta = { export const { useGetMigrationListQuery, useCreateMigrationMutation, + useGetCloudMigrationRunQuery, useDeleteCloudMigrationMutation, useGetCloudMigrationQuery, useGetCloudMigrationRunListQuery, useRunCloudMigrationMutation, - useGetCloudMigrationRunQuery, useCreateCloudMigrationTokenMutation, useGetDashboardByUidQuery, } = injectedRtkApi; diff --git a/public/app/features/migrate-to-cloud/onprem/Page.tsx b/public/app/features/migrate-to-cloud/onprem/Page.tsx index 87b4638ccaf..01c7b9c0d1b 100644 --- a/public/app/features/migrate-to-cloud/onprem/Page.tsx +++ b/public/app/features/migrate-to-cloud/onprem/Page.tsx @@ -41,12 +41,12 @@ function useGetLatestMigrationDestination() { }; } -function useGetLatestMigrationRun(migrationId?: number) { - const listResult = useGetCloudMigrationRunListQuery(migrationId ? { id: migrationId } : skipToken); +function useGetLatestMigrationRun(migrationUid?: string) { + const listResult = useGetCloudMigrationRunListQuery(migrationUid ? { uid: migrationUid } : skipToken); const latestMigrationRun = listResult.data?.runs?.at(-1); const runResult = useGetCloudMigrationRunQuery( - latestMigrationRun?.id && migrationId ? { runId: latestMigrationRun.id, id: migrationId } : skipToken + latestMigrationRun?.uid && migrationUid ? { runUid: latestMigrationRun.uid } : skipToken ); return { @@ -64,7 +64,7 @@ function useGetLatestMigrationRun(migrationId?: number) { export const Page = () => { const migrationDestination = useGetLatestMigrationDestination(); - const lastMigrationRun = useGetLatestMigrationRun(migrationDestination.data?.id); + const lastMigrationRun = useGetLatestMigrationRun(migrationDestination.data?.uid); const [performRunMigration, runMigrationResult] = useRunCloudMigrationMutation(); const [performDisconnect, disconnectResult] = useDeleteCloudMigrationMutation(); @@ -79,16 +79,16 @@ export const Page = () => { const resources = lastMigrationRun.data?.items; const handleDisconnect = useCallback(() => { - if (migrationDestination.data?.id) { + if (migrationDestination.data?.uid) { performDisconnect({ - id: migrationDestination.data.id, + uid: migrationDestination.data.uid, }); } - }, [migrationDestination.data?.id, performDisconnect]); + }, [migrationDestination.data?.uid, performDisconnect]); const handleStartMigration = useCallback(() => { - if (migrationDestination.data?.id) { - performRunMigration({ id: migrationDestination.data?.id }); + if (migrationDestination.data?.uid) { + performRunMigration({ uid: migrationDestination.data?.uid }); } }, [performRunMigration, migrationDestination]); diff --git a/public/openapi3.json b/public/openapi3.json index 4c6688cc9f9..c541f6c501d 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -3671,13 +3671,12 @@ "format": "date-time", "type": "string" }, - "id": { - "format": "int64", - "type": "integer" - }, "stack": { "type": "string" }, + "uid": { + "type": "string" + }, "updated": { "format": "date-time", "type": "string" @@ -6839,15 +6838,14 @@ }, "MigrateDataResponseDTO": { "properties": { - "id": { - "format": "int64", - "type": "integer" - }, "items": { "items": { "$ref": "#/components/schemas/MigrateDataResponseItemDTO" }, "type": "array" + }, + "uid": { + "type": "string" } }, "type": "object" @@ -6885,9 +6883,8 @@ }, "MigrateDataResponseListDTO": { "properties": { - "id": { - "format": "int64", - "type": "integer" + "uid": { + "type": "string" } }, "type": "object" @@ -14997,18 +14994,51 @@ ] } }, - "/cloudmigration/migration/{id}": { + "/cloudmigration/migration/run/{runUID}": { + "get": { + "operationId": "getCloudMigrationRun", + "parameters": [ + { + "description": "RunUID of a migration run", + "in": "path", + "name": "runUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/cloudMigrationRunResponse" + }, + "401": { + "$ref": "#/components/responses/unauthorisedError" + }, + "403": { + "$ref": "#/components/responses/forbiddenError" + }, + "500": { + "$ref": "#/components/responses/internalServerError" + } + }, + "summary": "Get the result of a single migration run.", + "tags": [ + "migrations" + ] + } + }, + "/cloudmigration/migration/{uid}": { "delete": { "operationId": "deleteCloudMigration", "parameters": [ { - "description": "ID of an migration", + "description": "UID of a migration", "in": "path", - "name": "id", + "name": "uid", "required": true, "schema": { - "format": "int64", - "type": "integer" + "type": "string" } } ], @@ -15033,13 +15063,12 @@ "operationId": "getCloudMigration", "parameters": [ { - "description": "ID of an migration", + "description": "UID of a migration", "in": "path", - "name": "id", + "name": "uid", "required": true, "schema": { - "format": "int64", - "type": "integer" + "type": "string" } } ], @@ -15063,18 +15092,17 @@ ] } }, - "/cloudmigration/migration/{id}/run": { + "/cloudmigration/migration/{uid}/run": { "get": { "operationId": "getCloudMigrationRunList", "parameters": [ { - "description": "ID of an migration", + "description": "UID of a migration", "in": "path", - "name": "id", + "name": "uid", "required": true, "schema": { - "format": "int64", - "type": "integer" + "type": "string" } } ], @@ -15102,13 +15130,12 @@ "operationId": "runCloudMigration", "parameters": [ { - "description": "ID of an migration", + "description": "UID of a migration", "in": "path", - "name": "id", + "name": "uid", "required": true, "schema": { - "format": "int64", - "type": "integer" + "type": "string" } } ], @@ -15132,51 +15159,6 @@ ] } }, - "/cloudmigration/migration/{id}/run/{runID}": { - "get": { - "operationId": "getCloudMigrationRun", - "parameters": [ - { - "description": "ID of an migration", - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - }, - { - "description": "Run ID of a migration run", - "in": "path", - "name": "runID", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/cloudMigrationRunResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get the result of a single migration run.", - "tags": [ - "migrations" - ] - } - }, "/cloudmigration/token": { "post": { "operationId": "createCloudMigrationToken",