Skip to content

Commit d963e7c

Browse files
authored
feat(rdb): add instance update settings (#2549)
1 parent 1ead5cc commit d963e7c

15 files changed

+4726
-0
lines changed

cmd/scw/testdata/test-all-usage-rdb-instance-update-usage.golden

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ Update an instance.
55
USAGE:
66
scw rdb instance update <instance-id ...> [arg=value ...]
77

8+
EXAMPLES:
9+
Update instance name
10+
scw rdb instance update 11111111-1111-1111-1111-111111111111 name=foo --wait
11+
12+
Update instance tags
13+
scw rdb instance update 11111111-1111-1111-1111-111111111111 tags.0=a --wait
14+
15+
Set a timezone
16+
scw rdb instance update 11111111-1111-1111-1111-111111111111 settings.0.name=timezone settings.0.value=UTC --wait
17+
818
ARGS:
919
[backup-schedule-frequency] In hours
1020
[backup-schedule-retention] In days
@@ -15,10 +25,13 @@ ARGS:
1525
[logs-policy.max-age-retention] Max age (in day) of remote logs to keep on the database instance
1626
[logs-policy.total-disk-retention] Max disk size of remote logs to keep on the database instance
1727
[backup-same-region] Store logical backups in the same region as the database instance
28+
[settings.{index}.name] Setting name of a given instance
29+
[settings.{index}.value] Setting value of a given instance
1830
[region=fr-par] Region to target. If none is passed will use default region from the config (fr-par | nl-ams | pl-waw)
1931

2032
FLAGS:
2133
-h, --help help for update
34+
-w, --wait wait until the instance is ready
2235

2336
GLOBAL FLAGS:
2437
-c, --config string The path to the config file

docs/commands/rdb.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,9 +685,31 @@ scw rdb instance update <instance-id ...> [arg=value ...]
685685
| logs-policy.max-age-retention | | Max age (in day) of remote logs to keep on the database instance |
686686
| logs-policy.total-disk-retention | | Max disk size of remote logs to keep on the database instance |
687687
| backup-same-region | | Store logical backups in the same region as the database instance |
688+
| settings.{index}.name | | Setting name of a given instance |
689+
| settings.{index}.value | | Setting value of a given instance |
688690
| region | Default: `fr-par`<br />One of: `fr-par`, `nl-ams`, `pl-waw` | Region to target. If none is passed will use default region from the config |
689691

690692

693+
**Examples:**
694+
695+
696+
Update instance name
697+
```
698+
scw rdb instance update 11111111-1111-1111-1111-111111111111 name=foo --wait
699+
```
700+
701+
Update instance tags
702+
```
703+
scw rdb instance update 11111111-1111-1111-1111-111111111111 tags.0=a --wait
704+
```
705+
706+
Set a timezone
707+
```
708+
scw rdb instance update 11111111-1111-1111-1111-111111111111 settings.0.name=timezone settings.0.value=UTC --wait
709+
```
710+
711+
712+
691713

692714
### Upgrade an instance to an higher instance type
693715

internal/namespaces/rdb/v1/custom.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ func GetCommands() *core.Commands {
4848
cmds.MustFind("rdb", "instance", "clone").Override(instanceCloneBuilder)
4949
cmds.MustFind("rdb", "instance", "create").Override(instanceCreateBuilder)
5050
cmds.MustFind("rdb", "instance", "upgrade").Override(instanceUpgradeBuilder)
51+
cmds.MustFind("rdb", "instance", "update").Override(instanceUpdateBuilder)
5152

5253
cmds.MustFind("rdb", "engine", "list").Override(engineListBuilder)
5354

internal/namespaces/rdb/v1/custom_instance.go

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,176 @@ func instanceUpgradeBuilder(c *core.Command) *core.Command {
163163
return c
164164
}
165165

166+
func instanceUpdateBuilder(c *core.Command) *core.Command {
167+
type rdbUpdateInstanceRequestCustom struct {
168+
*rdb.UpdateInstanceRequest
169+
Settings []*rdb.InstanceSetting
170+
}
171+
172+
return &core.Command{
173+
Short: `Update an instance`,
174+
Long: `Update an instance.`,
175+
Namespace: "rdb",
176+
Resource: "instance",
177+
Verb: "update",
178+
ArgsType: reflect.TypeOf(rdbUpdateInstanceRequestCustom{}),
179+
ArgSpecs: core.ArgSpecs{
180+
{
181+
Name: "backup-schedule-frequency",
182+
Short: `In hours`,
183+
Required: false,
184+
Deprecated: false,
185+
Positional: false,
186+
},
187+
{
188+
Name: "backup-schedule-retention",
189+
Short: `In days`,
190+
Required: false,
191+
Deprecated: false,
192+
Positional: false,
193+
},
194+
{
195+
Name: "is-backup-schedule-disabled",
196+
Short: `Whether or not the backup schedule is disabled`,
197+
Required: false,
198+
Deprecated: false,
199+
Positional: false,
200+
},
201+
{
202+
Name: "name",
203+
Short: `Name of the instance`,
204+
Required: false,
205+
Deprecated: false,
206+
Positional: false,
207+
},
208+
{
209+
Name: "instance-id",
210+
Short: `UUID of the instance to update`,
211+
Required: true,
212+
Deprecated: false,
213+
Positional: true,
214+
},
215+
{
216+
Name: "tags.{index}",
217+
Short: `Tags of a given instance`,
218+
Required: false,
219+
Deprecated: false,
220+
Positional: false,
221+
},
222+
{
223+
Name: "logs-policy.max-age-retention",
224+
Short: `Max age (in day) of remote logs to keep on the database instance`,
225+
Required: false,
226+
Deprecated: false,
227+
Positional: false,
228+
},
229+
{
230+
Name: "logs-policy.total-disk-retention",
231+
Short: `Max disk size of remote logs to keep on the database instance`,
232+
Required: false,
233+
Deprecated: false,
234+
Positional: false,
235+
},
236+
{
237+
Name: "backup-same-region",
238+
Short: `Store logical backups in the same region as the database instance`,
239+
Required: false,
240+
Deprecated: false,
241+
Positional: false,
242+
},
243+
{
244+
Name: "settings.{index}.name",
245+
Short: `Setting name of a given instance`,
246+
Required: false,
247+
Deprecated: false,
248+
Positional: false,
249+
},
250+
{
251+
Name: "settings.{index}.value",
252+
Short: `Setting value of a given instance`,
253+
Required: false,
254+
Deprecated: false,
255+
Positional: false,
256+
},
257+
core.RegionArgSpec(scw.RegionFrPar, scw.RegionNlAms, scw.RegionPlWaw),
258+
},
259+
Run: func(ctx context.Context, args interface{}) (i interface{}, e error) {
260+
customRequest := args.(*rdbUpdateInstanceRequestCustom)
261+
262+
updateInstanceRequest := customRequest.UpdateInstanceRequest
263+
264+
client := core.ExtractClient(ctx)
265+
api := rdb.NewAPI(client)
266+
267+
getResp, err := api.GetInstance(&rdb.GetInstanceRequest{
268+
Region: customRequest.Region,
269+
InstanceID: customRequest.InstanceID,
270+
})
271+
if err != nil {
272+
return nil, err
273+
}
274+
275+
if customRequest.Settings != nil {
276+
settings := getResp.Settings
277+
changes := customRequest.Settings
278+
279+
for _, change := range changes {
280+
matched := false
281+
for _, setting := range settings {
282+
if change.Name == setting.Name {
283+
setting.Value = change.Value
284+
matched = true
285+
break
286+
}
287+
}
288+
if !matched {
289+
settings = append(settings, change)
290+
}
291+
}
292+
293+
_, err = api.SetInstanceSettings(&rdb.SetInstanceSettingsRequest{
294+
Region: updateInstanceRequest.Region,
295+
InstanceID: updateInstanceRequest.InstanceID,
296+
Settings: settings,
297+
})
298+
if err != nil {
299+
return nil, err
300+
}
301+
}
302+
303+
updateInstanceResponse, err := api.UpdateInstance(updateInstanceRequest)
304+
if err != nil {
305+
return nil, err
306+
}
307+
308+
return updateInstanceResponse, nil
309+
},
310+
WaitFunc: func(ctx context.Context, argsI, respI interface{}) (interface{}, error) {
311+
api := rdb.NewAPI(core.ExtractClient(ctx))
312+
return api.WaitForInstance(&rdb.WaitForInstanceRequest{
313+
InstanceID: respI.(*rdb.Instance).ID,
314+
Region: respI.(*rdb.Instance).Region,
315+
Timeout: scw.TimeDurationPtr(instanceActionTimeout),
316+
RetryInterval: core.DefaultRetryInterval,
317+
})
318+
},
319+
Examples: []*core.Example{
320+
{
321+
Short: "Update instance name",
322+
Raw: "scw rdb instance update 11111111-1111-1111-1111-111111111111 name=foo --wait",
323+
},
324+
{
325+
Short: "Update instance tags",
326+
Raw: "scw rdb instance update 11111111-1111-1111-1111-111111111111 tags.0=a --wait",
327+
},
328+
{
329+
Short: "Set a timezone",
330+
Raw: "scw rdb instance update 11111111-1111-1111-1111-111111111111 settings.0.name=timezone settings.0.value=UTC --wait",
331+
},
332+
},
333+
}
334+
}
335+
166336
func instanceWaitCommand() *core.Command {
167337
return &core.Command{
168338
Short: `Wait for an instance to reach a stable state`,

internal/namespaces/rdb/v1/custom_instance_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import (
44
"fmt"
55
"testing"
66

7+
"github.com/alecthomas/assert"
78
"github.com/scaleway/scaleway-cli/v2/internal/core"
9+
"github.com/scaleway/scaleway-sdk-go/api/rdb/v1"
810
)
911

1012
func Test_ListInstance(t *testing.T) {
@@ -56,6 +58,98 @@ func Test_UpgradeInstance(t *testing.T) {
5658
}))
5759
}
5860

61+
func Test_UpdateInstance(t *testing.T) {
62+
t.Run("Update instance name", core.Test(&core.TestConfig{
63+
Commands: GetCommands(),
64+
BeforeFunc: createInstance("PostgreSQL-12"),
65+
Cmd: "scw rdb instance update {{ .Instance.ID }} name=foo --wait",
66+
Check: core.TestCheckCombine(
67+
func(t *testing.T, ctx *core.CheckFuncCtx) {
68+
assert.Equal(t, "foo", ctx.Result.(*rdb.Instance).Name)
69+
},
70+
core.TestCheckGolden(),
71+
core.TestCheckExitCode(0),
72+
),
73+
AfterFunc: deleteInstance(),
74+
}))
75+
76+
t.Run("Update instance tags", core.Test(&core.TestConfig{
77+
Commands: GetCommands(),
78+
BeforeFunc: createInstance("PostgreSQL-12"),
79+
Cmd: "scw rdb instance update {{ .Instance.ID }} tags.0=a --wait",
80+
Check: core.TestCheckCombine(
81+
func(t *testing.T, ctx *core.CheckFuncCtx) {
82+
assert.Equal(t, "a", ctx.Result.(*rdb.Instance).Tags[0])
83+
},
84+
core.TestCheckGolden(),
85+
core.TestCheckExitCode(0),
86+
),
87+
AfterFunc: deleteInstance(),
88+
}))
89+
90+
t.Run("Set a timezone", core.Test(&core.TestConfig{
91+
Commands: GetCommands(),
92+
BeforeFunc: createInstance("PostgreSQL-12"),
93+
Cmd: "scw rdb instance update {{ .Instance.ID }} settings.0.name=timezone settings.0.value=UTC --wait",
94+
Check: core.TestCheckCombine(
95+
func(t *testing.T, ctx *core.CheckFuncCtx) {
96+
assert.Equal(t, "timezone", ctx.Result.(*rdb.Instance).Settings[6].Name)
97+
assert.Equal(t, "UTC", ctx.Result.(*rdb.Instance).Settings[6].Value)
98+
},
99+
core.TestCheckGolden(),
100+
core.TestCheckExitCode(0),
101+
),
102+
AfterFunc: deleteInstance(),
103+
}))
104+
105+
t.Run("Modify default work_mem from 4 to 8 MB", core.Test(&core.TestConfig{
106+
Commands: GetCommands(),
107+
BeforeFunc: createInstance("PostgreSQL-12"),
108+
Cmd: "scw rdb instance update {{ .Instance.ID }} settings.0.name=work_mem settings.0.value=8 --wait",
109+
Check: core.TestCheckCombine(
110+
func(t *testing.T, ctx *core.CheckFuncCtx) {
111+
assert.Equal(t, "work_mem", ctx.Result.(*rdb.Instance).Settings[0].Name)
112+
assert.Equal(t, "8", ctx.Result.(*rdb.Instance).Settings[0].Value)
113+
},
114+
core.TestCheckGolden(),
115+
core.TestCheckExitCode(0),
116+
),
117+
AfterFunc: deleteInstance(),
118+
}))
119+
120+
t.Run("Modify 3 settings + add a new one", core.Test(&core.TestConfig{
121+
Commands: GetCommands(),
122+
BeforeFunc: core.BeforeFuncCombine(
123+
createInstance("PostgreSQL-12"),
124+
core.ExecBeforeCmd("scw rdb instance update {{ .Instance.ID }} settings.0.name=work_mem settings.0.value=8"+
125+
" settings.1.name=max_connections settings.1.value=200"+
126+
" settings.2.name=effective_cache_size settings.2.value=1000"+
127+
" name=foo1 --wait"),
128+
),
129+
Cmd: "scw rdb instance update {{ .Instance.ID }} settings.0.name=work_mem settings.0.value=16" +
130+
" settings.1.name=max_connections settings.1.value=150" +
131+
" settings.2.name=effective_cache_size settings.2.value=1200" +
132+
" settings.3.name=maintenance_work_mem settings.3.value=200" +
133+
" name=foo2 --wait",
134+
Check: core.TestCheckCombine(
135+
func(t *testing.T, ctx *core.CheckFuncCtx) {
136+
assert.Equal(t, "work_mem", ctx.Result.(*rdb.Instance).Settings[0].Name)
137+
assert.Equal(t, "16", ctx.Result.(*rdb.Instance).Settings[0].Value)
138+
assert.Equal(t, "max_connections", ctx.Result.(*rdb.Instance).Settings[1].Name)
139+
assert.Equal(t, "150", ctx.Result.(*rdb.Instance).Settings[1].Value)
140+
assert.Equal(t, "effective_cache_size", ctx.Result.(*rdb.Instance).Settings[2].Name)
141+
assert.Equal(t, "1200", ctx.Result.(*rdb.Instance).Settings[2].Value)
142+
assert.Equal(t, "maintenance_work_mem", ctx.Result.(*rdb.Instance).Settings[3].Name)
143+
assert.Equal(t, "200", ctx.Result.(*rdb.Instance).Settings[3].Value)
144+
assert.Equal(t, "foo2", ctx.Result.(*rdb.Instance).Name)
145+
},
146+
core.TestCheckGolden(),
147+
core.TestCheckExitCode(0),
148+
),
149+
AfterFunc: deleteInstance(),
150+
}))
151+
}
152+
59153
func Test_Connect(t *testing.T) {
60154
t.Run("mysql", core.Test(&core.TestConfig{
61155
Commands: GetCommands(),

0 commit comments

Comments
 (0)