Skip to content

Commit 7479aa7

Browse files
committed
wip: start update client
1 parent 056e112 commit 7479aa7

File tree

2 files changed

+426
-8
lines changed

2 files changed

+426
-8
lines changed
Lines changed: 138 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,161 @@
11
package update
22

33
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
48
"github.com/spf13/cobra"
59
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
611
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
12+
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
13+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
714
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
15+
"github.com/stackitcloud/stackit-cli/internal/pkg/projectname"
16+
"github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client"
17+
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
818
)
919

20+
type inputModel struct {
21+
*globalflags.GlobalFlagModel
22+
Labels map[string]any
23+
Description string
24+
Name string
25+
Stateful bool
26+
SecurityGroupId string
27+
}
28+
1029
func NewCmd(p *print.Printer) *cobra.Command {
1130
cmd := &cobra.Command{
12-
Use: "update",
13-
Short: "update security groups",
14-
Long: "update security groups",
31+
Use: "Update",
32+
Short: "Update a security group",
33+
Long: "Update a security group",
1534
Args: args.NoArgs,
1635
Example: examples.Build(
17-
examples.NewExample(`example 1`, `foo bar baz`),
18-
examples.NewExample(`example 2`, `foo bar baz`),
36+
examples.NewExample(`Update a named group`, `$ stackit beta security-group Update --name my-new-group`),
37+
examples.NewExample(`Update a named group with labels`, `$ stackit beta security-group Update --name my-new-group --labels label1=value1,label2=value2`),
1938
),
2039
RunE: func(cmd *cobra.Command, args []string) error {
2140
return executeUpdate(cmd, p, args)
2241
},
2342
}
24-
cmd.Flags().String("dummy", "foo", "fooify")
43+
44+
configureFlags(cmd)
2545
return cmd
2646
}
2747

28-
func executeUpdate(cmd *cobra.Command, p *print.Printer, args []string) error {
29-
p.Info("executing update command")
48+
func configureFlags(cmd *cobra.Command) {
49+
cmd.Flags().String("name", "", "the name of the security group. Must be <= 63 chars")
50+
cmd.Flags().String("description", "", "an optional description of the security group. Must be <= 127 chars")
51+
cmd.Flags().Bool("stateful", false, "Update a stateful or a stateless security group")
52+
cmd.Flags().StringSlice("labels", nil, "a list of labels in the form <key>=<value>")
53+
54+
if err := flags.MarkFlagsRequired(cmd, "name"); err != nil {
55+
cobra.CheckErr(err)
56+
}
57+
}
58+
59+
func executeUpdate(cmd *cobra.Command, p *print.Printer, _ []string) error {
60+
p.Info("executing Update command")
61+
ctx := context.Background()
62+
model, err := parseInput(p, cmd)
63+
if err != nil {
64+
return err
65+
}
66+
67+
// Configure API client
68+
apiClient, err := client.ConfigureClient(p)
69+
if err != nil {
70+
return err
71+
}
72+
73+
projectLabel, err := projectname.GetProjectName(ctx, p, cmd)
74+
if err != nil {
75+
p.Debug(print.ErrorLevel, "get project name: %v", err)
76+
projectLabel = model.ProjectId
77+
}
78+
79+
// Call API
80+
req := buildRequest(ctx, model, apiClient)
81+
_, err = req.Execute()
82+
if err != nil {
83+
return fmt.Errorf("Update security group: %w", err)
84+
}
85+
86+
operationState := "Enabled"
87+
if model.Async {
88+
operationState = "Triggered enablement of"
89+
}
90+
p.Info("%s security group %q for %q\n", operationState, model.Name, projectLabel)
3091
return nil
3192
}
93+
94+
func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
95+
globalFlags := globalflags.Parse(p, cmd)
96+
if globalFlags.ProjectId == "" {
97+
return nil, &errors.ProjectIdError{}
98+
}
99+
name := flags.FlagToStringValue(p, cmd, "name")
100+
if len(name) >= 64 {
101+
return nil, &errors.ArgValidationError{
102+
Arg: "invalid name",
103+
Details: "name exceeds 63 characters in length",
104+
}
105+
}
106+
107+
labels := make(map[string]any)
108+
for _, label := range flags.FlagToStringSliceValue(p, cmd, "labels") {
109+
parts := strings.Split(label, "=")
110+
if len(parts) != 2 {
111+
return nil, &errors.ArgValidationError{
112+
Arg: "labels",
113+
Details: "invalid label declaration. Must be in the form <key>=<value>",
114+
}
115+
}
116+
labels[parts[0]] = parts[1]
117+
118+
}
119+
description := flags.FlagToStringValue(p, cmd, "description")
120+
if len(description) >= 128 {
121+
return nil, &errors.ArgValidationError{
122+
Arg: "invalid description",
123+
Details: "description exceeds 127 characters in length",
124+
}
125+
}
126+
model := inputModel{
127+
GlobalFlagModel: globalFlags,
128+
Name: name,
129+
130+
Labels: labels,
131+
Description: description,
132+
Stateful: flags.FlagToBoolValue(p, cmd, "stateful"),
133+
}
134+
135+
if p.IsVerbosityDebug() {
136+
modelStr, err := print.BuildDebugStrFromInputModel(model)
137+
if err != nil {
138+
p.Debug(print.ErrorLevel, "convert model to string for debugging: %v", err)
139+
} else {
140+
p.Debug(print.DebugLevel, "parsed input values: %s", modelStr)
141+
}
142+
}
143+
144+
return &model, nil
145+
}
146+
147+
func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiUpdateSecurityGroupRequest {
148+
request := apiClient.UpdateSecurityGroup(ctx, model.ProjectId, model.SecurityGroupId)
149+
payload := iaas.NewUpdateSecurityGroupPayload()
150+
payload.Description = &model.Description
151+
if model.Labels != nil {
152+
// this check assure that we don't end up with a pointer to nil
153+
// which is a thing in go!
154+
payload.Labels = &model.Labels
155+
}
156+
payload.Name = &model.Name
157+
request = request.UpdateSecurityGroupPayload(*payload)
158+
159+
return request
160+
161+
}

0 commit comments

Comments
 (0)