Skip to content

Commit f7c0149

Browse files
committed
fix
1 parent 87a2c54 commit f7c0149

23 files changed

+4427
-209
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ ARGS:
1010
[name=<generated>] Name of the Database Instance
1111
engine Database engine of the Database Instance (PostgreSQL, MySQL, ...)
1212
user-name Username created when the Database Instance is created
13-
password Password of the user
13+
[generate-password=true] Will generate a 21 character-length password that contains a mix of upper/lower case letters, numbers and special symbols
14+
[password] Password of the user
1415
node-type=DB-DEV-S Type of node to use for the Database Instance
1516
[is-ha-cluster] Defines whether or not High-Availability is enabled
1617
[disable-backup] Defines whether or not backups are disabled

cmd/scw/testdata/test-all-usage-rdb-user-create-usage.golden

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ USAGE:
66
scw rdb user create [arg=value ...]
77

88
ARGS:
9-
instance-id UUID of the Database Instance in which you want to create a user
10-
[name] Name of the user you want to create
11-
[password] Password of the user you want to create
12-
[is-admin] Defines whether the user will have administrative privileges
13-
[region=fr-par] Region to target. If none is passed will use default region from the config (fr-par | nl-ams | pl-waw)
9+
instance-id UUID of the Database Instance in which you want to create a user
10+
[name] Name of the user you want to create
11+
[password] Password of the user you want to create
12+
[generate-password=true] Will generate a 21 character-length password that contains a mix of upper/lower case letters, numbers and special symbols
13+
[is-admin] Defines whether the user will have administrative privileges
14+
[region=fr-par] Region to target. If none is passed will use default region from the config (fr-par | nl-ams | pl-waw)
1415

1516
FLAGS:
1617
-h, --help help for create

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ USAGE:
66
scw rdb user update [arg=value ...]
77

88
ARGS:
9-
instance-id UUID of the Database Instance the user belongs to
10-
name Name of the database user
11-
[password] Password of the database user
12-
[is-admin] Defines whether or not this user got administrative privileges
13-
[region=fr-par] Region to target. If none is passed will use default region from the config (fr-par | nl-ams | pl-waw)
9+
instance-id UUID of the Database Instance the user belongs to
10+
name Name of the database user
11+
[password] Password of the database user
12+
[generate-password=true] Will generate a 21 character-length password that contains a mix of upper/lower case letters, numbers and special symbols
13+
[is-admin] Defines whether or not this user got administrative privileges
14+
[region=fr-par] Region to target. If none is passed will use default region from the config (fr-par | nl-ams | pl-waw)
1415

1516
FLAGS:
1617
-h, --help help for update

docs/commands/rdb.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,8 @@ scw rdb instance create [arg=value ...]
688688
| name | Default: `<generated>` | Name of the Database Instance |
689689
| engine | Required | Database engine of the Database Instance (PostgreSQL, MySQL, ...) |
690690
| user-name | Required | Username created when the Database Instance is created |
691-
| password | Required | Password of the user |
691+
| generate-password | Default: `true` | Will generate a 21 character-length password that contains a mix of upper/lower case letters, numbers and special symbols |
692+
| password | | Password of the user |
692693
| node-type | Required<br />Default: `DB-DEV-S` | Type of node to use for the Database Instance |
693694
| is-ha-cluster | | Defines whether or not High-Availability is enabled |
694695
| disable-backup | | Defines whether or not backups are disabled |
@@ -1514,6 +1515,7 @@ scw rdb user create [arg=value ...]
15141515
| instance-id | Required | UUID of the Database Instance in which you want to create a user |
15151516
| name | | Name of the user you want to create |
15161517
| password | | Password of the user you want to create |
1518+
| generate-password | Default: `true` | Will generate a 21 character-length password that contains a mix of upper/lower case letters, numbers and special symbols |
15171519
| is-admin | | Defines whether the user will have administrative privileges |
15181520
| 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 |
15191521

@@ -1580,6 +1582,7 @@ scw rdb user update [arg=value ...]
15801582
| instance-id | Required | UUID of the Database Instance the user belongs to |
15811583
| name | Required | Name of the database user |
15821584
| password | | Password of the database user |
1585+
| generate-password | Default: `true` | Will generate a 21 character-length password that contains a mix of upper/lower case letters, numbers and special symbols |
15831586
| is-admin | | Defines whether or not this user got administrative privileges |
15841587
| 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 |
15851588

