Skip to content

Commit 72c2369

Browse files
authored
Implement new Object Storage enable and disable commands (#96)
* Implement object-storage enable and disable commands * Update docs
1 parent 8056cae commit 72c2369

File tree

12 files changed

+657
-0
lines changed

12 files changed

+657
-0
lines changed

docs/stackit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ stackit [flags]
3232
* [stackit logme](./stackit_logme.md) - Provides functionality for LogMe
3333
* [stackit mariadb](./stackit_mariadb.md) - Provides functionality for MariaDB
3434
* [stackit mongodbflex](./stackit_mongodbflex.md) - Provides functionality for MongoDB Flex
35+
* [stackit object-storage](./stackit_object-storage.md) - Provides functionality regarding Object Storage
3536
* [stackit opensearch](./stackit_opensearch.md) - Provides functionality for OpenSearch
3637
* [stackit organization](./stackit_organization.md) - Provides functionality regarding organizations
3738
* [stackit postgresflex](./stackit_postgresflex.md) - Provides functionality for PostgreSQL Flex

docs/stackit_config_set.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ stackit config set [flags]
3535
--logme-custom-endpoint string LogMe API base URL, used in calls to this API
3636
--mariadb-custom-endpoint string MariaDB API base URL, used in calls to this API
3737
--mongodbflex-custom-endpoint string MongoDB Flex API base URL, used in calls to this API
38+
--object-storage-custom-endpoint string Object Storage API base URL, used in calls to this API
3839
--opensearch-custom-endpoint string OpenSearch API base URL, used in calls to this API
3940
--postgresflex-custom-endpoint string PostgreSQL Flex API base URL, used in calls to this API
4041
--rabbitmq-custom-endpoint string RabbitMQ API base URL, used in calls to this API

docs/stackit_config_unset.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ stackit config unset [flags]
3333
--logme-custom-endpoint LogMe API base URL. If unset, uses the default base URL
3434
--mariadb-custom-endpoint MariaDB API base URL. If unset, uses the default base URL
3535
--mongodbflex-custom-endpoint MongoDB Flex API base URL. If unset, uses the default base URL
36+
--object-storage-custom-endpoint Object Storage API base URL. If unset, uses the default base URL
3637
--opensearch-custom-endpoint OpenSearch API base URL. If unset, uses the default base URL
3738
--output-format Output format
3839
--postgresflex-custom-endpoint PostgreSQL Flex API base URL. If unset, uses the default base URL

docs/stackit_object-storage.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
## stackit object-storage
2+
3+
Provides functionality regarding Object Storage
4+
5+
### Synopsis
6+
7+
Provides functionality regarding Object Storage.
8+
9+
```
10+
stackit object-storage [flags]
11+
```
12+
13+
### Options
14+
15+
```
16+
-h, --help Help for "stackit object-storage"
17+
```
18+
19+
### Options inherited from parent commands
20+
21+
```
22+
-y, --assume-yes If set, skips all confirmation prompts
23+
--async If set, runs the command asynchronously
24+
-o, --output-format string Output format, one of ["json" "pretty"]
25+
-p, --project-id string Project ID
26+
```
27+
28+
### SEE ALSO
29+
30+
* [stackit](./stackit.md) - Manage STACKIT resources using the command line
31+
* [stackit object-storage disable](./stackit_object-storage_disable.md) - Disables Object Storage for a project
32+
* [stackit object-storage enable](./stackit_object-storage_enable.md) - Enables Object Storage for a project
33+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## stackit object-storage disable
2+
3+
Disables Object Storage for a project
4+
5+
### Synopsis
6+
7+
Disables Object Storage for a project. It will delete all associated buckets.
8+
9+
```
10+
stackit object-storage disable [flags]
11+
```
12+
13+
### Examples
14+
15+
```
16+
Disable Object Storage functionality for your project, deleting all associated buckets
17+
$ stackit object-storage disable
18+
```
19+
20+
### Options
21+
22+
```
23+
-h, --help Help for "stackit object-storage disable"
24+
```
25+
26+
### Options inherited from parent commands
27+
28+
```
29+
-y, --assume-yes If set, skips all confirmation prompts
30+
--async If set, runs the command asynchronously
31+
-o, --output-format string Output format, one of ["json" "pretty"]
32+
-p, --project-id string Project ID
33+
```
34+
35+
### SEE ALSO
36+
37+
* [stackit object-storage](./stackit_object-storage.md) - Provides functionality regarding Object Storage
38+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## stackit object-storage enable
2+
3+
Enables Object Storage for a project
4+
5+
### Synopsis
6+
7+
Enables Object Storage for a project.
8+
9+
```
10+
stackit object-storage enable [flags]
11+
```
12+
13+
### Examples
14+
15+
```
16+
Enable Object Storage functionality for your project
17+
$ stackit object-storage enable
18+
```
19+
20+
### Options
21+
22+
```
23+
-h, --help Help for "stackit object-storage enable"
24+
```
25+
26+
### Options inherited from parent commands
27+
28+
```
29+
-y, --assume-yes If set, skips all confirmation prompts
30+
--async If set, runs the command asynchronously
31+
-o, --output-format string Output format, one of ["json" "pretty"]
32+
-p, --project-id string Project ID
33+
```
34+
35+
### SEE ALSO
36+
37+
* [stackit object-storage](./stackit_object-storage.md) - Provides functionality regarding Object Storage
38+
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package disable
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/confirm"
9+
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
11+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
12+
"github.com/stackitcloud/stackit-cli/internal/pkg/projectname"
13+
"github.com/stackitcloud/stackit-cli/internal/pkg/services/object-storage/client"
14+
15+
"github.com/spf13/cobra"
16+
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
17+
)
18+
19+
type InputModel struct {
20+
*globalflags.GlobalFlagModel
21+
}
22+
23+
func NewCmd() *cobra.Command {
24+
cmd := &cobra.Command{
25+
Use: "disable",
26+
Short: "Disables Object Storage for a project",
27+
Long: "Disables Object Storage for a project. It will delete all associated buckets.",
28+
Args: args.NoArgs,
29+
Example: examples.Build(
30+
examples.NewExample(
31+
`Disable Object Storage functionality for your project, deleting all associated buckets`,
32+
"$ stackit object-storage disable"),
33+
),
34+
RunE: func(cmd *cobra.Command, args []string) error {
35+
ctx := context.Background()
36+
model, err := parseInput(cmd)
37+
if err != nil {
38+
return err
39+
}
40+
41+
// Configure API client
42+
apiClient, err := client.ConfigureClient(cmd)
43+
if err != nil {
44+
return err
45+
}
46+
47+
projectLabel, err := projectname.GetProjectName(ctx, cmd)
48+
if err != nil {
49+
projectLabel = model.ProjectId
50+
}
51+
52+
if !model.AssumeYes {
53+
prompt := fmt.Sprintf("Are you sure you want to disable Object Storage for project %s? (This will delete all associated clusters)", projectLabel)
54+
err = confirm.PromptForConfirmation(cmd, prompt)
55+
if err != nil {
56+
return err
57+
}
58+
}
59+
60+
// Call API
61+
req := buildRequest(ctx, model, apiClient)
62+
_, err = req.Execute()
63+
if err != nil {
64+
return fmt.Errorf("disable Object Storage: %w", err)
65+
}
66+
67+
operationState := "Disabled"
68+
if model.Async {
69+
operationState = "Triggered disablement of"
70+
}
71+
cmd.Printf("%s Object Storage for project %s\n", operationState, projectLabel)
72+
return nil
73+
},
74+
}
75+
return cmd
76+
}
77+
78+
func parseInput(cmd *cobra.Command) (*InputModel, error) {
79+
globalFlags := globalflags.Parse(cmd)
80+
if globalFlags.ProjectId == "" {
81+
return nil, &errors.ProjectIdError{}
82+
}
83+
84+
return &InputModel{
85+
GlobalFlagModel: globalFlags,
86+
}, nil
87+
}
88+
89+
func buildRequest(ctx context.Context, model *InputModel, apiClient *objectstorage.APIClient) objectstorage.ApiDisableServiceRequest {
90+
req := apiClient.DisableService(ctx, model.ProjectId)
91+
return req
92+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package disable
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
8+
9+
"github.com/google/go-cmp/cmp"
10+
"github.com/google/go-cmp/cmp/cmpopts"
11+
"github.com/google/uuid"
12+
"github.com/spf13/cobra"
13+
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
14+
)
15+
16+
var projectIdFlag = globalflags.ProjectIdFlag
17+
18+
type testCtxKey struct{}
19+
20+
var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo")
21+
var testClient = &objectstorage.APIClient{}
22+
var testProjectId = uuid.NewString()
23+
24+
func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string {
25+
flagValues := map[string]string{
26+
projectIdFlag: testProjectId,
27+
}
28+
for _, mod := range mods {
29+
mod(flagValues)
30+
}
31+
return flagValues
32+
}
33+
34+
func fixtureInputModel(mods ...func(model *InputModel)) *InputModel {
35+
model := &InputModel{
36+
GlobalFlagModel: &globalflags.GlobalFlagModel{
37+
ProjectId: testProjectId,
38+
},
39+
}
40+
for _, mod := range mods {
41+
mod(model)
42+
}
43+
return model
44+
}
45+
46+
func fixtureRequest(mods ...func(request *objectstorage.ApiDisableServiceRequest)) objectstorage.ApiDisableServiceRequest {
47+
request := testClient.DisableService(testCtx, testProjectId)
48+
for _, mod := range mods {
49+
mod(&request)
50+
}
51+
return request
52+
}
53+
54+
func TestParseInput(t *testing.T) {
55+
tests := []struct {
56+
description string
57+
flagValues map[string]string
58+
isValid bool
59+
expectedModel *InputModel
60+
}{
61+
{
62+
description: "base",
63+
flagValues: fixtureFlagValues(),
64+
isValid: true,
65+
expectedModel: fixtureInputModel(),
66+
},
67+
{
68+
description: "no values",
69+
flagValues: map[string]string{},
70+
isValid: false,
71+
},
72+
{
73+
description: "project id missing",
74+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
75+
delete(flagValues, projectIdFlag)
76+
}),
77+
isValid: false,
78+
},
79+
{
80+
description: "project id invalid 1",
81+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
82+
flagValues[projectIdFlag] = ""
83+
}),
84+
isValid: false,
85+
},
86+
{
87+
description: "project id invalid 2",
88+
flagValues: fixtureFlagValues(func(flagValues map[string]string) {
89+
flagValues[projectIdFlag] = "invalid-uuid"
90+
}),
91+
isValid: false,
92+
},
93+
}
94+
95+
for _, tt := range tests {
96+
t.Run(tt.description, func(t *testing.T) {
97+
cmd := &cobra.Command{}
98+
err := globalflags.Configure(cmd.Flags())
99+
if err != nil {
100+
t.Fatalf("configure global flags: %v", err)
101+
}
102+
103+
for flag, value := range tt.flagValues {
104+
err := cmd.Flags().Set(flag, value)
105+
if err != nil {
106+
if !tt.isValid {
107+
return
108+
}
109+
t.Fatalf("setting flag --%s=%s: %v", flag, value, err)
110+
}
111+
}
112+
113+
err = cmd.ValidateRequiredFlags()
114+
if err != nil {
115+
if !tt.isValid {
116+
return
117+
}
118+
t.Fatalf("error validating flags: %v", err)
119+
}
120+
121+
model, err := parseInput(cmd)
122+
if err != nil {
123+
if !tt.isValid {
124+
return
125+
}
126+
t.Fatalf("error parsing flags: %v", err)
127+
}
128+
129+
if !tt.isValid {
130+
t.Fatalf("did not fail on invalid input")
131+
}
132+
diff := cmp.Diff(model, tt.expectedModel)
133+
if diff != "" {
134+
t.Fatalf("Data does not match: %s", diff)
135+
}
136+
})
137+
}
138+
}
139+
140+
func TestBuildRequest(t *testing.T) {
141+
tests := []struct {
142+
description string
143+
model *InputModel
144+
expectedRequest objectstorage.ApiDisableServiceRequest
145+
}{
146+
{
147+
description: "base",
148+
model: fixtureInputModel(),
149+
expectedRequest: fixtureRequest(),
150+
},
151+
}
152+
153+
for _, tt := range tests {
154+
t.Run(tt.description, func(t *testing.T) {
155+
request := buildRequest(testCtx, tt.model, testClient)
156+
157+
diff := cmp.Diff(request, tt.expectedRequest,
158+
cmp.AllowUnexported(tt.expectedRequest),
159+
cmpopts.EquateComparable(testCtx),
160+
)
161+
if diff != "" {
162+
t.Fatalf("Data does not match: %s", diff)
163+
}
164+
})
165+
}
166+
}

0 commit comments

Comments
 (0)