Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200211104822-047c88bb15c4 h1:7MhGZPXmbEqx97kIrBA7Xen1obsqQPnR0HKErxh76S4=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200211104822-047c88bb15c4/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200212160027-75ab2f6aeda3 h1:BQb9gbsenI8ZwZmfN7O93VrlXW8eiDlL7Mz+glsK/os=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200212160027-75ab2f6aeda3/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
Expand Down
21 changes: 20 additions & 1 deletion internal/core/arg_specs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package core

import "github.com/scaleway/scaleway-sdk-go/scw"
import (
"fmt"

"github.com/scaleway/scaleway-sdk-go/scw"
)

type ArgSpecs []*ArgSpec

Expand All @@ -20,6 +24,21 @@ func (s *ArgSpecs) DeleteByName(name string) {
return
}
}
panic(fmt.Errorf("in DeleteByName: %s not found", name))
}

func (s *ArgSpecs) AddBefore(name string, argSpec *ArgSpec) {
for i, spec := range *s {
if spec.Name == name {
newSpecs := ArgSpecs(nil)
newSpecs = append(newSpecs, (*s)[:i]...)
newSpecs = append(newSpecs, argSpec)
newSpecs = append(newSpecs, (*s)[i:]...)
*s = newSpecs
return
}
}
panic(fmt.Errorf("in AddBefore: %s not found", name))
}

