Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(image): only accept numerical ids for update, delete, label #844

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions internal/cmd/image/delete.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package image

import (
"fmt"
"strconv"

"github.com/spf13/cobra"

"github.com/hetznercloud/cli/internal/cmd/base"
Expand All @@ -14,8 +17,12 @@ var DeleteCmd = base.DeleteCmd{
ResourceNamePlural: "images",
ShortDescription: "Delete an image",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Image().Names },
Fetch: func(s state.State, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return s.Client().Image().Get(s, idOrName)
Fetch: func(s state.State, _ *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
id, err := strconv.ParseInt(idOrName, 10, 64)
if err != nil {
return nil, nil, fmt.Errorf("invalid snapshot or backup ID %q", idOrName)
}
return s.Client().Image().GetByID(s, id)
},
Delete: func(s state.State, cmd *cobra.Command, resource interface{}) (*hcloud.Action, error) {
image := resource.(*hcloud.Image)
Expand Down
29 changes: 13 additions & 16 deletions internal/cmd/image/delete_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package image_test

import (
"strconv"
"testing"

"github.com/golang/mock/gomock"
Expand All @@ -19,20 +20,19 @@ func TestDelete(t *testing.T) {
fx.ExpectEnsureToken()

img := &hcloud.Image{
ID: 123,
Name: "test",
ID: 123,
}

fx.Client.ImageClient.EXPECT().
Get(gomock.Any(), "test").
GetByID(gomock.Any(), img.ID).
Return(img, nil, nil)
fx.Client.ImageClient.EXPECT().
Delete(gomock.Any(), img).
Return(nil, nil)

out, errOut, err := fx.Run(cmd, []string{"test"})
out, errOut, err := fx.Run(cmd, []string{"123"})

expOut := "image test deleted\n"
expOut := "image 123 deleted\n"

assert.NoError(t, err)
assert.Empty(t, errOut)
Expand All @@ -48,33 +48,30 @@ func TestDeleteMultiple(t *testing.T) {

images := []*hcloud.Image{
{
ID: 123,
Name: "test1",
ID: 123,
},
{
ID: 456,
Name: "test2",
ID: 456,
},
{
ID: 789,
Name: "test3",
ID: 789,
},
}

var names []string
var ids []string
for _, img := range images {
names = append(names, img.Name)
ids = append(ids, strconv.FormatInt(img.ID, 10))
fx.Client.ImageClient.EXPECT().
Get(gomock.Any(), img.Name).
GetByID(gomock.Any(), img.ID).
Return(img, nil, nil)
fx.Client.ImageClient.EXPECT().
Delete(gomock.Any(), img).
Return(nil, nil)
}

out, errOut, err := fx.Run(cmd, names)
out, errOut, err := fx.Run(cmd, ids)

assert.NoError(t, err)
assert.Empty(t, errOut)
assert.Equal(t, "images test1, test2, test3 deleted\n", out)
assert.Equal(t, "images 123, 456, 789 deleted\n", out)
}
9 changes: 7 additions & 2 deletions internal/cmd/image/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package image
import (
"fmt"
"os"
"strconv"

humanize "github.com/dustin/go-humanize"
"github.com/spf13/cobra"
Expand All @@ -23,17 +24,21 @@ var DescribeCmd = base.DescribeCmd{
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(s state.State, cmd *cobra.Command, idOrName string) (interface{}, interface{}, error) {
_, err := strconv.ParseInt(idOrName, 10, 64)
isId := err == nil

arch, err := cmd.Flags().GetString("architecture")
if err != nil {
return nil, nil, err
}
if !cmd.Flags().Changed("architecture") {

if !isId && !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.")
}

img, _, err := s.Client().Image().GetForArchitecture(s, idOrName, hcloud.Architecture(arch))
if err != nil {
return nil, nil, err
Expand Down
7 changes: 6 additions & 1 deletion internal/cmd/image/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package image

import (
"fmt"
"strconv"

"github.com/hetznercloud/cli/internal/cmd/base"
"github.com/hetznercloud/cli/internal/hcapi2"
Expand All @@ -16,7 +17,11 @@ var LabelCmds = base.LabelCmds{
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Image().Names },
LabelKeySuggestions: func(c hcapi2.Client) func(idOrName string) []string { return c.Image().LabelKeys },
FetchLabels: func(s state.State, idOrName string) (map[string]string, int64, error) {
image, _, err := s.Client().Image().Get(s, idOrName)
id, err := strconv.ParseInt(idOrName, 10, 64)
if err != nil {
return nil, 0, fmt.Errorf("invalid snapshot or backup ID %q", idOrName)
}
image, _, err := s.Client().Image().GetByID(s, id)
if err != nil {
return nil, 0, err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/image/labels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestLabelAdd(t *testing.T) {
fx.ExpectEnsureToken()

fx.Client.ImageClient.EXPECT().
Get(gomock.Any(), "123").
GetByID(gomock.Any(), int64(123)).
Return(&hcloud.Image{ID: 123}, nil, nil)
fx.Client.ImageClient.EXPECT().
Update(gomock.Any(), &hcloud.Image{ID: 123}, hcloud.ImageUpdateOpts{
Expand All @@ -45,7 +45,7 @@ func TestLabelRemove(t *testing.T) {
fx.ExpectEnsureToken()

fx.Client.ImageClient.EXPECT().
Get(gomock.Any(), "123").
GetByID(gomock.Any(), int64(123)).
Return(&hcloud.Image{
ID: 123,
Labels: map[string]string{
Expand Down
11 changes: 9 additions & 2 deletions internal/cmd/image/update.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package image

import (
"fmt"
"strconv"

"github.com/spf13/cobra"
"github.com/spf13/pflag"

Expand All @@ -15,8 +18,12 @@ var UpdateCmd = base.UpdateCmd{
ResourceNameSingular: "Image",
ShortDescription: "Update an image",
NameSuggestions: func(c hcapi2.Client) func() []string { return c.Image().Names },
Fetch: func(s state.State, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
return s.Client().Image().Get(s, idOrName)
Fetch: func(s state.State, _ *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error) {
id, err := strconv.ParseInt(idOrName, 10, 64)
if err != nil {
return nil, nil, fmt.Errorf("invalid snapshot or backup ID %q", idOrName)
}
return s.Client().Image().GetByID(s, id)
},
DefineFlags: func(cmd *cobra.Command) {
cmd.Flags().String("description", "", "Image description")
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/image/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestUpdateDescription(t *testing.T) {
fx.ExpectEnsureToken()

fx.Client.ImageClient.EXPECT().
Get(gomock.Any(), "123").
GetByID(gomock.Any(), int64(123)).
Return(&hcloud.Image{ID: 123}, nil, nil)
fx.Client.ImageClient.EXPECT().
Update(gomock.Any(), &hcloud.Image{ID: 123}, hcloud.ImageUpdateOpts{
Expand All @@ -43,7 +43,7 @@ func TestUpdateType(t *testing.T) {
fx.ExpectEnsureToken()

fx.Client.ImageClient.EXPECT().
Get(gomock.Any(), "123").
GetByID(gomock.Any(), int64(123)).
Return(&hcloud.Image{ID: 123}, nil, nil)
fx.Client.ImageClient.EXPECT().
Update(gomock.Any(), &hcloud.Image{ID: 123}, hcloud.ImageUpdateOpts{
Expand Down