Skip to content

Commit f8f1bb3

Browse files
committed
feat(alb): delete command
1 parent 1380977 commit f8f1bb3

File tree

3 files changed

+288
-0
lines changed

3 files changed

+288
-0
lines changed

internal/cmd/beta/alb/alb.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package alb
22

33
import (
44
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/alb/create"
5+
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/alb/delete"
6+
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/alb/describe"
57
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/alb/list"
68
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/alb/template"
79
"github.com/stackitcloud/stackit-cli/internal/cmd/beta/alb/update"
@@ -31,5 +33,7 @@ func addSubcommands(cmd *cobra.Command, p *print.Printer) {
3133
template.NewCmd(p),
3234
create.NewCmd(p),
3335
update.NewCmd(p),
36+
describe.NewCmd(p),
37+
delete.NewCmd(p),
3438
)
3539
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package delete
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
8+
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
9+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
11+
"github.com/stackitcloud/stackit-cli/internal/pkg/services/alb/client"
12+
13+
"github.com/spf13/cobra"
14+
"github.com/stackitcloud/stackit-sdk-go/services/alb"
15+
)
16+
17+
const (
18+
loadbalancerNameArg = "LOADBALANCER_NAME_ARG"
19+
)
20+
21+
type inputModel struct {
22+
*globalflags.GlobalFlagModel
23+
Name string
24+
}
25+
26+
func NewCmd(p *print.Printer) *cobra.Command {
27+
cmd := &cobra.Command{
28+
Use: fmt.Sprintf("delete %s", loadbalancerNameArg),
29+
Short: "Deletes an application loadbalancer",
30+
Long: "Deletes an application loadbalancer.",
31+
Args: args.SingleArg(loadbalancerNameArg, nil),
32+
Example: examples.Build(
33+
examples.NewExample(
34+
`Delete an application loadbalancer with name "my-load-balancer"`,
35+
"$ stackit beta alb delete my-load-balancer",
36+
),
37+
),
38+
RunE: func(cmd *cobra.Command, args []string) error {
39+
ctx := context.Background()
40+
model, err := parseInput(p, cmd, args)
41+
if err != nil {
42+
return err
43+
}
44+
45+
// Configure API client
46+
apiClient, err := client.ConfigureClient(p)
47+
if err != nil {
48+
return err
49+
}
50+
51+
// Call API
52+
req := buildRequest(ctx, model, apiClient)
53+
_, err = req.Execute()
54+
if err != nil {
55+
return fmt.Errorf("delete loadbalancer: %w", err)
56+
}
57+
58+
p.Outputln("Load balancer deleted.")
59+
return nil
60+
},
61+
}
62+
configureFlags(cmd)
63+
return cmd
64+
}
65+
66+
func configureFlags(cmd *cobra.Command) {
67+
}
68+
69+
func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inputModel, error) {
70+
globalFlags := globalflags.Parse(p, cmd)
71+
72+
loadbalancerName := inputArgs[0]
73+
model := inputModel{
74+
GlobalFlagModel: globalFlags,
75+
Name: loadbalancerName,
76+
}
77+
78+
if p.IsVerbosityDebug() {
79+
modelStr, err := print.BuildDebugStrFromInputModel(model)
80+
if err != nil {
81+
p.Debug(print.ErrorLevel, "convert model to string for debugging: %v", err)
82+
} else {
83+
p.Debug(print.DebugLevel, "parsed input values: %s", modelStr)
84+
}
85+
}
86+
87+
return &model, nil
88+
}
89+
90+
func buildRequest(ctx context.Context, model *inputModel, apiClient *alb.APIClient) alb.ApiDeleteLoadBalancerRequest {
91+
return apiClient.DeleteLoadBalancer(ctx, model.ProjectId, model.Region, model.Name)
92+
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package delete
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
8+
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
9+
10+
"github.com/google/go-cmp/cmp"
11+
"github.com/google/go-cmp/cmp/cmpopts"
12+
"github.com/google/uuid"
13+
"github.com/stackitcloud/stackit-sdk-go/services/alb"
14+
)
15+
16+
type testCtxKey struct{}
17+
18+
var (
19+
testCtx = context.WithValue(context.Background(), testCtxKey{}, "test")
20+
testProjectId = uuid.NewString()
21+
testRegion = "eu01"
22+
testClient = &alb.APIClient{}
23+
testLoadBalancerName = "my-test-loadbalancer"
24+
)
25+
26+
func fixtureArgValues(mods ...func(argVales []string)) []string {
27+
argVales := []string{
28+
testLoadBalancerName,
29+
}
30+
for _, m := range mods {
31+
m(argVales)
32+
}
33+
return argVales
34+
}
35+
36+
func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string {
37+
flagValues := map[string]string{
38+
globalflags.ProjectIdFlag: testProjectId,
39+
globalflags.RegionFlag: testRegion,
40+
}
41+
for _, m := range mods {
42+
m(flagValues)
43+
}
44+
return flagValues
45+
}
46+
47+
func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
48+
model := &inputModel{
49+
GlobalFlagModel: &globalflags.GlobalFlagModel{
50+
Verbosity: globalflags.VerbosityDefault,
51+
ProjectId: testProjectId,
52+
Region: testRegion,
53+
},
54+
Name: testLoadBalancerName,
55+
}
56+
for _, mod := range mods {
57+
mod(model)
58+
}
59+
return model
60+
}
61+
62+
func fixtureRequest(mods ...func(request *alb.ApiDeleteLoadBalancerRequest)) alb.ApiDeleteLoadBalancerRequest {
63+
request := testClient.DeleteLoadBalancer(testCtx, testProjectId, testRegion, testLoadBalancerName)
64+
for _, mod := range mods {
65+
mod(&request)
66+
}
67+
return request
68+
}
69+
70+
func TestParseInput(t *testing.T) {
71+
tests := []struct {
72+
description string
73+
argsValues []string
74+
flagValues map[string]string
75+
isValid bool
76+
expectedModel *inputModel
77+
}{
78+
{
79+
description: "base",
80+
argsValues: fixtureArgValues(),
81+
flagValues: fixtureFlagValues(),
82+
isValid: true,
83+
expectedModel: fixtureInputModel(),
84+
},
85+
{
86+
description: "no values",
87+
argsValues: []string{},
88+
flagValues: map[string]string{
89+
globalflags.ProjectIdFlag: testProjectId,
90+
globalflags.RegionFlag: testRegion,
91+
},
92+
isValid: false,
93+
},
94+
{
95+
description: "no arg values",
96+
argsValues: []string{},
97+
flagValues: fixtureFlagValues(),
98+
isValid: false,
99+
},
100+
{
101+
description: "no flag values",
102+
argsValues: fixtureArgValues(),
103+
flagValues: map[string]string{
104+
globalflags.ProjectIdFlag: testProjectId,
105+
globalflags.RegionFlag: testRegion,
106+
},
107+
isValid: true,
108+
expectedModel: fixtureInputModel(),
109+
},
110+
}
111+
112+
for _, tt := range tests {
113+
t.Run(tt.description, func(t *testing.T) {
114+
p := print.NewPrinter()
115+
cmd := NewCmd(p)
116+
err := globalflags.Configure(cmd.Flags())
117+
if err != nil {
118+
t.Fatalf("configure global flags: %v", err)
119+
}
120+
121+
for flag, value := range tt.flagValues {
122+
err = cmd.Flags().Set(flag, value)
123+
if err != nil {
124+
if !tt.isValid {
125+
return
126+
}
127+
t.Fatalf("setting flag --%s=%s: %v", flag, value, err)
128+
}
129+
}
130+
131+
err = cmd.ValidateArgs(tt.argsValues)
132+
if err != nil {
133+
if !tt.isValid {
134+
return
135+
}
136+
t.Fatalf("error validating args: %v", err)
137+
}
138+
139+
err = cmd.ValidateRequiredFlags()
140+
if err != nil {
141+
if !tt.isValid {
142+
return
143+
}
144+
t.Fatalf("error validating flags: %v", err)
145+
}
146+
147+
model, err := parseInput(p, cmd, tt.argsValues)
148+
if err != nil {
149+
if !tt.isValid {
150+
return
151+
}
152+
t.Fatalf("error parsing input: %v", err)
153+
}
154+
155+
if !tt.isValid {
156+
t.Fatalf("did not fail on invalid input")
157+
}
158+
diff := cmp.Diff(model, tt.expectedModel)
159+
if diff != "" {
160+
t.Fatalf("Data does not match: %s", diff)
161+
}
162+
})
163+
}
164+
}
165+
166+
func TestBuildRequest(t *testing.T) {
167+
tests := []struct {
168+
description string
169+
model *inputModel
170+
expectedResult alb.ApiDeleteLoadBalancerRequest
171+
}{
172+
{
173+
description: "base",
174+
model: fixtureInputModel(),
175+
expectedResult: fixtureRequest(),
176+
},
177+
}
178+
179+
for _, tt := range tests {
180+
t.Run(tt.description, func(t *testing.T) {
181+
request := buildRequest(testCtx, tt.model, testClient)
182+
183+
diff := cmp.Diff(request, tt.expectedResult,
184+
cmp.AllowUnexported(tt.expectedResult),
185+
cmpopts.EquateComparable(testCtx),
186+
)
187+
if diff != "" {
188+
t.Fatalf("data does not match: %s", diff)
189+
}
190+
})
191+
}
192+
}

0 commit comments

Comments
 (0)