type ArgSpec struct {
Expand Down
58 changes: 42 additions & 16 deletions internal/namespaces/instance/v1/custom_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net"
"reflect"
"sort"
"strconv"
"time"

"github.com/fatih/color"
Expand Down Expand Up @@ -178,28 +179,43 @@ func serverUpdateBuilder(c *core.Command) *core.Command {
*instance.UpdateServerRequest
IP *instance.NullableStringValue
PlacementGroupID *instance.NullableStringValue
SecurityGroupID string
SecurityGroupID *string
VolumeIDs *[]string
}

IPArgSpec := &core.ArgSpec{
Name: "ip",
Short: `IP that should be attached to the server (use ip=none to remove)`,
}
c.ArgSpecs.GetByName("placement-group").Name = "placement-group-id"

c.ArgsType = reflect.TypeOf(instanceUpdateServerRequestCustom{})

c.ArgSpecs = append(c.ArgSpecs, IPArgSpec)
c.ArgSpecs.DeleteByName("security-group.name")
// Rename modified arg specs.
c.ArgSpecs.GetByName("placement-group").Name = "placement-group-id"
c.ArgSpecs.GetByName("security-group.id").Name = "security-group-id"

// Delete unused arg specs.
c.ArgSpecs.DeleteByName("security-group.name")
c.ArgSpecs.DeleteByName("volumes.{key}.name")
c.ArgSpecs.DeleteByName("volumes.{key}.size")
c.ArgSpecs.DeleteByName("volumes.{key}.id")
c.ArgSpecs.DeleteByName("volumes.{key}.volume-type")
c.ArgSpecs.DeleteByName("volumes.{key}.organization")

// Add new arg specs.
c.ArgSpecs.AddBefore("placement-group-id", &core.ArgSpec{
Name: "volume-ids.{index}",
Short: "Will update ALL volume IDs at once, including the root volume of the server (use volume-ids=none to detach all volumes)",
})
c.ArgSpecs.AddBefore("boot-type", &core.ArgSpec{
Name: "ip",
Short: `IP that should be attached to the server (use ip=none to detach)`,
})

c.Run = func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
customRequest := argsI.(*instanceUpdateServerRequestCustom)

updateServerRequest := customRequest.UpdateServerRequest
updateServerRequest.PlacementGroup = customRequest.PlacementGroupID
updateServerRequest.SecurityGroup = &instance.SecurityGroupTemplate{
ID: customRequest.SecurityGroupID,
if customRequest.SecurityGroupID != nil {
updateServerRequest.SecurityGroup = &instance.SecurityGroupTemplate{
ID: *customRequest.SecurityGroupID,
}
}

attachIPRequest := (*instance.UpdateIPRequest)(nil)
Expand All @@ -210,11 +226,11 @@ func serverUpdateBuilder(c *core.Command) *core.Command {
api := instance.NewAPI(client)

getServerResponse, err := api.GetServer(&instance.GetServerRequest{
Zone: "",
Zone: updateServerRequest.Zone,
ServerID: customRequest.ServerID,
})
if err != nil {
return "", err
return nil, err
}

switch {
Expand Down Expand Up @@ -255,20 +271,30 @@ func serverUpdateBuilder(c *core.Command) *core.Command {
},
})
if err != nil {
return "", err
return nil, err
}
}

if attachIPRequest != nil {
_, err = api.UpdateIP(attachIPRequest)
if err != nil {
return "", err
return nil, err
}
}

// Update all volume IDs at once.
if customRequest.VolumeIDs != nil {
volumes := make(map[string]*instance.VolumeTemplate)
for i, volumeID := range *customRequest.VolumeIDs {
index := strconv.Itoa(i)
volumes[index] = &instance.VolumeTemplate{ID: volumeID, Name: getServerResponse.Server.Name + "-" + index}
}
customRequest.Volumes = &volumes
}

updateServerResponse, err := api.UpdateServer(updateServerRequest)
if err != nil {
return "", err
return nil, err
}

return updateServerResponse, nil
Expand Down
40 changes: 40 additions & 0 deletions internal/namespaces/instance/v1/custom_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ func Test_ServerVolumeUpdate(t *testing.T) {
}

func Test_ServerUpdateCustom(t *testing.T) {

// IP cases.
t.Run("Try to remove ip from server without ip", core.Test(&core.TestConfig{
Commands: GetCommands(),
BeforeFunc: func(ctx *core.BeforeFuncCtx) error {
Expand Down Expand Up @@ -184,6 +186,7 @@ func Test_ServerUpdateCustom(t *testing.T) {
},
}))

// Placement group cases.
t.Run("Update server placement-group-id from server with placement-group-id", core.Test(&core.TestConfig{
Commands: GetCommands(),
BeforeFunc: func(ctx *core.BeforeFuncCtx) error {
Expand All @@ -209,6 +212,7 @@ func Test_ServerUpdateCustom(t *testing.T) {
},
}))

// Security group cases.
t.Run("Update server security-group-id from server with security-group-id", core.Test(&core.TestConfig{
Commands: GetCommands(),
BeforeFunc: func(ctx *core.BeforeFuncCtx) error {
Expand All @@ -233,4 +237,40 @@ func Test_ServerUpdateCustom(t *testing.T) {
return nil
},
}))

// Volumes cases.
t.Run("Volumes", func(t *testing.T) {
t.Run("valid simple block volume", core.Test(&core.TestConfig{
Commands: GetCommands(),
BeforeFunc: func(ctx *core.BeforeFuncCtx) error {
ctx.Meta["Response"] = ctx.ExecuteCmd("scw instance volume create name=cli-test size=10G volume-type=b_ssd")
return createVanillaServer(ctx)
},
Cmd: `scw instance server update server-id={{ .Server.ID }} volume-ids.0={{ (index .Server.Volumes "0").ID }} volume-ids.1={{ .Response.Volume.ID }}`,
Check: func(t *testing.T, ctx *core.CheckFuncCtx) {
require.NoError(t, ctx.Err)
assert.Equal(t, 20*scw.GB, ctx.Result.(*instance.UpdateServerResponse).Server.Volumes["0"].Size)
assert.Equal(t, 10*scw.GB, ctx.Result.(*instance.UpdateServerResponse).Server.Volumes["1"].Size)
},
AfterFunc: deleteVanillaServer,
}))

t.Run("detach all volumes", core.Test(&core.TestConfig{
Commands: GetCommands(),
BeforeFunc: func(ctx *core.BeforeFuncCtx) error {
ctx.Meta["Server"] = ctx.ExecuteCmd("scw instance server create stopped=true image=ubuntu-bionic additional-volumes.0=block:10G")
return nil
},
Cmd: `scw instance server update server-id={{ .Server.ID }} volume-ids=none`,
Check: func(t *testing.T, ctx *core.CheckFuncCtx) {
require.NoError(t, ctx.Err)
assert.Equal(t, 0, len(ctx.Result.(*instance.UpdateServerResponse).Server.Volumes))
},
AfterFunc: func(ctx *core.AfterFuncCtx) error {
ctx.ExecuteCmd(`scw instance delete volume volume-id={{ (index .Server.Volumes "0").ID }}`)
ctx.ExecuteCmd(`scw instance delete volume volume-id={{ (index .Server.Volumes "1").ID }}`)
return deleteVanillaServer(ctx)
},
}))
})
}
Loading