internal/namespaces/rdb/v1/custom.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ func GetCommands() *core.Commands {
1212
human.RegisterMarshalerFunc(rdb.Instance{}, instanceMarshalerFunc)
1313
human.RegisterMarshalerFunc(rdb.BackupSchedule{}, backupScheduleMarshalerFunc)
1414
human.RegisterMarshalerFunc(backupDownloadResult{}, backupResultMarshallerFunc)
15+
human.RegisterMarshalerFunc(createInstanceResult{}, createInstanceResultMarshalerFunc)
1516

1617
human.RegisterMarshalerFunc(rdb.InstanceStatus(""), human.EnumMarshalFunc(instanceStatusMarshalSpecs))
1718
human.RegisterMarshalerFunc(rdb.DatabaseBackupStatus(""), human.EnumMarshalFunc(backupStatusMarshalSpecs))
@@ -41,6 +42,8 @@ func GetCommands() *core.Commands {
4142
cmds.MustFind("rdb", "engine", "list").Override(engineListBuilder)
4243

4344
cmds.MustFind("rdb", "user", "list").Override(userListBuilder)
45+
cmds.MustFind("rdb", "user", "create").Override(userCreateBuilder)
46+
cmds.MustFind("rdb", "user", "update").Override(userUpdateBuilder)
4447

4548
cmds.MustFind("rdb", "backup", "list").Override(backupListBuilder)
4649

internal/namespaces/rdb/v1/custom_instance.go

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
"github.com/scaleway/scaleway-cli/v2/internal/core"
1616
"github.com/scaleway/scaleway-cli/v2/internal/human"
1717
"github.com/scaleway/scaleway-cli/v2/internal/interactive"
18+
"github.com/scaleway/scaleway-cli/v2/internal/passwordgenerator"
19+
"github.com/scaleway/scaleway-cli/v2/internal/terminal"
1820
"github.com/scaleway/scaleway-sdk-go/api/rdb/v1"
1921
"github.com/scaleway/scaleway-sdk-go/scw"
2022
)
@@ -48,6 +50,40 @@ type serverWaitRequest struct {
4850
Timeout time.Duration
4951
}
5052

53+
type createInstanceResult struct {
54+
*rdb.Instance
55+
Password string
56+
}
57+
58+
func createInstanceResultMarshalerFunc(i interface{}, opt *human.MarshalOpt) (string, error) {
59+
instanceResult := i.(createInstanceResult)
60+
61+
opt.Sections = []*human.MarshalSection{
62+
{
63+
FieldName: "Endpoint",
64+
},
65+
{
66+
FieldName: "Volume",
67+
},
68+
{
69+
FieldName: "BackupSchedule",
70+
},
71+
{
72+
FieldName: "Settings",
73+
},
74+
}
75+
76+
instanceStr, err := human.Marshal(instanceResult.Instance, opt)
77+
if err != nil {
78+
return "", err
79+
}
80+
81+
return strings.Join([]string{
82+
instanceStr,
83+
terminal.Style("Password: ", color.Bold) + "\n" + instanceResult.Password,
84+
}, "\n\n"), nil
85+
}
86+
5187
func instanceMarshalerFunc(i interface{}, opt *human.MarshalOpt) (string, error) {
5288
// To avoid recursion of human.Marshal we create a dummy type
5389
type tmp rdb.Instance
@@ -154,22 +190,79 @@ func autoCompleteNodeType(ctx context.Context, prefix string) core.AutocompleteS
154190
}
155191

156192
func instanceCreateBuilder(c *core.Command) *core.Command {
193+
type rdbCreateInstanceRequestCustom struct {
194+
*rdb.CreateInstanceRequest
195+
GeneratePassword bool
196+
}
197+
198+
c.ArgSpecs.AddBefore("password", &core.ArgSpec{
199+
Name: "generate-password",
200+
Short: `Will generate a 21 character-length password that contains a mix of upper/lower case letters, numbers and special symbols`,
201+
Required: false,
202+
Deprecated: false,
203+
Positional: false,
204+
Default: core.DefaultValueSetter("true"),
205+
})
206+
c.ArgSpecs.GetByName("password").Required = false
157207
c.ArgSpecs.GetByName("node-type").Default = core.DefaultValueSetter("DB-DEV-S")
158208
c.ArgSpecs.GetByName("node-type").AutoCompleteFunc = autoCompleteNodeType
159209

210+
c.ArgsType = reflect.TypeOf(rdbCreateInstanceRequestCustom{})
211+
160212
c.WaitFunc = func(ctx context.Context, argsI, respI interface{}) (interface{}, error) {
161213
api := rdb.NewAPI(core.ExtractClient(ctx))
162-
return api.WaitForInstance(&rdb.WaitForInstanceRequest{
163-
InstanceID: respI.(*rdb.Instance).ID,
164-
Region: respI.(*rdb.Instance).Region,
214+
instance, err := api.WaitForInstance(&rdb.WaitForInstanceRequest{
215+
InstanceID: respI.(createInstanceResult).Instance.ID,
216+
Region: respI.(createInstanceResult).Instance.Region,
165217
Timeout: scw.TimeDurationPtr(instanceActionTimeout),
166218
RetryInterval: core.DefaultRetryInterval,
167219
})
220+
if err != nil {
221+
return nil, err
222+
}
223+
224+
result := createInstanceResult{
225+
Instance: instance,
226+
Password: respI.(createInstanceResult).Password,
227+
}
228+
229+
return result, nil
230+
}
231+
232+
c.Run = func(ctx context.Context, argsI interface{}) (interface{}, error) {
233+
client := core.ExtractClient(ctx)
234+
api := rdb.NewAPI(client)
235+
236+
customRequest := argsI.(*rdbCreateInstanceRequestCustom)
237+
createInstanceRequest := customRequest.CreateInstanceRequest
238+
239+
var err error
240+
createInstanceRequest.NodeType = strings.ToLower(createInstanceRequest.NodeType)
241+
if customRequest.GeneratePassword && customRequest.Password == "" {
242+
createInstanceRequest.Password, err = passwordgenerator.GeneratePassword(21, 1, 1, 1, 1)
243+
if err != nil {
244+
return nil, err
245+
}
246+
fmt.Printf("Your generated password is %s \n", createInstanceRequest.Password)
247+
fmt.Printf("\n")
248+
}
249+
250+
instance, err := api.CreateInstance(createInstanceRequest)
251+
if err != nil {
252+
return nil, err
253+
}
254+
255+
result := createInstanceResult{
256+
Instance: instance,
257+
Password: createInstanceRequest.Password,
258+
}
259+
260+
return result, nil
168261
}
169262

170263
// Waiting for API to accept uppercase node-type
171264
c.Interceptor = func(ctx context.Context, argsI interface{}, runner core.CommandRunner) (interface{}, error) {
172-
args := argsI.(*rdb.CreateInstanceRequest)
265+
args := argsI.(*rdbCreateInstanceRequestCustom)
173266
args.NodeType = strings.ToLower(args.NodeType)
174267
return runner(ctx, args)
175268
}

internal/namespaces/rdb/v1/custom_instance_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ func Test_CreateInstance(t *testing.T) {
3636
Check: core.TestCheckGolden(),
3737
AfterFunc: core.ExecAfterCmd("scw rdb instance delete {{ .CmdResult.ID }}"),
3838
}))
39+
40+
t.Run("With password generator", core.Test(&core.TestConfig{
41+
Commands: GetCommands(),
42+
Cmd: fmt.Sprintf("scw rdb instance create node-type=DB-DEV-S is-ha-cluster=false name=%s engine=%s user-name=%s generate-password=true --wait", name, engine, user),
43+
Check: core.TestCheckGolden(),
44+
AfterFunc: core.ExecAfterCmd("scw rdb instance delete {{ .CmdResult.ID }}"),
45+
}))
3946
}
4047

4148
func Test_GetInstance(t *testing.T) {

internal/namespaces/rdb/v1/custom_user.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package rdb
22

33
import (
44
"context"
5+
"fmt"
6+
"reflect"
57

68
"github.com/scaleway/scaleway-cli/v2/internal/core"
9+
"github.com/scaleway/scaleway-cli/v2/internal/passwordgenerator"
710
"github.com/scaleway/scaleway-sdk-go/api/rdb/v1"
811
"github.com/scaleway/scaleway-sdk-go/scw"
912
)
@@ -80,3 +83,110 @@ func userListBuilder(c *core.Command) *core.Command {
8083

8184
return c
8285
}
86+
87+
func userCreateBuilder(c *core.Command) *core.Command {
88+
type rdbCreateUserRequestCustom struct {
89+
*rdb.CreateUserRequest
90+
GeneratePassword bool
91+
}
92+
93+
type rdbCreateUserResponseCustom struct {
94+
*rdb.User
95+
Password string
96+
}
97+
98+
c.ArgSpecs.AddBefore("is-admin", &core.ArgSpec{
99+
Name: "generate-password",
100+
Short: `Will generate a 21 character-length password that contains a mix of upper/lower case letters, numbers and special symbols`,
101+
Required: false,
102+
Deprecated: false,
103+
Positional: false,
104+
Default: core.DefaultValueSetter("true"),
105+
})
106+
c.ArgsType = reflect.TypeOf(rdbCreateUserRequestCustom{})
107+
108+
c.Run = func(ctx context.Context, argsI interface{}) (interface{}, error) {
109+
client := core.ExtractClient(ctx)
110+
api := rdb.NewAPI(client)
111+
112+
customRequest := argsI.(*rdbCreateUserRequestCustom)
113+
createUserRequest := customRequest.CreateUserRequest
114+
115+
var err error
116+
if customRequest.GeneratePassword && customRequest.Password == "" {
117+
createUserRequest.Password, err = passwordgenerator.GeneratePassword(21, 1, 1, 1, 1)
118+
if err != nil {
119+
return nil, err
120+
}
121+
fmt.Printf("Your generated password is %s \n", createUserRequest.Password)
122+
fmt.Printf("\n")
123+
}
124+
125+
user, err := api.CreateUser(createUserRequest)
126+
if err != nil {
127+
return nil, err
128+
}
129+
130+
result := rdbCreateUserResponseCustom{
131+
User: user,
132+
Password: createUserRequest.Password,
133+
}
134+
135+
return result, nil
136+
}
137+
138+
return c
139+
}
140+
141+
func userUpdateBuilder(c *core.Command) *core.Command {
142+
type rdbUpdateUserRequestCustom struct {
143+
*rdb.UpdateUserRequest
144+
GeneratePassword bool
145+
}
146+
147+
type rdbUpdateUserResponseCustom struct {
148+
*rdb.User
149+
Password string
150+
}
151+
152+
c.ArgSpecs.AddBefore("is-admin", &core.ArgSpec{
153+
Name: "generate-password",
154+
Short: `Will generate a 21 character-length password that contains a mix of upper/lower case letters, numbers and special symbols`,
155+
Required: false,
156+
Deprecated: false,
157+
Positional: false,
158+
Default: core.DefaultValueSetter("true"),
159+
})
160+
c.ArgsType = reflect.TypeOf(rdbUpdateUserRequestCustom{})
161+
162+
c.Run = func(ctx context.Context, argsI interface{}) (interface{}, error) {
163+
client := core.ExtractClient(ctx)
164+
api := rdb.NewAPI(client)
165+
166+
customRequest := argsI.(*rdbUpdateUserRequestCustom)
167+
168+
updateUserRequest := customRequest.UpdateUserRequest
169+
170+
var err error
171+
if customRequest.GeneratePassword && customRequest.Password == nil {
172+
updateUserRequest.Password = new(string)
173+
*updateUserRequest.Password, err = passwordgenerator.GeneratePassword(21, 1, 1, 1, 1)
174+
fmt.Printf("Your generated password is %v \n", *updateUserRequest.Password)
175+
fmt.Printf("\n")
176+
}
177+
178+
user, err := api.UpdateUser(updateUserRequest)
179+
if err != nil {
180+
return nil, err
181+
}
182+
183+
result := rdbUpdateUserResponseCustom{
184+
User: user,
185+
Password: *updateUserRequest.Password,
186+
}
187+
188+
return result, nil
189+
}
190+
191+
return c
192+
}

0 commit comments

Comments
 (0)