Skip to content

Commit c3b76dd

Browse files
feat(objectstorage): delete, list & show commands (#268)
1 parent 5b948a0 commit c3b76dd

10 files changed

Lines changed: 491 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Add `objectstorage` commands (`delete`, `list`, `show`) for Managed object storage management
12+
1013
## [3.1.0] - 2023-11-06
1114

1215
### Added

internal/commands/all/all.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands/kubernetes/nodegroup"
1313
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands/loadbalancer"
1414
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands/network"
15+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands/objectstorage"
1516
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands/root"
1617
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands/router"
1718
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands/server"
@@ -175,6 +176,12 @@ func BuildCommands(rootCmd *cobra.Command, conf *config.Config) {
175176
commands.BuildCommand(servergroup.ModifyCommand(), serverGroupCommand.Cobra(), conf)
176177
commands.BuildCommand(servergroup.ShowCommand(), serverGroupCommand.Cobra(), conf)
177178

179+
// Managed object storage operations
180+
objectStorageCommand := commands.BuildCommand(objectstorage.BaseobjectstorageCommand(), rootCmd, conf)
181+
commands.BuildCommand(objectstorage.DeleteCommand(), objectStorageCommand.Cobra(), conf)
182+
commands.BuildCommand(objectstorage.ListCommand(), objectStorageCommand.Cobra(), conf)
183+
commands.BuildCommand(objectstorage.ShowCommand(), objectStorageCommand.Cobra(), conf)
184+
178185
// Misc
179186
commands.BuildCommand(
180187
&root.VersionCommand{
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package objectstorage
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands"
7+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/output"
8+
"github.com/UpCloudLtd/upcloud-go-api/v6/upcloud/request"
9+
)
10+
11+
// DeleteCommand creates the "objectstorage delete" command
12+
func DeleteCommand() commands.Command {
13+
return &deleteCommand{
14+
BaseCommand: commands.New(
15+
"delete",
16+
"Delete a Managed object storage service",
17+
"upctl objectstorage delete 55199a44-4751-4e27-9394-7c7661910be8",
18+
),
19+
}
20+
}
21+
22+
type deleteCommand struct {
23+
*commands.BaseCommand
24+
}
25+
26+
// Execute implements commands.MultipleArgumentCommand
27+
func (c *deleteCommand) Execute(exec commands.Executor, arg string) (output.Output, error) {
28+
svc := exec.All()
29+
msg := fmt.Sprintf("Deleting object storage service %v", arg)
30+
exec.PushProgressStarted(msg)
31+
32+
err := svc.DeleteManagedObjectStorage(exec.Context(), &request.DeleteManagedObjectStorageRequest{
33+
UUID: arg,
34+
})
35+
if err != nil {
36+
return commands.HandleError(exec, msg, err)
37+
}
38+
39+
exec.PushProgressSuccess(msg)
40+
41+
return output.None{}, nil
42+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package objectstorage
2+
3+
import (
4+
"testing"
5+
6+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands"
7+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/config"
8+
smock "github.com/UpCloudLtd/upcloud-cli/v3/internal/mock"
9+
10+
"github.com/UpCloudLtd/upcloud-go-api/v6/upcloud"
11+
"github.com/UpCloudLtd/upcloud-go-api/v6/upcloud/request"
12+
"github.com/gemalto/flume"
13+
"github.com/stretchr/testify/assert"
14+
)
15+
16+
func TestDeleteCommand(t *testing.T) {
17+
targetMethod := "DeleteManagedObjectStorage"
18+
19+
objectstorage := upcloud.ManagedObjectStorage{
20+
UUID: "17fbd082-30b0-11eb-adc1-0242ac120003",
21+
}
22+
23+
for _, test := range []struct {
24+
name string
25+
arg string
26+
error string
27+
req request.DeleteManagedObjectStorageRequest
28+
}{
29+
{
30+
name: "delete with UUID",
31+
arg: objectstorage.UUID,
32+
req: request.DeleteManagedObjectStorageRequest{UUID: objectstorage.UUID},
33+
},
34+
} {
35+
t.Run(test.name, func(t *testing.T) {
36+
mService := smock.Service{}
37+
mService.On(targetMethod, &test.req).Return(nil)
38+
39+
conf := config.New()
40+
c := commands.BuildCommand(DeleteCommand(), nil, conf)
41+
42+
_, err := c.(commands.MultipleArgumentCommand).Execute(commands.NewExecutor(conf, &mService, flume.New("test")), test.arg)
43+
44+
if test.error != "" {
45+
assert.EqualError(t, err, test.error)
46+
} else {
47+
assert.NoError(t, err)
48+
mService.AssertNumberOfCalls(t, targetMethod, 1)
49+
}
50+
})
51+
}
52+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package objectstorage
2+
3+
import (
4+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands"
5+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/format"
6+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/output"
7+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/ui"
8+
"github.com/UpCloudLtd/upcloud-go-api/v6/upcloud/request"
9+
)
10+
11+
// ListCommand creates the "objectstorage list" command
12+
func ListCommand() commands.Command {
13+
return &listCommand{
14+
BaseCommand: commands.New("list", "List current Managed object storage services", "upctl objectstorage list"),
15+
}
16+
}
17+
18+
type listCommand struct {
19+
*commands.BaseCommand
20+
}
21+
22+
// ExecuteWithoutArguments implements commands.NoArgumentCommand
23+
func (c *listCommand) ExecuteWithoutArguments(exec commands.Executor) (output.Output, error) {
24+
svc := exec.All()
25+
objectstorages, err := svc.GetManagedObjectStorages(exec.Context(), &request.GetManagedObjectStoragesRequest{})
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
rows := []output.TableRow{}
31+
for _, objectstorage := range objectstorages {
32+
rows = append(rows, output.TableRow{
33+
objectstorage.UUID,
34+
objectstorage.Region,
35+
objectstorage.ConfiguredStatus,
36+
objectstorage.OperationalState,
37+
})
38+
}
39+
40+
return output.MarshaledWithHumanOutput{
41+
Value: objectstorages,
42+
Output: output.Table{
43+
Columns: []output.TableColumn{
44+
{Key: "uuid", Header: "UUID", Colour: ui.DefaultUUUIDColours},
45+
{Key: "region", Header: "Region"},
46+
{Key: "configured_status", Header: "Configured status", Format: format.ObjectStorageConfiguredStatus},
47+
{Key: "operational_state", Header: "Operational state", Format: format.ObjectStorageOperationalState},
48+
},
49+
Rows: rows,
50+
},
51+
}, nil
52+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package objectstorage
2+
3+
import (
4+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands"
5+
)
6+
7+
// BaseobjectstorageCommand creates the base "objectstorage" command
8+
func BaseobjectstorageCommand() commands.Command {
9+
return &objectstorageCommand{
10+
commands.New("objectstorage", "Manage Managed object storage services"),
11+
}
12+
}
13+
14+
type objectstorageCommand struct {
15+
*commands.BaseCommand
16+
}
17+
18+
// InitCommand implements Command.InitCommand
19+
func (c *objectstorageCommand) InitCommand() {
20+
c.Cobra().Aliases = []string{"object-storage", "objsto"}
21+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package objectstorage
2+
3+
import (
4+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands"
5+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/format"
6+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/labels"
7+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/output"
8+
"github.com/UpCloudLtd/upcloud-cli/v3/internal/ui"
9+
"github.com/UpCloudLtd/upcloud-go-api/v6/upcloud/request"
10+
)
11+
12+
// ShowCommand creates the "objectstorage show" command
13+
func ShowCommand() commands.Command {
14+
return &showCommand{
15+
BaseCommand: commands.New(
16+
"show",
17+
"Show Managed object storage service details",
18+
"upctl objectstorage show 55199a44-4751-4e27-9394-7c7661910be8",
19+
),
20+
}
21+
}
22+
23+
type showCommand struct {
24+
*commands.BaseCommand
25+
}
26+
27+
// Execute implements commands.MultipleArgumentCommand
28+
func (c *showCommand) Execute(exec commands.Executor, uuid string) (output.Output, error) {
29+
svc := exec.All()
30+
objectStorage, err := svc.GetManagedObjectStorage(exec.Context(), &request.GetManagedObjectStorageRequest{UUID: uuid})
31+
if err != nil {
32+
return nil, err
33+
}
34+
35+
endpointRows := make([]output.TableRow, 0)
36+
for _, endpoint := range objectStorage.Endpoints {
37+
endpointRows = append(endpointRows, output.TableRow{
38+
endpoint.DomainName,
39+
endpoint.Type,
40+
})
41+
}
42+
43+
endpointColumns := []output.TableColumn{
44+
{Key: "domain_name", Header: "Domain"},
45+
{Key: "type", Header: "Type"},
46+
}
47+
48+
networkRows := make([]output.TableRow, 0)
49+
for _, network := range objectStorage.Networks {
50+
networkUUID := ""
51+
if network.UUID != nil {
52+
networkUUID = *network.UUID
53+
}
54+
networkRows = append(networkRows, output.TableRow{
55+
network.Name,
56+
networkUUID,
57+
network.Type,
58+
network.Family,
59+
})
60+
}
61+
62+
networkColumns := []output.TableColumn{
63+
{Key: "name", Header: "Name"},
64+
{Key: "uuid", Header: "UUID", Colour: ui.DefaultUUUIDColours, Format: format.PossiblyUnknownString},
65+
{Key: "type", Header: "Type"},
66+
{Key: "Family", Header: "Family"},
67+
}
68+
69+
userRows := make([]output.TableRow, 0)
70+
for _, user := range objectStorage.Users {
71+
userRows = append(userRows, output.TableRow{
72+
user.Username,
73+
user.CreatedAt,
74+
user.UpdatedAt,
75+
user.OperationalState,
76+
})
77+
}
78+
79+
userColumns := []output.TableColumn{
80+
{Key: "name", Header: "Username"},
81+
{Key: "created_at", Header: "Created"},
82+
{Key: "updated_at", Header: "Updated"},
83+
{Key: "operational_state", Header: "Updated", Format: format.ObjectStorageUserOperationalState},
84+
}
85+
86+
// For JSON and YAML output, passthrough API response
87+
return output.MarshaledWithHumanOutput{
88+
Value: objectStorage,
89+
Output: output.Combined{
90+
output.CombinedSection{
91+
Contents: output.Details{
92+
Sections: []output.DetailSection{
93+
{
94+
Title: "Overview:",
95+
Rows: []output.DetailRow{
96+
{Title: "UUID:", Value: objectStorage.UUID, Colour: ui.DefaultUUUIDColours},
97+
{Title: "Region:", Value: objectStorage.Region},
98+
{Title: "Configured status:", Value: objectStorage.ConfiguredStatus, Format: format.ObjectStorageConfiguredStatus},
99+
{Title: "Operational state:", Value: objectStorage.OperationalState, Format: format.ObjectStorageOperationalState},
100+
{Title: "Created:", Value: objectStorage.CreatedAt},
101+
{Title: "Updated:", Value: objectStorage.UpdatedAt},
102+
},
103+
},
104+
},
105+
},
106+
},
107+
labels.GetLabelsSectionWithResourceType(objectStorage.Labels, "managed object storage"),
108+
output.CombinedSection{
109+
Key: "endpoints",
110+
Title: "Endpoints:",
111+
Contents: output.Table{
112+
Columns: endpointColumns,
113+
Rows: endpointRows,
114+
EmptyMessage: "No endpoints found for this Managed object storage service.",
115+
},
116+
},
117+
output.CombinedSection{
118+
Key: "networks",
119+
Title: "Networks:",
120+
Contents: output.Table{
121+
Columns: networkColumns,
122+
Rows: networkRows,
123+
EmptyMessage: "No networks found for this Managed object storage service.",
124+
},
125+
},
126+
output.CombinedSection{
127+
Key: "users",
128+
Title: "Users:",
129+
Contents: output.Table{
130+
Columns: userColumns,
131+
Rows: userRows,
132+
EmptyMessage: "No users found for this Managed object storage service.",
133+
},
134+
},
135+
},
136+
}, nil
137+
}

0 commit comments

Comments
 (0)