Skip to content

Commit

Permalink
refactor: rewrite user create without zero-alloc
Browse files Browse the repository at this point in the history
  • Loading branch information
avirtopeanu-ionos committed Jan 8, 2025
1 parent b72a267 commit 83413b1
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 490 deletions.
83 changes: 49 additions & 34 deletions commands/dbaas/mongo/user/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import (
"fmt"
"strings"

"github.com/cjrd/allocate"
"github.com/ionos-cloud/ionosctl/v6/internal/client"
"github.com/ionos-cloud/ionosctl/v6/internal/constants"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/json2table/resource2table"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/jsontabwriter"
"github.com/ionos-cloud/ionosctl/v6/internal/printer/tabheaders"
"github.com/mmatczuk/anyflag"
"github.com/ionos-cloud/sdk-go-bundle/products/dbaas/mongo/v2"

"github.com/ionos-cloud/ionosctl/v6/commands/dbaas/mongo/completer"
"github.com/ionos-cloud/ionosctl/v6/internal/core"
Expand All @@ -22,9 +21,6 @@ import (
)

func UserCreateCmd() *core.Command {
var userProperties = sdkgo.UserProperties{}
var roles []sdkgo.UserRoles

cmd := core.NewCommand(context.TODO(), nil, core.CommandBuilder{
Namespace: "dbaas-mongo",
Resource: "user",
Expand Down Expand Up @@ -53,11 +49,28 @@ func UserCreateCmd() *core.Command {
},
CmdRun: func(c *core.CommandConfig) error {
clusterId := viper.GetString(core.GetFlagName(c.NS, constants.FlagClusterId))
fmt.Fprintf(c.Command.Command.ErrOrStderr(), jsontabwriter.GenerateVerboseOutput("Creating users for cluster %s", clusterId))
fmt.Fprintf(c.Command.Command.ErrOrStderr(), jsontabwriter.GenerateVerboseOutput("Creating user for cluster %s", clusterId))

input := mongo.UserProperties{}
if fn := core.GetFlagName(c.NS, FlagRoles); viper.IsSet(fn) {
roles, err := parseRoles(viper.GetString(fn))
if err != nil {
return err
}

input.Roles = roles
}

if fn := core.GetFlagName(c.NS, constants.FlagName); viper.IsSet(fn) {
input.Username = viper.GetString(fn)
}

if fn := core.GetFlagName(c.NS, constants.ArgPassword); viper.IsSet(fn) {
input.Password = viper.GetString(fn)
}

userProperties.Roles = &roles
u, _, err := client.Must().MongoClient.UsersApi.ClustersUsersPost(context.Background(), clusterId).
User(sdkgo.User{Properties: &userProperties}).Execute()
User(sdkgo.User{Properties: &input}).Execute()
if err != nil {
return err
}
Expand Down Expand Up @@ -86,50 +99,52 @@ func UserCreateCmd() *core.Command {
})

// required Path flags
_ = allocate.Zero(&userProperties)
cmd.AddStringVarFlag(userProperties.Username, constants.FlagName, constants.FlagNameShort, "", "The authentication username", core.RequiredFlagOption())
cmd.AddStringVarFlag(userProperties.Password, constants.ArgPassword, constants.ArgPasswordShort, "", "The authentication password", core.RequiredFlagOption())

sliceOfRolesFlag := anyflag.NewValue(nil, &roles, rolesParser)
cmd.Command.Flags().VarP(sliceOfRolesFlag, FlagRoles, FlagRolesShort, "User's role for each db. DB1=Role1,DB2=Role2. Roles: read, readWrite, readAnyDatabase, readWriteAnyDatabase, dbAdmin, dbAdminAnyDatabase, clusterMonitor")
_ = viper.BindPFlag(core.GetFlagName(cmd.NS, FlagRoles), cmd.Command.Flags().Lookup(FlagRoles))
_ = cmd.Command.RegisterFlagCompletionFunc(FlagRoles, func(c *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if toComplete[len(toComplete)-1] != '=' {
toComplete += "="
}
return []string{
toComplete + "read",
toComplete + "readWrite",
toComplete + "readAnyDatabase",
toComplete + "readWriteAnyDatabase",
toComplete + "dbAdmin",
toComplete + "dbAdminAnyDatabase",
toComplete + "clusterMonitor",
toComplete + "enableSharding",
}, cobra.ShellCompDirectiveNoFileComp
})
cmd.AddStringFlag(constants.FlagName, constants.FlagNameShort, "", "The authentication username", core.RequiredFlagOption())
cmd.AddStringFlag(constants.ArgPassword, constants.ArgPasswordShort, "", "The authentication password", core.RequiredFlagOption())

cmd.AddStringFlag(FlagRoles, FlagRolesShort, "", "User's role for each db. DB1=Role1,DB2=Role2."+
"Roles: read, readWrite, readAnyDatabase, readWriteAnyDatabase, dbAdmin, dbAdminAnyDatabase, clusterMonitor, enableSharding",
core.RequiredFlagOption(),
core.WithCompletionComplex(
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if toComplete[len(toComplete)-1] != '=' {
toComplete += "="
}
return []string{
toComplete + "read",
toComplete + "readWrite",
toComplete + "readAnyDatabase",
toComplete + "readWriteAnyDatabase",
toComplete + "dbAdmin",
toComplete + "dbAdminAnyDatabase",
toComplete + "clusterMonitor",
toComplete + "enableSharding",
}, cobra.ShellCompDirectiveNoFileComp
}, "",
),
)

cmd.Command.SilenceUsage = true

return cmd
}

// rolesParser converts user input into a slice of "UserRoles" objects
func rolesParser(val string) ([]sdkgo.UserRoles, error) {
// parseRoles converts string "DB1=role,DB2=other-role" input into a slice of "UserRoles" objects
func parseRoles(val string) ([]sdkgo.UserRoles, error) {
// step 1. Use identical slice conversion as pflag lib for compatibility reasons
stringReader := strings.NewReader(val)
csvReader := csv.NewReader(stringReader)
tuples, err := csvReader.Read()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to read csv: %w", err)
}

// step 2. For each tuple, get its Database and Role
var rs []sdkgo.UserRoles
for _, t := range tuples {
dbAndRole := strings.Split(t, "=")
if len(dbAndRole) != 2 {
return nil, fmt.Errorf("invalid input format: %s, need db=role1,db=role2\n", val)
return nil, fmt.Errorf("invalid input format: %s, need db=role1,db=role2", val)
}
r := sdkgo.UserRoles{Database: &dbAndRole[0], Role: &dbAndRole[1]}
rs = append(rs, r)
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ require (
github.com/itchyny/gojq v0.12.13
github.com/kardianos/ftps v1.0.3
github.com/mitchellh/go-homedir v1.1.0
github.com/mmatczuk/anyflag v0.0.0-20230209112147-9567d4cab866
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.16.0
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,6 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mmatczuk/anyflag v0.0.0-20230209112147-9567d4cab866 h1:uyqivbxMwBElUp4ZoTvC2gWRbSQNm/ZPSRm2rhp87eo=
github.com/mmatczuk/anyflag v0.0.0-20230209112147-9567d4cab866/go.mod h1:PT22bA6vWBzPL8tAeK2XCMvWOQ4e19yY3MJIgnTZRaE=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
Expand Down
201 changes: 0 additions & 201 deletions vendor/github.com/mmatczuk/anyflag/LICENSE

This file was deleted.

Loading

0 comments on commit 83413b1

Please sign in to comment.