Skip to content

Commit

Permalink
feat(instance): add image update command (#2539)
Browse files Browse the repository at this point in the history
  • Loading branch information
yfodil authored Oct 7, 2022
1 parent 30aa3a2 commit 38c93d3
Show file tree
Hide file tree
Showing 12 changed files with 6,346 additions and 0 deletions.
37 changes: 37 additions & 0 deletions cmd/scw/testdata/test-all-usage-instance-image-update-usage.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲
🟥🟥🟥 STDERR️️ 🟥🟥🟥️
Update properties of an instance image.

USAGE:
scw instance image update [arg=value ...]

EXAMPLES:
Update image name
scw instance image update image-id=11111111-1111-1111-1111-111111111111 name=foo

Update image public
scw instance image update image-id=11111111-1111-1111-1111-111111111111 public=true

Add extra volume
scw instance image update image-id=11111111-1111-1111-1111-111111111111 extra-volumes.1.id=11111111-1111-1111-1111-111111111111

ARGS:
image-id
[name]
[arch] (x86_64 | arm)
[extra-volumes.{index}.id] Additional extra-volume ID
[from-server]
[public]
[tags.{index}]
[project] Project ID to use. If none is passed the default project ID will be used
[organization] Organization ID to use. If none is passed the default organization ID will be used
[zone=fr-par-1] Zone to target. If none is passed will use default zone from the config (fr-par-1 | fr-par-2 | fr-par-3 | nl-ams-1 | nl-ams-2 | pl-waw-1)

FLAGS:
-h, --help help for update

GLOBAL FLAGS:
-c, --config string The path to the config file
-D, --debug Enable debug mode
-o, --output string Output format: json or human, see 'scw help output' for more info (default "human")
-p, --profile string The config profile to use
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ AVAILABLE COMMANDS:
delete Delete an instance image
get Get an instance image
list List instance images
update Update an instance image
wait Wait for image to reach a stable state

FLAGS:
Expand Down
49 changes: 49 additions & 0 deletions docs/commands/instance.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Instance API
- [Delete an instance image](#delete-an-instance-image)
- [Get an instance image](#get-an-instance-image)
- [List instance images](#list-instance-images)
- [Update an instance image](#update-an-instance-image)
- [Wait for image to reach a stable state](#wait-for-image-to-reach-a-stable-state)
- [IP management commands](#ip-management-commands)
- [Attach an IP to a given server](#attach-an-ip-to-a-given-server)
Expand Down Expand Up @@ -235,6 +236,54 @@ scw instance image list



### Update an instance image

Update properties of an instance image.

**Usage:**

```
scw instance image update [arg=value ...]
```


**Args:**

| Name | | Description |
|------|---|-------------|
| image-id | Required | |
| name | | |
| arch | One of: `x86_64`, `arm` | |
| extra-volumes.{index}.id | | Additional extra-volume ID |
| from-server | | |
| public | | |
| tags.{index} | | |
| project | | Project ID to use. If none is passed the default project ID will be used |
| organization | | Organization ID to use. If none is passed the default organization ID will be used |
| zone | Default: `fr-par-1`<br />One of: `fr-par-1`, `fr-par-2`, `fr-par-3`, `nl-ams-1`, `nl-ams-2`, `pl-waw-1` | Zone to target. If none is passed will use default zone from the config |


**Examples:**


Update image name
```
scw instance image update image-id=11111111-1111-1111-1111-111111111111 name=foo
```

Update image public
```
scw instance image update image-id=11111111-1111-1111-1111-111111111111 public=true
```

Add extra volume
```
scw instance image update image-id=11111111-1111-1111-1111-111111111111 extra-volumes.1.id=11111111-1111-1111-1111-111111111111
```




### Wait for image to reach a stable state

Wait for image to reach a stable state. This is similar to using --wait flag on other action commands, but without requiring a new action on the image.
Expand Down
1 change: 1 addition & 0 deletions internal/namespaces/instance/v1/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func GetCommands() *core.Commands {
cmds.MustFind("instance", "image", "delete").Override(imageDeleteBuilder)
cmds.Merge(core.NewCommands(
imageWaitCommand(),
imageUpdateCommand(),
))

//
Expand Down
120 changes: 120 additions & 0 deletions internal/namespaces/instance/v1/custom_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/scaleway/scaleway-cli/v2/internal/core"
"github.com/scaleway/scaleway-cli/v2/internal/human"
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
"github.com/scaleway/scaleway-sdk-go/logger"
"github.com/scaleway/scaleway-sdk-go/scw"
)

Expand Down Expand Up @@ -314,6 +315,125 @@ func imageDeleteBuilder(c *core.Command) *core.Command {
return c
}

//
// Commands
//

func imageUpdateCommand() *core.Command {
return &core.Command{
Short: `Update an instance image`,
Long: `Update properties of an instance image.`,
Namespace: "instance",
Resource: "image",
Verb: "update",
ArgsType: reflect.TypeOf(instance.UpdateImageRequest{}),
ArgSpecs: core.ArgSpecs{
{
Name: "image-id",
Required: true,
Positional: false,
},
{
Name: "name",
Required: false,
Positional: false,
},
{
Name: "arch",
Required: false,
Positional: false,
EnumValues: []string{"x86_64", "arm"},
},
{
Name: "extra-volumes.{index}.id",
Short: `Additional extra-volume ID`,
Required: false,
Deprecated: false,
Positional: false,
},
{
Name: "from-server",
Required: false,
Positional: false,
},
{
Name: "public",
Required: false,
Positional: false,
},
{
Name: "tags.{index}",
Required: false,
Positional: false,
},
core.ProjectArgSpec(),
core.OrganizationArgSpec(),
core.ZoneArgSpec(scw.ZoneFrPar1, scw.ZoneFrPar2, scw.ZoneFrPar3, scw.ZoneNlAms1, scw.ZoneNlAms2, scw.ZonePlWaw1),
},
Run: func(ctx context.Context, argsI interface{}) (i interface{}, err error) {
request := argsI.(*instance.UpdateImageRequest)

client := core.ExtractClient(ctx)
api := instance.NewAPI(client)

getImageResponse, err := api.GetImage(&instance.GetImageRequest{
Zone: request.Zone,
ImageID: request.ImageID,
})
if err != nil {
logger.Warningf("cannot get image %s: %s", request.Name, err)
}

if request.Name == nil {
request.Name = &getImageResponse.Image.Name
}
if request.Arch == "" {
request.Arch = getImageResponse.Image.Arch
}
if request.CreationDate == nil {
request.CreationDate = getImageResponse.Image.CreationDate
}
if request.ModificationDate == nil {
request.ModificationDate = getImageResponse.Image.ModificationDate
}
if request.ExtraVolumes == nil {
request.ExtraVolumes = make(map[string]*instance.VolumeTemplate)
for k, v := range getImageResponse.Image.ExtraVolumes {
volume := instance.VolumeTemplate{
ID: v.ID,
Name: v.Name,
Size: v.Size,
VolumeType: v.VolumeType,
}
request.ExtraVolumes[k] = &volume
}
}
if request.RootVolume == nil {
request.RootVolume = getImageResponse.Image.RootVolume
}
if !request.Public && !getImageResponse.Image.Public {
request.Public = getImageResponse.Image.Public
}

return api.UpdateImage(request)
},
Examples: []*core.Example{
{
Short: "Update image name",
Raw: "scw instance image update image-id=11111111-1111-1111-1111-111111111111 name=foo",
},
{
Short: "Update image public",
Raw: "scw instance image update image-id=11111111-1111-1111-1111-111111111111 public=true",
},
{
Short: "Add extra volume",
Raw: "scw instance image update image-id=11111111-1111-1111-1111-111111111111 extra-volumes.1.id=11111111-1111-1111-1111-111111111111",
},
},
}
}

func imageWaitCommand() *core.Command {
return &core.Command{
Short: `Wait for image to reach a stable state`,
Expand Down
58 changes: 58 additions & 0 deletions internal/namespaces/instance/v1/custom_image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,61 @@ func Test_ImageList(t *testing.T) {
AfterFunc: deleteImage("Image"),
}))
}

func Test_ImageUpdate(t *testing.T) {
t.Run("Change name", core.Test(&core.TestConfig{
BeforeFunc: createImage("ImageName"),
Commands: GetCommands(),
Cmd: "scw instance image update image-id={{ .ImageName.Image.ID }} name=foo",
Check: core.TestCheckCombine(
func(t *testing.T, ctx *core.CheckFuncCtx) {
assert.Equal(t, "foo", ctx.Result.(*instance.UpdateImageResponse).Image.Name)
},
core.TestCheckGolden(),
core.TestCheckExitCode(0),
),
AfterFunc: core.AfterFuncCombine(
deleteServer("Server"),
deleteImage("ImageName"),
),
}))

t.Run("Change public from default false to true", core.Test(&core.TestConfig{
BeforeFunc: createImage("ImagePub"),
Commands: GetCommands(),
Cmd: "scw instance image update image-id={{ .ImagePub.Image.ID }} public=true",
Check: core.TestCheckCombine(
func(t *testing.T, ctx *core.CheckFuncCtx) {
assert.Equal(t, true, ctx.Result.(*instance.UpdateImageResponse).Image.Public)
},
core.TestCheckGolden(),
core.TestCheckExitCode(0),
),
AfterFunc: core.AfterFuncCombine(
deleteServer("Server"),
deleteImage("ImagePub"),
),
}))

t.Run("Add extra volume", core.Test(&core.TestConfig{
BeforeFunc: core.BeforeFuncCombine(
createVolume("Volume", 20, instance.VolumeVolumeTypeBSSD),
core.ExecStoreBeforeCmd("SnapshotVol", `scw instance snapshot create -w name=snapVol volume-id={{ .Volume.ID }}`),
createImage("ImageExtraVol"),
),
Commands: GetCommands(),
Cmd: "scw instance image update image-id={{ .ImageExtraVol.Image.ID }} extra-volumes.1.id={{ .SnapshotVol.ID }}",
Check: core.TestCheckCombine(
func(t *testing.T, ctx *core.CheckFuncCtx) {
assert.Equal(t, "snapVol", ctx.Result.(*instance.UpdateImageResponse).Image.ExtraVolumes["1"].Name)
},
core.TestCheckGolden(),
core.TestCheckExitCode(0),
),
AfterFunc: core.AfterFuncCombine(
deleteServer("Server"),
deleteImage("ImageExtraVol"),
deleteVolume("Volume"),
),
}))
}
Loading

0 comments on commit 38c93d3

Please sign in to comment.