Files
lean.dev 0719f73f35 Cloud Migration: Remove ID migration in favor of UID (#86550)
* - Added migration to add a new collumn UID to both migration and migration_run tables.
- Added migration to set UID for records already existent in the database before adding a new column.
- Added UID field to CloudMigration and CloudMigrationRun dtos (model.go)

* Fix db migration

* Updating store and model

* Updating API to use UID

* fix typo

* update openapi specs and generated endpoints

* fix spec

* update openapi specs and generated endpoints

* Fixing db mapping

* Fix frontend

* fix migration

* remove migration uid from run fetch endpoint

* Revert "merge"

This reverts commit d654e4c530caebe439060c876c44132e74a28de8, reversing
changes made to 5fe0b483eb62cc9dfceb01043d2165617d974ed9.

* manual merge

* rename some funcs for consistency

* make interfaces consistent

* validate uids

* update generated frontend api

* fix enterprise spec

* manually resolve api

* try again

* try yet again

* once more

---------

Co-authored-by: Josh Hunt <joshhunt@users.noreply.github.com>
Co-authored-by: Michael Mandrus <michael.mandrus@grafana.com>
Co-authored-by: joshhunt <josh@trtr.co>
2024-05-01 12:29:25 -04:00

330 lines
10 KiB
Go

package api
import (
"net/http"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"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"
)
type CloudMigrationAPI struct {
cloudMigrationService cloudmigration.Service
routeRegister routing.RouteRegister
log log.Logger
tracer tracing.Tracer
}
func RegisterApi(
rr routing.RouteRegister,
cms cloudmigration.Service,
tracer tracing.Tracer,
) *CloudMigrationAPI {
api := &CloudMigrationAPI{
log: log.New("cloudmigrations.api"),
routeRegister: rr,
cloudMigrationService: cms,
tracer: tracer,
}
api.registerEndpoints()
return api
}
// 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/: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)
}
// swagger:route POST /cloudmigration/token migrations createCloudMigrationToken
//
// Create gcom access token.
//
// Responses:
// 200: cloudMigrationCreateTokenResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (cma *CloudMigrationAPI) CreateToken(c *contextmodel.ReqContext) response.Response {
ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.CreateAccessToken")
defer span.End()
logger := cma.log.FromContext(ctx)
resp, err := cma.cloudMigrationService.CreateToken(ctx)
if err != nil {
logger.Error("creating gcom access token", "err", err.Error())
return response.Error(http.StatusInternalServerError, "creating gcom access token", err)
}
return response.JSON(http.StatusOK, cloudmigration.CreateAccessTokenResponseDTO(resp))
}
// swagger:route GET /cloudmigration/migration migrations getMigrationList
//
// Get a list of all cloud migrations.
//
// Responses:
// 200: cloudMigrationListResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (cma *CloudMigrationAPI) GetMigrationList(c *contextmodel.ReqContext) response.Response {
ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.GetMigrationList")
defer span.End()
cloudMigrations, err := cma.cloudMigrationService.GetMigrationList(ctx)
if err != nil {
return response.Error(http.StatusInternalServerError, "migration list error", err)
}
return response.JSON(http.StatusOK, cloudMigrations)
}
// swagger:route GET /cloudmigration/migration/{uid} migrations getCloudMigration
//
// Get a cloud migration.
//
// It returns migrations that has been created.
//
// Responses:
// 200: cloudMigrationResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (cma *CloudMigrationAPI) GetMigration(c *contextmodel.ReqContext) response.Response {
ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.GetMigration")
defer span.End()
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, uid)
if err != nil {
return response.Error(http.StatusNotFound, "migration not found", err)
}
return response.JSON(http.StatusOK, cloudMigration)
}
// swagger:parameters getCloudMigration
type GetCloudMigrationRequest struct {
// UID of a migration
//
// in: path
UID string `json:"uid"`
}
// swagger:route POST /cloudmigration/migration migrations createMigration
//
// Create a migration.
//
// Responses:
// 200: cloudMigrationResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (cma *CloudMigrationAPI) CreateMigration(c *contextmodel.ReqContext) response.Response {
ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.CreateMigration")
defer span.End()
cmd := cloudmigration.CloudMigrationRequest{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
cloudMigration, err := cma.cloudMigrationService.CreateMigration(ctx, cmd)
if err != nil {
return response.Error(http.StatusInternalServerError, "migration creation error", err)
}
return response.JSON(http.StatusOK, cloudMigration)
}
// swagger:route POST /cloudmigration/migration/{uid}/run migrations runCloudMigration
//
// Trigger the run of a migration to the Grafana Cloud.
//
// It returns migrations that has been created.
//
// Responses:
// 200: cloudMigrationRunResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (cma *CloudMigrationAPI) RunMigration(c *contextmodel.ReqContext) response.Response {
ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.RunMigration")
defer span.End()
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, uid)
if err != nil {
return response.Error(http.StatusInternalServerError, "migration run error", err)
}
return response.JSON(http.StatusOK, result)
}
// swagger:parameters runCloudMigration
type RunCloudMigrationRequest struct {
// UID of a migration
//
// in: path
UID string `json:"uid"`
}
// swagger:route GET /cloudmigration/migration/run/{runUID} migrations getCloudMigrationRun
//
// Get the result of a single migration run.
//
// Responses:
// 200: cloudMigrationRunResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (cma *CloudMigrationAPI) GetMigrationRun(c *contextmodel.ReqContext) response.Response {
ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.GetMigrationRun")
defer span.End()
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)
}
runResponse, err := migrationStatus.ToResponse()
if err != nil {
cma.log.Error("could not return migration run", "err", err)
return response.Error(http.StatusInternalServerError, "migration run get error", err)
}
return response.JSON(http.StatusOK, runResponse)
}
// swagger:parameters getCloudMigrationRun
type GetMigrationRunParams struct {
// RunUID of a migration run
//
// in: path
RunUID string `json:"runUID"`
}
// swagger:route GET /cloudmigration/migration/{uid}/run migrations getCloudMigrationRunList
//
// Get a list of migration runs for a migration.
//
// Responses:
// 200: cloudMigrationRunListResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (cma *CloudMigrationAPI) GetMigrationRunList(c *contextmodel.ReqContext) response.Response {
ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.GetMigrationRunList")
defer span.End()
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)
}
return response.JSON(http.StatusOK, runList)
}
// swagger:parameters getCloudMigrationRunList
type GetCloudMigrationRunList struct {
// UID of a migration
//
// in: path
UID string `json:"uid"`
}
// swagger:route DELETE /cloudmigration/migration/{uid} migrations deleteCloudMigration
//
// Delete a migration.
//
// Responses:
// 200
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
func (cma *CloudMigrationAPI) DeleteMigration(c *contextmodel.ReqContext) response.Response {
ctx, span := cma.tracer.Start(c.Req.Context(), "MigrationAPI.DeleteMigration")
defer span.End()
uid := web.Params(c.Req)[":uid"]
if err := util.ValidateUID(uid); err != nil {
return response.Error(http.StatusBadRequest, "invalid migration uid", err)
}
_, err := cma.cloudMigrationService.DeleteMigration(ctx, uid)
if err != nil {
return response.Error(http.StatusInternalServerError, "migration delete error", err)
}
return response.Empty(http.StatusOK)
}
// swagger:parameters deleteCloudMigration
type DeleteMigrationRequest struct {
// UID of a migration
//
// in: path
UID string `json:"uid"`
}
// swagger:response cloudMigrationRunResponse
type CloudMigrationRunResponse struct {
// in: body
Body cloudmigration.MigrateDataResponseDTO
}
// swagger:response cloudMigrationListResponse
type CloudMigrationListResponse struct {
// in: body
Body cloudmigration.CloudMigrationListResponse
}
// swagger:response cloudMigrationResponse
type CloudMigrationResponse struct {
// in: body
Body cloudmigration.CloudMigrationResponse
}
// swagger:response cloudMigrationRunListResponse
type CloudMigrationRunListResponse struct {
// in: body
Body cloudmigration.CloudMigrationRunList
}
// swagger:response cloudMigrationCreateTokenResponse
type CloudMigrationCreateTokenResponse struct {
// in: body
Body cloudmigration.CreateAccessTokenResponseDTO
}