From 7ea13bbee1a896b413475de32a0090fce60688ab Mon Sep 17 00:00:00 2001 From: Mathieu Tortuyaux Date: Tue, 23 Apr 2024 15:16:00 +0200 Subject: [PATCH] fix(instance): support snapshot based instance This PR allow users to create an instance from a snapshot directly without creating an image. It's already supported by the APIs. Signed-off-by: Mathieu Tortuyaux --- ...-usage-instance-server-create-usage.golden | 3 ++ .../instance/v1/custom_server_create.go | 44 +++++++++++++------ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/cmd/scw/testdata/test-all-usage-instance-server-create-usage.golden b/cmd/scw/testdata/test-all-usage-instance-server-create-usage.golden index ffff1cc668..c018f45ccb 100644 --- a/cmd/scw/testdata/test-all-usage-instance-server-create-usage.golden +++ b/cmd/scw/testdata/test-all-usage-instance-server-create-usage.golden @@ -21,6 +21,9 @@ EXAMPLES: Create an instance with volumes from snapshots scw instance server create image=ubuntu_focal root-volume=local: additional-volumes.0=block: + Create and start an instance from a snapshot + scw instance server create image=none root-volume=local: + Use an existing IP ip=$(scw instance ip create | grep id | awk '{ print $2 }') scw instance server create image=ubuntu_focal ip=$ip diff --git a/internal/namespaces/instance/v1/custom_server_create.go b/internal/namespaces/instance/v1/custom_server_create.go index 1c7081b5b9..f84167f816 100644 --- a/internal/namespaces/instance/v1/custom_server_create.go +++ b/internal/namespaces/instance/v1/custom_server_create.go @@ -168,6 +168,10 @@ func serverCreateCommand() *core.Command { Short: "Create an instance with volumes from snapshots", ArgsJSON: `{"image":"ubuntu_focal","root_volume":"local:","additional_volumes":["block:"]}`, }, + { + Short: "Create and start an instance from a snapshot", + ArgsJSON: `{"image":"none","root_volume":"local:"}`, + }, { Short: "Use an existing IP", Raw: `ip=$(scw instance ip create | grep id | awk '{ print $2 }') @@ -231,6 +235,8 @@ func instanceServerCreateRun(ctx context.Context, argsI interface{}) (i interfac // - An image label // switch { + case args.Image == "none": + break case !validation.IsUUID(args.Image): // For retro-compatibility, we replace dashes with underscores imageLabel := strings.Replace(args.Image, "-", "_", -1) @@ -250,22 +256,32 @@ func instanceServerCreateRun(ctx context.Context, argsI interface{}) (i interfac serverReq.Image = args.Image } - getImageResponse, err := apiInstance.GetImage(&instance.GetImageRequest{ - Zone: args.Zone, - ImageID: serverReq.Image, - }) - if err != nil { - logger.Warningf("cannot get image %s: %s", serverReq.Image, err) - } + var ( + getImageResponse *instance.GetImageResponse + serverType *instance.ServerType + ) + if args.Image != "none" { + var err error + getImageResponse, err = apiInstance.GetImage(&instance.GetImageRequest{ + Zone: args.Zone, + ImageID: serverReq.Image, + }) + if err != nil { + logger.Warningf("cannot get image %s: %s", serverReq.Image, err) + } - serverType := getServerType(apiInstance, serverReq.Zone, serverReq.CommercialType) + serverType = getServerType(apiInstance, serverReq.Zone, serverReq.CommercialType) - if serverType != nil && getImageResponse != nil { - if err := validateImageServerTypeCompatibility(getImageResponse.Image, serverType, serverReq.CommercialType); err != nil { - return nil, err + if serverType != nil && getImageResponse != nil { + if err := validateImageServerTypeCompatibility(getImageResponse.Image, serverType, serverReq.CommercialType); err != nil { + return nil, err + } + } else { + logger.Warningf("skipping image server-type compatibility validation") } } else { - logger.Warningf("skipping image server-type compatibility validation") + getImageResponse = nil + serverType = nil } // @@ -315,7 +331,7 @@ func instanceServerCreateRun(ctx context.Context, argsI interface{}) (i interfac } // Validate root volume type and size. - if getImageResponse != nil { + if args.Image != "none" && getImageResponse != nil { if err := validateRootVolume(getImageResponse.Image.RootVolume.Size, volumes["0"]); err != nil { return nil, err } @@ -324,7 +340,7 @@ func instanceServerCreateRun(ctx context.Context, argsI interface{}) (i interfac } // Validate total local volume sizes. - if serverType != nil && getImageResponse != nil { + if args.Image != "none" && serverType != nil && getImageResponse != nil { if err := validateLocalVolumeSizes(volumes, serverType, serverReq.CommercialType, getImageResponse.Image.RootVolume.Size); err != nil { return nil, err }