From e2f155f9f7ad8ee8c0518bcd804fd1fa8cacc888 Mon Sep 17 00:00:00 2001 From: idafurjes <36131195+idafurjes@users.noreply.github.com> Date: Mon, 25 Mar 2024 13:30:47 +0100 Subject: [PATCH] Grafana: define the api for the grafana cloudmigration api (not the csm api) (#84430) * Add cloud migration endpoints * Built auth into creating a migration. * Added more detail to the migration result model * goimports * Update pkg/services/cloudmigration/api/api.go Co-authored-by: lean.dev <34773040+leandro-deveikis@users.noreply.github.com> * Update pkg/services/cloudmigration/api/api.go Co-authored-by: lean.dev <34773040+leandro-deveikis@users.noreply.github.com> --------- Co-authored-by: Leonard Gram Co-authored-by: lean.dev <34773040+leandro-deveikis@users.noreply.github.com> --- pkg/services/cloudmigration/api/api.go | 97 +++++++++++++++---- pkg/services/cloudmigration/cloudmigration.go | 20 ++++ .../cloudmigrationimpl/cloudmigration.go | 61 +++++++++++- .../cloudmigrationimpl/cloudmigration_noop.go | 44 +++++++++ .../cloudmigration/cloudmigrations.go | 9 -- pkg/services/cloudmigration/model.go | 49 ++++++++++ 6 files changed, 251 insertions(+), 29 deletions(-) create mode 100644 pkg/services/cloudmigration/cloudmigration.go delete mode 100644 pkg/services/cloudmigration/cloudmigrations.go diff --git a/pkg/services/cloudmigration/api/api.go b/pkg/services/cloudmigration/api/api.go index fb408f09cad..650fdd776ba 100644 --- a/pkg/services/cloudmigration/api/api.go +++ b/pkg/services/cloudmigration/api/api.go @@ -2,6 +2,7 @@ package api import ( "net/http" + "strconv" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/routing" @@ -12,7 +13,7 @@ import ( "github.com/grafana/grafana/pkg/web" ) -type MigrationAPI struct { +type CloudMigrationAPI struct { cloudMigrationsService cloudmigration.Service routeRegister routing.RouteRegister log log.Logger @@ -21,8 +22,8 @@ type MigrationAPI struct { func RegisterApi( rr routing.RouteRegister, cms cloudmigration.Service, -) *MigrationAPI { - api := &MigrationAPI{ +) *CloudMigrationAPI { + api := &CloudMigrationAPI{ log: log.New("cloudmigrations.api"), routeRegister: rr, cloudMigrationsService: cms, @@ -32,25 +33,87 @@ func RegisterApi( } // RegisterAPIEndpoints Registers Endpoints on Grafana Router -func (api *MigrationAPI) registerEndpoints() { - api.routeRegister.Group("/api/cloudmigrations", func(apiRoute routing.RouteRegister) { - apiRoute.Post( - "/migrate_datasources", - routing.Wrap(api.MigrateDatasources), - ) +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)) }, middleware.ReqGrafanaAdmin) } -func (api *MigrationAPI) MigrateDatasources(c *contextmodel.ReqContext) response.Response { - var req cloudmigration.MigrateDatasourcesRequestDTO - if err := web.Bind(c.Req, &req); err != nil { +func (cma *CloudMigrationAPI) CreateToken(c *contextmodel.ReqContext) response.Response { + err := cma.cloudMigrationsService.CreateToken(c.Req.Context()) + if err != nil { + return response.Error(http.StatusInternalServerError, "token creation error", err) + } + return response.Success("Token created") +} + +func (cma *CloudMigrationAPI) GetMigrationList(c *contextmodel.ReqContext) response.Response { + cloudMigrations, err := cma.cloudMigrationsService.GetMigrationList(c.Req.Context()) + if err != nil { + return response.Error(http.StatusInternalServerError, "migration list error", err) + } + return response.JSON(http.StatusOK, cloudMigrations) +} + +func (cma *CloudMigrationAPI) GetMigration(c *contextmodel.ReqContext) response.Response { + id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64) + if err != nil { + return response.Error(http.StatusBadRequest, "id is invalid", err) + } + cloudMigration, err := cma.cloudMigrationsService.GetMigration(c.Req.Context(), id) + if err != nil { + return response.Error(http.StatusNotFound, "migration not found", err) + } + return response.JSON(http.StatusOK, cloudMigration) +} + +func (cma *CloudMigrationAPI) CreateMigration(c *contextmodel.ReqContext) response.Response { + cmd := cloudmigration.CloudMigrationRequest{} + if err := web.Bind(c.Req, &cmd); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) } - - resp, err := api.cloudMigrationsService.MigrateDatasources(c.Req.Context(), &cloudmigration.MigrateDatasourcesRequest{MigrateToPDC: req.MigrateToPDC, MigrateCredentials: req.MigrateCredentials}) + cloudMigration, err := cma.cloudMigrationsService.CreateMigration(c.Req.Context(), cmd) if err != nil { - return response.Error(http.StatusInternalServerError, "data source migrations error", err) + return response.Error(http.StatusInternalServerError, "migration creation error", err) } - - return response.JSON(http.StatusOK, cloudmigration.MigrateDatasourcesResponseDTO{DatasourcesMigrated: resp.DatasourcesMigrated}) + return response.JSON(http.StatusOK, cloudMigration) +} + +func (cma *CloudMigrationAPI) RunMigration(c *contextmodel.ReqContext) response.Response { + cloudMigrationRun, err := cma.cloudMigrationsService.RunMigration(c.Req.Context(), web.Params(c.Req)[":id"]) + if err != nil { + return response.Error(http.StatusInternalServerError, "migration run error", err) + } + return response.JSON(http.StatusOK, cloudMigrationRun) +} + +func (cma *CloudMigrationAPI) GetMigrationRun(c *contextmodel.ReqContext) response.Response { + migrationStatus, err := cma.cloudMigrationsService.GetMigrationStatus(c.Req.Context(), web.Params(c.Req)[":id"], web.Params(c.Req)[":runID"]) + if err != nil { + return response.Error(http.StatusInternalServerError, "migration status error", err) + } + return response.JSON(http.StatusOK, migrationStatus) +} + +func (cma *CloudMigrationAPI) GetMigrationRunList(c *contextmodel.ReqContext) response.Response { + migrationStatus, err := cma.cloudMigrationsService.GetMigrationStatusList(c.Req.Context(), web.Params(c.Req)[":id"]) + if err != nil { + return response.Error(http.StatusInternalServerError, "migration status error", err) + } + return response.JSON(http.StatusOK, migrationStatus) +} + +func (cma *CloudMigrationAPI) DeleteMigration(c *contextmodel.ReqContext) response.Response { + err := cma.cloudMigrationsService.DeleteMigration(c.Req.Context(), web.Params(c.Req)[":id"]) + if err != nil { + return response.Error(http.StatusInternalServerError, "migration delete error", err) + } + return response.Empty(http.StatusOK) } diff --git a/pkg/services/cloudmigration/cloudmigration.go b/pkg/services/cloudmigration/cloudmigration.go new file mode 100644 index 00000000000..c66bbda45ce --- /dev/null +++ b/pkg/services/cloudmigration/cloudmigration.go @@ -0,0 +1,20 @@ +package cloudmigration + +import ( + "context" +) + +type Service interface { + CreateToken(context.Context) error + ValidateToken(context.Context, string) error + SaveEncryptedToken(context.Context, string) error + // migration + GetMigration(context.Context, int64) (*CloudMigrationResponse, error) + GetMigrationList(context.Context) ([]CloudMigrationResponse, error) + CreateMigration(context.Context, CloudMigrationRequest) (*CloudMigrationResponse, error) + UpdateMigration(context.Context, int64, CloudMigrationRequest) (*CloudMigrationResponse, error) + RunMigration(context.Context, string) (*CloudMigrationRun, error) + GetMigrationStatus(context.Context, string, string) (*CloudMigrationRun, error) + GetMigrationStatusList(context.Context, string) ([]CloudMigrationRun, error) + DeleteMigration(context.Context, string) error +} diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go index c1e58e8f397..b66667393b0 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go @@ -24,7 +24,7 @@ type Service struct { features featuremgmt.FeatureToggles dsService datasources.DataSourceService - api *api.MigrationAPI + api *api.CloudMigrationAPI // metrics *Metrics } @@ -62,6 +62,61 @@ func ProvideService( return s } -func (s *Service) MigrateDatasources(ctx context.Context, request *cloudmigration.MigrateDatasourcesRequest) (*cloudmigration.MigrateDatasourcesResponse, error) { - return s.store.MigrateDatasources(ctx, request) +func (s *Service) CreateToken(ctx context.Context) error { + // TODO: Implement method + return nil } + +func (s *Service) ValidateToken(ctx context.Context, token string) error { + // TODO: Implement method + return nil +} + +func (s *Service) SaveEncryptedToken(ctx context.Context, token string) error { + // TODO: Implement method + return nil +} + +func (s *Service) GetMigration(ctx context.Context, id int64) (*cloudmigration.CloudMigrationResponse, error) { + // TODO: Implement method + return nil, nil +} + +func (s *Service) GetMigrationList(ctx context.Context) ([]cloudmigration.CloudMigrationResponse, error) { + // TODO: Implement method + return nil, nil +} + +func (s *Service) CreateMigration(ctx context.Context, cm cloudmigration.CloudMigrationRequest) (*cloudmigration.CloudMigrationResponse, error) { + // TODO: Implement method + return nil, nil +} + +func (s *Service) UpdateMigration(ctx context.Context, id int64, cm cloudmigration.CloudMigrationRequest) (*cloudmigration.CloudMigrationResponse, error) { + // TODO: Implement method + return nil, nil +} + +func (s *Service) RunMigration(ctx context.Context, uid string) (*cloudmigration.CloudMigrationRun, error) { + // TODO: Implement method + return nil, nil +} + +func (s *Service) GetMigrationStatus(ctx context.Context, id string, runID string) (*cloudmigration.CloudMigrationRun, error) { + // TODO: Implement method + return nil, nil +} + +func (s *Service) GetMigrationStatusList(ctx context.Context, id string) ([]cloudmigration.CloudMigrationRun, error) { + // TODO: Implement method + return nil, nil +} + +func (s *Service) DeleteMigration(ctx context.Context, id string) error { + // TODO: Implement method + return nil +} + +// func (s *Service) MigrateDatasources(ctx context.Context, request *cloudmigration.MigrateDatasourcesRequest) (*cloudmigration.MigrateDatasourcesResponse, error) { +// return s.store.MigrateDatasources(ctx, request) +// } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go index 3f22422b7c7..72c3c101327 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go @@ -14,3 +14,47 @@ var _ cloudmigration.Service = (*NoopServiceImpl)(nil) func (s *NoopServiceImpl) MigrateDatasources(ctx context.Context, request *cloudmigration.MigrateDatasourcesRequest) (*cloudmigration.MigrateDatasourcesResponse, error) { return nil, cloudmigration.ErrFeatureDisabledError } + +func (s *NoopServiceImpl) CreateToken(ctx context.Context) error { + return cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) ValidateToken(ctx context.Context, token string) error { + return cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) SaveEncryptedToken(ctx context.Context, token string) error { + return cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) GetMigration(ctx context.Context, id int64) (*cloudmigration.CloudMigrationResponse, error) { + return nil, cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) GetMigrationList(ctx context.Context) ([]cloudmigration.CloudMigrationResponse, error) { + return nil, cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) CreateMigration(ctx context.Context, cm cloudmigration.CloudMigrationRequest) (*cloudmigration.CloudMigrationResponse, error) { + return nil, cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) UpdateMigration(ctx context.Context, id int64, cm cloudmigration.CloudMigrationRequest) (*cloudmigration.CloudMigrationResponse, error) { + return nil, cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) RunMigration(ctx context.Context, uid string) (*cloudmigration.CloudMigrationRun, error) { + return nil, cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) GetMigrationStatus(ctx context.Context, id string, runID string) (*cloudmigration.CloudMigrationRun, error) { + return nil, cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) GetMigrationStatusList(ctx context.Context, id string) ([]cloudmigration.CloudMigrationRun, error) { + return nil, cloudmigration.ErrFeatureDisabledError +} + +func (s *NoopServiceImpl) DeleteMigration(ctx context.Context, id string) error { + return cloudmigration.ErrFeatureDisabledError +} diff --git a/pkg/services/cloudmigration/cloudmigrations.go b/pkg/services/cloudmigration/cloudmigrations.go deleted file mode 100644 index 34bb99c11d3..00000000000 --- a/pkg/services/cloudmigration/cloudmigrations.go +++ /dev/null @@ -1,9 +0,0 @@ -package cloudmigration - -import ( - "context" -) - -type Service interface { - MigrateDatasources(context.Context, *MigrateDatasourcesRequest) (*MigrateDatasourcesResponse, error) -} diff --git a/pkg/services/cloudmigration/model.go b/pkg/services/cloudmigration/model.go index e118abbd5a3..eeb76225d34 100644 --- a/pkg/services/cloudmigration/model.go +++ b/pkg/services/cloudmigration/model.go @@ -1,6 +1,8 @@ package cloudmigration import ( + "time" + "github.com/grafana/grafana/pkg/util/errutil" "github.com/prometheus/client_golang/prometheus" ) @@ -10,6 +12,53 @@ var ( ErrFeatureDisabledError = errutil.Internal("cloudmigrations.disabled", errutil.WithPublicMessage("Cloud migrations are disabled on this instance")) ) +type CloudMigration struct { + ID int64 `json:"id" xorm:"pk autoincr 'id'"` + AuthToken string `json:"authToken"` + Stack string `json:"stack"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` +} + +type MigratedResourceResult struct { + Status string `json:"status"` + Message string `json:"message"` +} + +type MigrationResult struct { + Status string `json:"status"` + Message string `json:"message"` +} + +type MigratedResource struct { + Type string `json:"type"` + ID string `json:"id"` + RefID string `json:"refID"` + Name string `json:"name"` + Result MigratedResourceResult `json:"result"` +} + +type CloudMigrationRun struct { + ID int64 `json:"id" xorm:"pk autoincr 'id'"` + CloudMigrationUID string `json:"uid" xorm:"cloud_migration_uid"` + Resources []MigratedResource `json:"items"` + Result MigrationResult `json:"result"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` + Finished time.Time `json:"finished"` +} + +type CloudMigrationRequest struct { + AuthToken string `json:"authToken"` +} + +type CloudMigrationResponse struct { + ID int64 `json:"id"` + Stack string `json:"stack"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` +} + type MigrateDatasourcesRequest struct { MigrateToPDC bool MigrateCredentials bool