Skip to content

Commit

Permalink
feat: add support for ARM APIs (#468)
Browse files Browse the repository at this point in the history
* chore(deps): bump hcloud-go

* feat(server): select correct image by ARCH

* feat(iso): verify iso has correct architecture

* feat(image): show architecture field

* feat(servertype): show architecture field

* feat(iso): show architecture field

* feat(image): architecture filter on list command

* feat(image): architecture filter on describe command

* feat(iso): architecture filter on list command
  • Loading branch information
apricote authored Apr 12, 2023
1 parent ebd67a4 commit 6abb4e2
Show file tree
Hide file tree
Showing 15 changed files with 181 additions and 59 deletions.
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.5.9
github.com/guptarohit/asciigraph v0.5.5
github.com/hetznercloud/hcloud-go v1.41.0
github.com/hetznercloud/hcloud-go v1.42.0
github.com/pelletier/go-toml/v2 v2.0.6
github.com/rjeczalik/interfaces v0.3.0
github.com/spf13/cobra v1.5.0
Expand Down Expand Up @@ -36,10 +36,10 @@ require (
github.com/prometheus/procfs v0.8.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/term v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
20 changes: 10 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ github.com/guptarohit/asciigraph v0.5.5 h1:ccFnUF8xYIOUPPY3tmdvRyHqmn1MYI9iv1pLK
github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hetznercloud/hcloud-go v1.41.0 h1:KJGFRRc68QiVu4PrEP5BmCQVveCP2CM26UGQUKGpIUs=
github.com/hetznercloud/hcloud-go v1.41.0/go.mod h1:NaHg47L6C77mngZhwBG652dTAztYrsZ2/iITJKhQkHA=
github.com/hetznercloud/hcloud-go v1.42.0 h1:Es/CDOForQN3nOOP5Vxh1N/YHjpCg386iYEX5zCgi+A=
github.com/hetznercloud/hcloud-go v1.42.0/go.mod h1:YADL8AbmQYH0Eo+1lkuyoc8LutT0UeMvaKP47nNUb+Y=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
Expand Down Expand Up @@ -324,8 +324,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -386,21 +386,21 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down
19 changes: 17 additions & 2 deletions internal/cmd/image/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package image
import (
"context"
"fmt"
"os"

humanize "github.com/dustin/go-humanize"
"github.com/hetznercloud/cli/internal/cmd/base"
"github.com/hetznercloud/cli/internal/cmd/cmpl"
"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/hcapi2"
"github.com/hetznercloud/hcloud-go/hcloud"
Expand All @@ -17,9 +19,21 @@ var describeCmd = base.DescribeCmd{
ShortDescription: "Describe an image",
JSONKeyGetByID: "image",
JSONKeyGetByName: "images",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Image().Names },
AdditionalFlags: func(cmd *cobra.Command) {
cmd.Flags().StringP("architecture", "a", string(hcloud.ArchitectureX86), "architecture of the image, default is x86")
cmd.RegisterFlagCompletionFunc("architecture", cmpl.SuggestCandidates(string(hcloud.ArchitectureX86), string(hcloud.ArchitectureARM)))

},
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Image().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.Image().Get(ctx, idOrName)
arch, err := cmd.Flags().GetString("architecture")
if err != nil {
return nil, nil, err
}
if !cmd.Flags().Changed("architecture") {
_, _ = fmt.Fprintln(os.Stderr, "INFO: This command only returns x86 images by default. Explicitly set the --architecture=x86|arm flag to hide this message.")
}
return client.Image().GetForArchitecture(ctx, idOrName, hcloud.Architecture(arch))
},
PrintText: func(_ context.Context, _ hcapi2.Client, _ *cobra.Command, resource interface{}) error {
image := resource.(*hcloud.Image)
Expand All @@ -41,6 +55,7 @@ var describeCmd = base.DescribeCmd{
fmt.Printf("Disk size:\t%.0f GB\n", image.DiskSize)
fmt.Printf("OS flavor:\t%s\n", image.OSFlavor)
fmt.Printf("OS version:\t%s\n", util.NA(image.OSVersion))
fmt.Printf("Architecture:\t%s\n", image.Architecture)
fmt.Printf("Rapid deploy:\t%s\n", util.YesNo(image.RapidDeploy))
fmt.Printf("Protection:\n")
fmt.Printf(" Delete:\t%s\n", util.YesNo(image.Protection.Delete))
Expand Down
15 changes: 14 additions & 1 deletion internal/cmd/image/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,33 @@ import (

var listCmd = base.ListCmd{
ResourceNamePlural: "Images",
DefaultColumns: []string{"id", "type", "name", "description", "image_size", "disk_size", "created", "deprecated"},
DefaultColumns: []string{"id", "type", "name", "description", "architecture", "image_size", "disk_size", "created", "deprecated"},
AdditionalFlags: func(cmd *cobra.Command) {
cmd.Flags().StringP("type", "t", "", "Only show images of given type")
cmd.RegisterFlagCompletionFunc("type", cmpl.SuggestCandidates("backup", "snapshot", "system", "app"))

cmd.Flags().StringSliceP("architecture", "a", []string{}, "Only show images of given architecture: x86|arm")
cmd.RegisterFlagCompletionFunc("architecture", cmpl.SuggestCandidates(string(hcloud.ArchitectureX86), string(hcloud.ArchitectureARM)))
},
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) {
opts := hcloud.ImageListOpts{ListOpts: listOpts, IncludeDeprecated: true}

imageType, _ := cmd.Flags().GetString("type")
if len(imageType) > 0 {
opts.Type = []hcloud.ImageType{hcloud.ImageType(imageType)}
}

architecture, _ := cmd.Flags().GetStringSlice("architecture")
if len(architecture) > 0 {
for _, arch := range architecture {
opts.Architecture = append(opts.Architecture, hcloud.Architecture(arch))
}
}

if len(sorts) > 0 {
opts.Sort = sorts
}

images, err := client.Image().AllWithOpts(ctx, opts)

var resources []interface{}
Expand Down
8 changes: 7 additions & 1 deletion internal/cmd/iso/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package iso
import (
"context"
"fmt"

"github.com/hetznercloud/cli/internal/cmd/base"
"github.com/hetznercloud/cli/internal/hcapi2"
"github.com/spf13/cobra"
Expand All @@ -28,6 +27,13 @@ var DescribeCmd = base.DescribeCmd{
fmt.Printf("Name:\t\t%s\n", iso.Name)
fmt.Printf("Description:\t%s\n", iso.Description)
fmt.Printf("Type:\t\t%s\n", iso.Type)

architecture := "-"
if iso.Architecture != nil {
architecture = string(*iso.Architecture)
}
fmt.Printf("Architecture:\t%s\n", architecture)

return nil
},
}
33 changes: 31 additions & 2 deletions internal/cmd/iso/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package iso

import (
"context"
"github.com/hetznercloud/cli/internal/cmd/cmpl"

"github.com/hetznercloud/cli/internal/cmd/base"
"github.com/hetznercloud/cli/internal/cmd/output"
Expand All @@ -14,13 +15,33 @@ import (

var listCmd = base.ListCmd{
ResourceNamePlural: "isos",
DefaultColumns: []string{"id", "name", "description", "type"},
DefaultColumns: []string{"id", "name", "description", "type", "architecture"},
AdditionalFlags: func(cmd *cobra.Command) {
cmd.Flags().StringSlice("architecture", []string{}, "Only show images of given architecture: x86|arm")
cmd.RegisterFlagCompletionFunc("architecture", cmpl.SuggestCandidates(string(hcloud.ArchitectureX86), string(hcloud.ArchitectureARM)))

cmd.Flags().Bool("include-architecture-wildcard", false, "Include ISOs with unknown architecture, only required if you want so show custom ISOs and still filter for architecture.")
},

Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) {
opts := hcloud.ISOListOpts{ListOpts: listOpts}

architecture, _ := cmd.Flags().GetStringSlice("architecture")
if len(architecture) > 0 {
for _, arch := range architecture {
opts.Architecture = append(opts.Architecture, hcloud.Architecture(arch))
}
}

includeArchitectureWildcard, _ := cmd.Flags().GetBool("include-architecture-wildcard")
if includeArchitectureWildcard {
opts.IncludeWildcardArchitecture = includeArchitectureWildcard
}

if len(sorts) > 0 {
opts.Sort = sorts
}

isos, _, err := client.ISO().List(ctx, opts)

var resources []interface{}
Expand All @@ -32,7 +53,15 @@ var listCmd = base.ListCmd{

OutputTable: func(_ hcapi2.Client) *output.Table {
return output.NewTable().
AddAllowedFields(hcloud.Location{})
AddAllowedFields(hcloud.ISO{}).
AddFieldFn("architecture", func(obj interface{}) string {
iso := obj.(*hcloud.ISO)
if iso.Architecture == nil {
return "-"
} else {
return string(*iso.Architecture)
}
})
},

JSONSchema: func(resources []interface{}) interface{} {
Expand Down
7 changes: 7 additions & 0 deletions internal/cmd/server/attach_iso.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package server

import (
"context"
"errors"
"fmt"

"github.com/hetznercloud/cli/internal/cmd/base"
Expand Down Expand Up @@ -44,6 +45,12 @@ var AttachISOCommand = base.Cmd{
return fmt.Errorf("ISO not found: %s", isoIDOrName)
}

// If ISO architecture is empty -> wildcard/unknown --> allow
// If ISO architecture is set and does not match server --> deny
if iso.Architecture != nil && *iso.Architecture != server.ServerType.Architecture {
return errors.New("failed to attach iso: iso has a different architecture than the server")
}

action, _, err := client.Server().AttachISO(ctx, server, iso)
if err != nil {
return err
Expand Down
30 changes: 15 additions & 15 deletions internal/cmd/server/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func createOptsFromFlags(
ctx context.Context, client hcapi2.Client, flags *pflag.FlagSet,
) (opts hcloud.ServerCreateOpts, err error) {
name, _ := flags.GetString("name")
serverType, _ := flags.GetString("type")
serverTypeName, _ := flags.GetString("type")
imageIDorName, _ := flags.GetString("image")
location, _ := flags.GetString("location")
datacenter, _ := flags.GetString("datacenter")
Expand All @@ -216,21 +216,22 @@ func createOptsFromFlags(
primaryIPv4IDorName, _ := flags.GetString("primary-ipv4")
primaryIPv6IDorName, _ := flags.GetString("primary-ipv6")

image, _, err := client.Image().Get(ctx, imageIDorName)
serverType, _, err := client.ServerType().Get(ctx, serverTypeName)
if err != nil {
return
}

// Select correct image based on server type architecture
image, _, err := client.Image().GetForArchitecture(ctx, imageIDorName, serverType.Architecture)
if err != nil {
return
}

if image == nil {
images, err := client.Image().AllWithOpts(ctx, hcloud.ImageListOpts{Name: imageIDorName, IncludeDeprecated: true})
if err != nil {
return opts, err
}
if len(images) == 0 {
err = fmt.Errorf("image not found: %s", imageIDorName)
return opts, err
}
image = images[0]
err = fmt.Errorf("image %s for architecture %s not found", imageIDorName, serverType.Architecture)
return
}

if !image.Deprecated.IsZero() {
if allowDeprecatedImage {
fmt.Printf("Attention: image %s is deprecated. It will continue to be available until %s.\n", image.Name, image.Deprecated.AddDate(0, 3, 0).Format("2006-01-02"))
Expand All @@ -239,15 +240,14 @@ func createOptsFromFlags(
return
}
}

if withoutIPv4 && withoutIPv6 && len(networks) == 0 {
err = fmt.Errorf("a server can not be created without IPv4, IPv6 and a private network. Choose at least one of those options to create the server")
return
}
opts = hcloud.ServerCreateOpts{
Name: name,
ServerType: &hcloud.ServerType{
Name: serverType,
},
Name: name,
ServerType: serverType,
Image: image,
Labels: labels,
StartAfterCreate: &startAfterCreate,
Expand Down
5 changes: 4 additions & 1 deletion internal/cmd/server/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ func TestCreate(t *testing.T) {

fx.ExpectEnsureToken()

fx.Client.ServerTypeClient.EXPECT().
Get(gomock.Any(), "cx11").
Return(&hcloud.ServerType{Architecture: hcloud.ArchitectureX86}, nil, nil)
fx.Client.ImageClient.EXPECT().
Get(gomock.Any(), "ubuntu-20.04").
GetForArchitecture(gomock.Any(), "ubuntu-20.04", hcloud.ArchitectureX86).
Return(&hcloud.Image{}, nil, nil)
fx.Client.ServerClient.EXPECT().
Create(gomock.Any(), gomock.Any()).
Expand Down
16 changes: 14 additions & 2 deletions internal/cmd/server/rebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var RebuildCommand = base.Cmd{
cmd.Flags().String("image", "", "ID or name of image to rebuild from (required)")
cmd.RegisterFlagCompletionFunc("image", cmpl.SuggestCandidatesF(client.Image().Names))
cmd.MarkFlagRequired("image")
cmd.Flags().Bool("allow-deprecated-image", false, "Enable the use of deprecated images (default: false)")

return cmd
},
Expand All @@ -40,12 +41,23 @@ var RebuildCommand = base.Cmd{
}

imageIDOrName, _ := cmd.Flags().GetString("image")
image, _, err := client.Image().Get(ctx, imageIDOrName)
// Select correct image based on server type architecture
image, _, err := client.Image().GetForArchitecture(ctx, imageIDOrName, server.ServerType.Architecture)
if err != nil {
return err
}

if image == nil {
return fmt.Errorf("image not found: %s", imageIDOrName)
return fmt.Errorf("image %s for architecture %s not found", imageIDOrName, server.ServerType.Architecture)
}

allowDeprecatedImage, _ := cmd.Flags().GetBool("allow-deprecated-image")
if !image.Deprecated.IsZero() {
if allowDeprecatedImage {
fmt.Printf("Attention: image %s is deprecated. It will continue to be available until %s.\n", image.Name, image.Deprecated.AddDate(0, 3, 0).Format("2006-01-02"))
} else {
return fmt.Errorf("image %s is deprecated, please use --allow-deprecated-image to create a server with this image. It will continue to be available until %s", image.Name, image.Deprecated.AddDate(0, 3, 0).Format("2006-01-02"))
}
}

opts := hcloud.ServerRebuildOpts{
Expand Down
1 change: 1 addition & 0 deletions internal/cmd/servertype/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var describeCmd = base.DescribeCmd{
fmt.Printf("Description:\t%s\n", serverType.Description)
fmt.Printf("Cores:\t\t%d\n", serverType.Cores)
fmt.Printf("CPU Type:\t%s\n", serverType.CPUType)
fmt.Printf("Architecture:\t%s\n", serverType.Architecture)
fmt.Printf("Memory:\t\t%.1f GB\n", serverType.Memory)
fmt.Printf("Disk:\t\t%d GB\n", serverType.Disk)
fmt.Printf("Storage Type:\t%s\n", serverType.StorageType)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/servertype/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
var ListCmd = base.ListCmd{
ResourceNamePlural: "Server Types",

DefaultColumns: []string{"id", "name", "cores", "cpu_type", "memory", "disk", "storage_type"},
DefaultColumns: []string{"id", "name", "cores", "cpu_type", "architecture", "memory", "disk", "storage_type"},

Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) {
opts := hcloud.ServerTypeListOpts{ListOpts: listOpts}
Expand Down
Loading

0 comments on commit 6abb4e2

Please sign in to comment.