Skip to content

Commit faa2578

Browse files
apricotelukasmetzner
authored andcommitted
feat: add storage-box-type command (#1131)
Adds the CRUD commands `hcloud storage-box-type describe` and `hcloud storage-box-type list`. Related to #1117 --------- Co-authored-by: lukasmetzner <[email protected]>
1 parent 37d268f commit faa2578

File tree

15 files changed

+734
-0
lines changed

15 files changed

+734
-0
lines changed

docs/reference/manual/hcloud.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ A command-line interface for Hetzner Cloud
4242
* [hcloud server](hcloud_server.md) - Manage Servers
4343
* [hcloud server-type](hcloud_server-type.md) - View Server Types
4444
* [hcloud ssh-key](hcloud_ssh-key.md) - Manage SSH Keys
45+
* [hcloud storage-box-type](hcloud_storage-box-type.md) - View Storage Box Types
4546
* [hcloud version](hcloud_version.md) - Print version information
4647
* [hcloud volume](hcloud_volume.md) - Manage Volumes
4748
* [hcloud zone](hcloud_zone.md) - [experimental] Manage DNS Zones and Zone RRSets (records)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## hcloud storage-box-type
2+
3+
View Storage Box Types
4+
5+
### Options
6+
7+
```
8+
-h, --help help for storage-box-type
9+
```
10+
11+
### Options inherited from parent commands
12+
13+
```
14+
--config string Config file path (default "~/.config/hcloud/cli.toml")
15+
--context string Currently active context
16+
--debug Enable debug output
17+
--debug-file string File to write debug output to
18+
--endpoint string Hetzner Cloud API endpoint (default "https://api.hetzner.cloud/v1")
19+
--hetzner-endpoint string Hetzner API endpoint (default "https://api.hetzner.com/v1")
20+
--no-experimental-warnings If true, experimental warnings are not shown
21+
--poll-interval duration Interval at which to poll information, for example action progress (default 500ms)
22+
--quiet If true, only print error messages
23+
```
24+
25+
### SEE ALSO
26+
27+
* [hcloud](hcloud.md) - Hetzner Cloud CLI
28+
* [hcloud storage-box-type describe](hcloud_storage-box-type_describe.md) - Describe a Storage Box Type
29+
* [hcloud storage-box-type list](hcloud_storage-box-type_list.md) - List Storage Box Types
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
## hcloud storage-box-type describe
2+
3+
Describe a Storage Box Type
4+
5+
```
6+
hcloud storage-box-type describe [options] <storage-box-type>
7+
```
8+
9+
### Options
10+
11+
```
12+
-h, --help help for describe
13+
-o, --output stringArray output options: json|yaml|format
14+
```
15+
16+
### Options inherited from parent commands
17+
18+
```
19+
--config string Config file path (default "~/.config/hcloud/cli.toml")
20+
--context string Currently active context
21+
--debug Enable debug output
22+
--debug-file string File to write debug output to
23+
--endpoint string Hetzner Cloud API endpoint (default "https://api.hetzner.cloud/v1")
24+
--hetzner-endpoint string Hetzner API endpoint (default "https://api.hetzner.com/v1")
25+
--no-experimental-warnings If true, experimental warnings are not shown
26+
--poll-interval duration Interval at which to poll information, for example action progress (default 500ms)
27+
--quiet If true, only print error messages
28+
```
29+
30+
### SEE ALSO
31+
32+
* [hcloud storage-box-type](hcloud_storage-box-type.md) - View Storage Box Types
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
## hcloud storage-box-type list
2+
3+
List Storage Box Types
4+
5+
### Synopsis
6+
7+
Displays a list of Storage Box Types.
8+
9+
Output can be controlled with the -o flag. Use -o noheader to suppress the
10+
table header. Displayed columns and their order can be set with
11+
-o columns=deprecated,description (see available columns below).
12+
13+
Columns:
14+
- deprecated
15+
- description
16+
- id
17+
- name
18+
- size
19+
- subaccounts_limit
20+
21+
```
22+
hcloud storage-box-type list [options]
23+
```
24+
25+
### Options
26+
27+
```
28+
-h, --help help for list
29+
-o, --output stringArray output options: noheader|columns=...|json|yaml
30+
-l, --selector string Selector to filter by labels
31+
-s, --sort strings Determine the sorting of the result
32+
```
33+
34+
### Options inherited from parent commands
35+
36+
```
37+
--config string Config file path (default "~/.config/hcloud/cli.toml")
38+
--context string Currently active context
39+
--debug Enable debug output
40+
--debug-file string File to write debug output to
41+
--endpoint string Hetzner Cloud API endpoint (default "https://api.hetzner.cloud/v1")
42+
--hetzner-endpoint string Hetzner API endpoint (default "https://api.hetzner.com/v1")
43+
--no-experimental-warnings If true, experimental warnings are not shown
44+
--poll-interval duration Interval at which to poll information, for example action progress (default 500ms)
45+
--quiet If true, only print error messages
46+
```
47+
48+
### SEE ALSO
49+
50+
* [hcloud storage-box-type](hcloud_storage-box-type.md) - View Storage Box Types

internal/cli/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/hetznercloud/cli/internal/cmd/server"
2525
"github.com/hetznercloud/cli/internal/cmd/servertype"
2626
"github.com/hetznercloud/cli/internal/cmd/sshkey"
27+
"github.com/hetznercloud/cli/internal/cmd/storageboxtype"
2728
"github.com/hetznercloud/cli/internal/cmd/util"
2829
"github.com/hetznercloud/cli/internal/cmd/version"
2930
"github.com/hetznercloud/cli/internal/cmd/volume"
@@ -61,6 +62,7 @@ func NewRootCommand(s state.State) *cobra.Command {
6162
firewall.NewCommand(s),
6263
placementgroup.NewCommand(s),
6364
primaryip.NewCommand(s),
65+
storageboxtype.NewCommand(s),
6466
zone.NewCommand(s),
6567
)
6668

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package storageboxtype
2+
3+
import (
4+
"github.com/dustin/go-humanize"
5+
"github.com/spf13/cobra"
6+
7+
"github.com/hetznercloud/cli/internal/cmd/base"
8+
"github.com/hetznercloud/cli/internal/cmd/util"
9+
"github.com/hetznercloud/cli/internal/hcapi2"
10+
"github.com/hetznercloud/cli/internal/state"
11+
"github.com/hetznercloud/hcloud-go/v2/hcloud"
12+
)
13+
14+
var DescribeCmd = base.DescribeCmd[*hcloud.StorageBoxType]{
15+
ResourceNameSingular: "Storage Box Type",
16+
ShortDescription: "Describe a Storage Box Type",
17+
NameSuggestions: func(c hcapi2.Client) func() []string { return c.StorageBoxType().Names },
18+
Fetch: func(s state.State, _ *cobra.Command, idOrName string) (*hcloud.StorageBoxType, any, error) {
19+
st, _, err := s.Client().StorageBoxType().Get(s, idOrName)
20+
if err != nil {
21+
return nil, nil, err
22+
}
23+
return st, hcloud.SchemaFromStorageBoxType(st), nil
24+
},
25+
PrintText: func(s state.State, cmd *cobra.Command, storageBoxType *hcloud.StorageBoxType) error {
26+
cmd.Printf("ID:\t\t\t\t%d\n", storageBoxType.ID)
27+
cmd.Printf("Name:\t\t\t\t%s\n", storageBoxType.Name)
28+
cmd.Printf("Description:\t\t\t%s\n", storageBoxType.Description)
29+
cmd.Printf("Size:\t\t\t\t%s\n", humanize.IBytes(uint64(storageBoxType.Size)))
30+
cmd.Printf("Snapshot Limit:\t\t\t%d\n", storageBoxType.SnapshotLimit)
31+
cmd.Printf("Automatic Snapshot Limit:\t%d\n", storageBoxType.AutomaticSnapshotLimit)
32+
cmd.Printf("Subaccounts Limit:\t\t%d\n", storageBoxType.SubaccountsLimit)
33+
cmd.Print(util.DescribeDeprecation(storageBoxType))
34+
35+
err := loadCurrencyFromAPI(s, storageBoxType)
36+
if err != nil {
37+
cmd.PrintErrf("failed to get currency for Storage Box Type prices: %v", err)
38+
}
39+
40+
cmd.Printf("Pricings per Location:\n")
41+
for _, price := range storageBoxType.Pricings {
42+
cmd.Printf(" - Location:\t%s\n", price.Location)
43+
cmd.Printf(" Hourly:\t%s\n", util.GrossPrice(price.PriceHourly))
44+
cmd.Printf(" Monthly:\t%s\n", util.GrossPrice(price.PriceMonthly))
45+
cmd.Printf(" Setup Fee:\t%s\n", util.GrossPrice(price.SetupFee))
46+
cmd.Printf("\n")
47+
}
48+
49+
return nil
50+
},
51+
}
52+
53+
func loadCurrencyFromAPI(s state.State, storageBoxType *hcloud.StorageBoxType) error {
54+
pricing, _, err := s.Client().Pricing().Get(s)
55+
if err != nil {
56+
return err
57+
}
58+
59+
for i := range storageBoxType.Pricings {
60+
storageBoxType.Pricings[i].PriceMonthly.Currency = pricing.Currency
61+
storageBoxType.Pricings[i].PriceMonthly.VATRate = pricing.VATRate
62+
63+
storageBoxType.Pricings[i].PriceHourly.Currency = pricing.Currency
64+
storageBoxType.Pricings[i].PriceHourly.VATRate = pricing.VATRate
65+
66+
storageBoxType.Pricings[i].SetupFee.Currency = pricing.Currency
67+
storageBoxType.Pricings[i].SetupFee.VATRate = pricing.VATRate
68+
}
69+
70+
return nil
71+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package storageboxtype_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
"go.uber.org/mock/gomock"
9+
10+
"github.com/hetznercloud/cli/internal/cmd/storageboxtype"
11+
"github.com/hetznercloud/cli/internal/testutil"
12+
"github.com/hetznercloud/hcloud-go/v2/hcloud"
13+
)
14+
15+
func TestDescribe(t *testing.T) {
16+
fx := testutil.NewFixture(t)
17+
defer fx.Finish()
18+
19+
cmd := storageboxtype.DescribeCmd.CobraCommand(fx.State())
20+
fx.ExpectEnsureToken()
21+
22+
fx.Client.StorageBoxTypeClient.EXPECT().
23+
Get(gomock.Any(), "bx11").
24+
Return(&hcloud.StorageBoxType{
25+
ID: 42,
26+
Name: "bx11",
27+
Description: "BX11",
28+
SnapshotLimit: 10,
29+
AutomaticSnapshotLimit: 10,
30+
SubaccountsLimit: 200,
31+
Size: 1073741824,
32+
Pricings: []hcloud.StorageBoxTypeLocationPricing{
33+
{
34+
Location: "fsn1",
35+
PriceHourly: hcloud.Price{
36+
Gross: "0.0051",
37+
Net: "0.0051",
38+
},
39+
PriceMonthly: hcloud.Price{
40+
Gross: "3.2000",
41+
Net: "3.2000",
42+
},
43+
SetupFee: hcloud.Price{
44+
Gross: "0.0000",
45+
Net: "0.0000",
46+
},
47+
},
48+
{
49+
Location: "hel1",
50+
PriceHourly: hcloud.Price{
51+
Gross: "0.0051",
52+
Net: "0.0051",
53+
},
54+
PriceMonthly: hcloud.Price{
55+
Gross: "3.2000",
56+
Net: "3.2000",
57+
},
58+
SetupFee: hcloud.Price{
59+
Gross: "0.0000",
60+
Net: "0.0000",
61+
},
62+
},
63+
},
64+
}, nil, nil)
65+
66+
fx.Client.PricingClient.EXPECT().
67+
Get(gomock.Any()).
68+
Return(hcloud.Pricing{
69+
Currency: "EUR",
70+
VATRate: "1.19",
71+
}, nil, nil)
72+
73+
out, errOut, err := fx.Run(cmd, []string{"bx11"})
74+
75+
expOut := `ID: 42
76+
Name: bx11
77+
Description: BX11
78+
Size: 1.0 GiB
79+
Snapshot Limit: 10
80+
Automatic Snapshot Limit: 10
81+
Subaccounts Limit: 200
82+
Pricings per Location:
83+
- Location: fsn1
84+
Hourly: € 0.0051
85+
Monthly: € 3.2000
86+
Setup Fee: € 0.0000
87+
88+
- Location: hel1
89+
Hourly: € 0.0051
90+
Monthly: € 3.2000
91+
Setup Fee: € 0.0000
92+
93+
`
94+
95+
require.NoError(t, err)
96+
assert.Empty(t, errOut)
97+
assert.Equal(t, expOut, out)
98+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package storageboxtype
2+
3+
import (
4+
"github.com/dustin/go-humanize"
5+
"github.com/spf13/pflag"
6+
7+
"github.com/hetznercloud/cli/internal/cmd/base"
8+
"github.com/hetznercloud/cli/internal/cmd/output"
9+
"github.com/hetznercloud/cli/internal/cmd/util"
10+
"github.com/hetznercloud/cli/internal/hcapi2"
11+
"github.com/hetznercloud/cli/internal/state"
12+
"github.com/hetznercloud/hcloud-go/v2/hcloud"
13+
"github.com/hetznercloud/hcloud-go/v2/hcloud/schema"
14+
)
15+
16+
var ListCmd = base.ListCmd[*hcloud.StorageBoxType, schema.StorageBoxType]{
17+
ResourceNamePlural: "Storage Box Types",
18+
JSONKeyGetByName: "storage_box_types",
19+
DefaultColumns: []string{"id", "name", "description", "size", "snapshot_limit", "automatic_snapshot_limit", "subaccounts_limit"},
20+
SortOption: nil, // Storage Box Types do not support sorting
21+
22+
Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, _ []string) ([]*hcloud.StorageBoxType, error) {
23+
opts := hcloud.StorageBoxTypeListOpts{ListOpts: listOpts}
24+
return s.Client().StorageBoxType().AllWithOpts(s, opts)
25+
},
26+
27+
OutputTable: func(t *output.Table, _ hcapi2.Client) {
28+
t.
29+
AddAllowedFields(hcloud.StorageBoxType{}).
30+
AddFieldFn("size", func(obj interface{}) string {
31+
storageBoxType := obj.(*hcloud.StorageBoxType)
32+
return humanize.IBytes(uint64(storageBoxType.Size))
33+
}).
34+
AddFieldFn("deprecated", func(obj interface{}) string {
35+
storageBoxType := obj.(*hcloud.StorageBoxType)
36+
if !storageBoxType.IsDeprecated() {
37+
return "-"
38+
}
39+
return util.Datetime(storageBoxType.UnavailableAfter())
40+
})
41+
},
42+
43+
Schema: hcloud.SchemaFromStorageBoxType,
44+
}

0 commit comments

Comments
 (0)