Skip to content

Commit

Permalink
fix: integer fields are displayed as floats when using describe with …
Browse files Browse the repository at this point in the history
…-o=yaml (#650)

Closes #638
  • Loading branch information
phm07 committed Dec 19, 2023
1 parent 69346f7 commit ee4c51e
Show file tree
Hide file tree
Showing 17 changed files with 103 additions and 56 deletions.
31 changes: 7 additions & 24 deletions internal/cmd/base/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package base

import (
"context"
"encoding/json"
"fmt"
"io"
"reflect"
"strings"

Expand All @@ -15,7 +13,6 @@ import (
"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/hcapi2"
"github.com/hetznercloud/cli/internal/state"
"github.com/hetznercloud/hcloud-go/v2/hcloud"
)

// DescribeCmd allows defining commands for describing a resource.
Expand All @@ -27,8 +24,10 @@ type DescribeCmd struct {
JSONKeyGetByName string // e.g. "servers"
NameSuggestions func(client hcapi2.Client) func() []string
AdditionalFlags func(*cobra.Command)
Fetch func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error)
PrintText func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error
// Fetch is called to fetch the resource to describe.
// The first returned interface is the resource itself as a hcloud struct, the second is the schema for the resource.
Fetch func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error)
PrintText func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error
}

// CobraCommand creates a command that can be registered with cobra.
Expand Down Expand Up @@ -59,7 +58,7 @@ func (dc *DescribeCmd) Run(ctx context.Context, client hcapi2.Client, cmd *cobra
outputFlags := output.FlagsForCommand(cmd)

idOrName := args[0]
resource, resp, err := dc.Fetch(ctx, client, cmd, idOrName)
resource, schema, err := dc.Fetch(ctx, client, cmd, idOrName)
if err != nil {
return err
}
Expand All @@ -72,28 +71,12 @@ func (dc *DescribeCmd) Run(ctx context.Context, client hcapi2.Client, cmd *cobra

switch {
case outputFlags.IsSet("json"):
return dc.describe(resp.Body, util.DescribeJSON)
return util.DescribeJSON(schema)
case outputFlags.IsSet("yaml"):
return dc.describe(resp.Body, util.DescribeYAML)
return util.DescribeYAML(schema)
case outputFlags.IsSet("format"):
return util.DescribeFormat(resource, outputFlags["format"][0])
default:
return dc.PrintText(ctx, client, cmd, resource)
}
}

func (dc *DescribeCmd) describe(body io.ReadCloser, describeFunc func(interface{}) error) error {
var schema map[string]interface{}
if err := json.NewDecoder(body).Decode(&schema); err != nil {
return err
}
if resource, ok := schema[dc.JSONKeyGetByID]; ok {
return describeFunc(resource)
}
if resources, ok := schema[dc.JSONKeyGetByName].([]interface{}); ok {
// We check whether we got a resource at all above (see reflect-based nil check), so it's
// ok to assume there's an element in resources.
return describeFunc(resources[0])
}
return fmt.Errorf("got invalid JSON response")
}
8 changes: 6 additions & 2 deletions internal/cmd/certificate/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "certificate",
JSONKeyGetByName: "certificates",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Certificate().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.Certificate().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
cert, _, err := client.Certificate().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return cert, hcloud.SchemaFromCertificate(cert), nil
},
PrintText: func(_ context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
cert := resource.(*hcloud.Certificate)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/datacenter/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "datacenter",
JSONKeyGetByName: "datacenters",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Datacenter().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.Datacenter().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
dc, _, err := client.Datacenter().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return dc, hcloud.SchemaFromDatacenter(dc), nil
},
PrintText: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
datacenter := resource.(*hcloud.Datacenter)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/firewall/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "firewall",
JSONKeyGetByName: "firewalls",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Firewall().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.Firewall().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
fw, _, err := client.Firewall().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return fw, hcloud.SchemaFromFirewall(fw), nil
},
PrintText: func(_ context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
firewall := resource.(*hcloud.Firewall)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/floatingip/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "floating_ip",
JSONKeyGetByName: "floating_ips",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.FloatingIP().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.FloatingIP().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
ip, _, err := client.FloatingIP().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return ip, hcloud.SchemaFromFloatingIP(ip), nil
},
PrintText: func(_ context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
floatingIP := resource.(*hcloud.FloatingIP)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/image/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,19 @@ var DescribeCmd = base.DescribeCmd{

},
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) {
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
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))
img, _, err := client.Image().GetForArchitecture(ctx, idOrName, hcloud.Architecture(arch))
if err != nil {
return nil, nil, err
}
return img, hcloud.SchemaFromImage(img), nil
},
PrintText: func(_ context.Context, _ hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
image := resource.(*hcloud.Image)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/iso/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "iso",
JSONKeyGetByName: "isos",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Location().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.ISO().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
iso, _, err := client.ISO().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return iso, hcloud.SchemaFromISO(iso), nil
},
PrintText: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
iso := resource.(*hcloud.ISO)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/loadbalancer/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "load_balancer",
JSONKeyGetByName: "load_balancers",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.LoadBalancer().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.LoadBalancer().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
lb, _, err := client.LoadBalancer().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return lb, hcloud.SchemaFromLoadBalancer(lb), nil
},
AdditionalFlags: func(cmd *cobra.Command) {
cmd.Flags().Bool("expand-targets", false, "Expand all label_selector targets")
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/loadbalancertype/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "load_balancer_type",
JSONKeyGetByName: "load_balancer_types",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.LoadBalancerType().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.LoadBalancerType().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
lbt, _, err := client.LoadBalancerType().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return lbt, hcloud.SchemaFromLoadBalancerType(lbt), nil
},
PrintText: func(_ context.Context, _ hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
loadBalancerType := resource.(*hcloud.LoadBalancerType)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/location/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "location",
JSONKeyGetByName: "locations",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Location().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.Location().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
l, _, err := client.Location().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return l, hcloud.SchemaFromLocation(l), nil
},
PrintText: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
location := resource.(*hcloud.Location)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/network/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "network",
JSONKeyGetByName: "networks",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Network().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.Network().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
n, _, err := client.Network().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return n, hcloud.SchemaFromNetwork(n), nil
},
PrintText: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
network := resource.(*hcloud.Network)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/placementgroup/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "placement_group",
JSONKeyGetByName: "placement_groups",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.PlacementGroup().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.PlacementGroup().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
pg, _, err := client.PlacementGroup().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return pg, hcloud.SchemaFromPlacementGroup(pg), nil
},
PrintText: func(_ context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
placementGroup := resource.(*hcloud.PlacementGroup)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/primaryip/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "primary_ip",
JSONKeyGetByName: "primary_ips",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.PrimaryIP().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.PrimaryIP().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
ip, _, err := client.PrimaryIP().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return ip, hcloud.SchemaFromPrimaryIP(ip), nil
},
PrintText: func(_ context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
primaryIP := resource.(*hcloud.PrimaryIP)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/server/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "server",
JSONKeyGetByName: "servers",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Server().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.Server().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
srv, _, err := client.Server().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return srv, hcloud.SchemaFromServer(srv), nil
},
PrintText: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
server := resource.(*hcloud.Server)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/servertype/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "server_type",
JSONKeyGetByName: "server_types",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.ServerType().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.ServerType().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
st, _, err := client.ServerType().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return st, hcloud.SchemaFromServerType(st), nil
},
PrintText: func(_ context.Context, _ hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
serverType := resource.(*hcloud.ServerType)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/sshkey/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "ssh_key",
JSONKeyGetByName: "ssh_keys",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.SSHKey().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.SSHKey().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
key, _, err := client.SSHKey().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return key, hcloud.SchemaFromSSHKey(key), nil
},
PrintText: func(_ context.Context, _ hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
sshKey := resource.(*hcloud.SSHKey)
Expand Down
8 changes: 6 additions & 2 deletions internal/cmd/volume/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ var DescribeCmd = base.DescribeCmd{
JSONKeyGetByID: "volume",
JSONKeyGetByName: "volumes",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Volume().Names },
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return client.Volume().Get(ctx, idOrName)
Fetch: func(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
v, _, err := client.Volume().Get(ctx, idOrName)
if err != nil {
return nil, nil, err
}
return v, hcloud.SchemaFromVolume(v), nil
},
PrintText: func(_ context.Context, client hcapi2.Client, cmd *cobra.Command, resource interface{}) error {
volume := resource.(*hcloud.Volume)
Expand Down

0 comments on commit ee4c51e

Please sign in to comment.