Skip to content

Commit 1393b49

Browse files
committed
feature: implement calling service and output of results
1 parent adc2a02 commit 1393b49

File tree

4 files changed

+475
-18
lines changed

4 files changed

+475
-18
lines changed

internal/cmd/auth/security_group/create/create.go

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ package create
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"strings"
78

9+
"github.com/goccy/go-yaml"
810
"github.com/spf13/cobra"
911
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
1012
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
1113
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
1214
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
1315
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
1416
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
15-
"github.com/stackitcloud/stackit-cli/internal/pkg/projectname"
1617
"github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client"
1718
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
1819
)
@@ -69,26 +70,34 @@ func executeCreate(cmd *cobra.Command, p *print.Printer, _ []string) error {
6970
return err
7071
}
7172

72-
projectLabel, err := projectname.GetProjectName(ctx, p, cmd)
73-
if err != nil {
74-
p.Debug(print.ErrorLevel, "get project name: %v", err)
75-
projectLabel = model.ProjectId
73+
if !model.AssumeYes {
74+
prompt := fmt.Sprintf("Are you sure you want to create the security group %q?", model.Name)
75+
err = p.PromptForConfirmation(prompt)
76+
if err != nil {
77+
return err
78+
}
7679
}
7780

7881
// Call API
79-
req := buildRequest(ctx, model, apiClient)
80-
_, err = req.Execute()
82+
request := buildRequest(ctx, model, apiClient)
83+
_, err = request.Execute()
8184
if err != nil {
8285
return fmt.Errorf("create security group: %w", err)
8386
}
8487

8588
operationState := "Enabled"
8689
if model.Async {
87-
operationState = "Triggered enablement of"
90+
operationState = "Triggered label creation"
8891
}
89-
p.Info("%s security group %q for %q\n", operationState, model.Name, projectLabel)
92+
p.Info("%s security group %q for %q\n", operationState, model.Name, model.ProjectId)
9093

91-
panic("todo: invocation not implemented!")
94+
group, err := request.Execute()
95+
if err != nil {
96+
return fmt.Errorf("create security group: %w", err)
97+
}
98+
if err:=outputResult(p, model, group);err != nil {
99+
return err
100+
}
92101

93102
return nil
94103
}
@@ -162,3 +171,31 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli
162171
return request
163172

164173
}
174+
175+
func outputResult(p *print.Printer, model *inputModel, resp *iaas.SecurityGroup) error {
176+
switch model.OutputFormat {
177+
case print.JSONOutputFormat:
178+
details, err := json.MarshalIndent(resp, "", " ")
179+
if err != nil {
180+
return fmt.Errorf("marshal security group: %w", err)
181+
}
182+
p.Outputln(string(details))
183+
184+
return nil
185+
case print.YAMLOutputFormat:
186+
details, err := yaml.MarshalWithOptions(resp, yaml.IndentSequence(true))
187+
if err != nil {
188+
return fmt.Errorf("marshal security group: %w", err)
189+
}
190+
p.Outputln(string(details))
191+
192+
return nil
193+
default:
194+
operationState := "Created"
195+
if model.Async {
196+
operationState = "Triggered creation of"
197+
}
198+
p.Outputf("%s security group %q\n", operationState, model.Name)
199+
return nil
200+
}
201+
}

internal/cmd/auth/security_group/list/list.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ func executeList(cmd *cobra.Command, p *print.Printer, _ []string) error {
7676
operationState = "Triggered enablement of"
7777
}
7878
p.Info("%s security group for %q\n", operationState, projectLabel)
79+
80+
panic("todo: implement client invocation and output")
7981
return nil
8082
}
8183

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)