-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the
alpha <resource> delete
command (#2321)
- Loading branch information
Showing
11 changed files
with
303 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package templates | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"os" | ||
|
||
"github.com/kyma-project/cli.v3/internal/clierror" | ||
"github.com/kyma-project/cli.v3/internal/cmd/alpha/templates/parameters" | ||
"github.com/kyma-project/cli.v3/internal/cmd/alpha/templates/types" | ||
"github.com/spf13/cobra" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
) | ||
|
||
type DeleteOptions struct { | ||
types.DeleteCommand | ||
ResourceInfo types.ResourceInfo | ||
} | ||
|
||
func BuildDeleteCommand(clientGetter KubeClientGetter, options *DeleteOptions) *cobra.Command { | ||
return buildDeleteCommand(os.Stdout, clientGetter, options) | ||
} | ||
|
||
func buildDeleteCommand(out io.Writer, clientGetter KubeClientGetter, options *DeleteOptions) *cobra.Command { | ||
extraValues := []parameters.Value{} | ||
cmd := &cobra.Command{ | ||
Use: "delete", | ||
Short: options.Description, | ||
Long: options.DescriptionLong, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
clierror.Check(deleteResource(&deleteArgs{ | ||
out: out, | ||
ctx: cmd.Context(), | ||
deleteOptions: options, | ||
clientGetter: clientGetter, | ||
extraValues: extraValues, | ||
})) | ||
}, | ||
} | ||
|
||
for _, flag := range commonResourceFlags(options.ResourceInfo.Scope) { | ||
value := parameters.NewTyped(flag.Type, flag.Path, flag.DefaultValue) | ||
cmd.Flags().VarP(value, flag.Name, flag.Shorthand, flag.Description) | ||
if flag.Required { | ||
_ = cmd.MarkFlagRequired(flag.Name) | ||
} | ||
extraValues = append(extraValues, value) | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
type deleteArgs struct { | ||
out io.Writer | ||
ctx context.Context | ||
deleteOptions *DeleteOptions | ||
clientGetter KubeClientGetter | ||
extraValues []parameters.Value | ||
} | ||
|
||
func deleteResource(args *deleteArgs) clierror.Error { | ||
u := &unstructured.Unstructured{} | ||
u.SetGroupVersionKind(schema.GroupVersionKind{ | ||
Group: args.deleteOptions.ResourceInfo.Group, | ||
Version: args.deleteOptions.ResourceInfo.Version, | ||
Kind: args.deleteOptions.ResourceInfo.Kind, | ||
}) | ||
|
||
client, clierr := args.clientGetter.GetKubeClientWithClierr() | ||
if clierr != nil { | ||
return clierr | ||
} | ||
|
||
clierr = setExtraValues(u, args.extraValues) | ||
if clierr != nil { | ||
return clierr | ||
} | ||
|
||
err := client.RootlessDynamic().Remove(args.ctx, u) | ||
if err != nil { | ||
return clierror.Wrap(err, clierror.New("failed to delete resource")) | ||
} | ||
|
||
fmt.Fprintf(args.out, "resource %s deleted\n", getResourceName(args.deleteOptions.ResourceInfo.Scope, u)) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package templates | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"errors" | ||
"io" | ||
"testing" | ||
|
||
"github.com/kyma-project/cli.v3/internal/clierror" | ||
"github.com/kyma-project/cli.v3/internal/cmd/alpha/templates/types" | ||
"github.com/kyma-project/cli.v3/internal/kube/fake" | ||
"github.com/spf13/cobra" | ||
"github.com/stretchr/testify/require" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
) | ||
|
||
func Test_remove(t *testing.T) { | ||
t.Run("build proper command", func(t *testing.T) { | ||
cmd := fixDeleteCommand(bytes.NewBuffer([]byte{}), &mockGetter{}) | ||
|
||
require.Equal(t, "delete", cmd.Use) | ||
require.Equal(t, "delete test deploy", cmd.Short) | ||
require.Equal(t, "use this to delete test deploy", cmd.Long) | ||
|
||
require.NotNil(t, cmd.Flag("name")) | ||
require.NotNil(t, cmd.Flag("namespace")) | ||
}) | ||
|
||
t.Run("delete resource", func(t *testing.T) { | ||
buf := bytes.NewBuffer([]byte{}) | ||
fakeClient := &fake.RootlessDynamicClient{} | ||
mock := mockGetter{ | ||
client: &fake.KubeClient{ | ||
TestRootlessDynamicInterface: fakeClient, | ||
}, | ||
} | ||
|
||
cmd := fixDeleteCommand(buf, &mock) | ||
|
||
cmd.SetArgs([]string{"--name", "test-deploy", "--namespace", "test-namespace"}) | ||
|
||
err := cmd.Execute() | ||
require.NoError(t, err) | ||
|
||
require.Len(t, fakeClient.RemovedObjs, 1) | ||
require.Equal(t, fixDeletedUnstructuredDeployment(), fakeClient.RemovedObjs[0]) | ||
}) | ||
|
||
t.Run("failed to get client", func(t *testing.T) { | ||
buf := bytes.NewBuffer([]byte{}) | ||
mock := mockGetter{ | ||
clierror: clierror.New("test error"), | ||
client: nil, | ||
} | ||
|
||
err := deleteResource(&deleteArgs{ | ||
out: buf, | ||
ctx: context.Background(), | ||
clientGetter: &mock, | ||
deleteOptions: fixDeleteOptions(), | ||
}) | ||
require.Equal(t, clierror.New("test error"), err) | ||
}) | ||
|
||
t.Run("failed to delete object", func(t *testing.T) { | ||
buf := bytes.NewBuffer([]byte{}) | ||
fakeClient := &fake.RootlessDynamicClient{ | ||
ReturnRemoveErr: errors.New("test error"), | ||
} | ||
mock := mockGetter{ | ||
client: &fake.KubeClient{ | ||
TestRootlessDynamicInterface: fakeClient, | ||
}, | ||
} | ||
|
||
err := deleteResource(&deleteArgs{ | ||
out: buf, | ||
ctx: context.Background(), | ||
clientGetter: &mock, | ||
deleteOptions: fixDeleteOptions(), | ||
}) | ||
require.Equal(t, clierror.Wrap(errors.New("test error"), clierror.New("failed to delete resource")), err) | ||
}) | ||
} | ||
|
||
func fixDeleteCommand(writer io.Writer, getter KubeClientGetter) *cobra.Command { | ||
return buildDeleteCommand(writer, getter, fixDeleteOptions()) | ||
} | ||
|
||
func fixDeleteOptions() *DeleteOptions { | ||
return &DeleteOptions{ | ||
DeleteCommand: types.DeleteCommand{ | ||
Description: "delete test deploy", | ||
DescriptionLong: "use this to delete test deploy", | ||
}, | ||
ResourceInfo: types.ResourceInfo{ | ||
Scope: types.NamespaceScope, | ||
Kind: "Deployment", | ||
Group: "apps", | ||
Version: "v1", | ||
}, | ||
} | ||
} | ||
|
||
func fixDeletedUnstructuredDeployment() unstructured.Unstructured { | ||
return unstructured.Unstructured{ | ||
Object: map[string]interface{}{ | ||
"apiVersion": "apps/v1", | ||
"kind": "Deployment", | ||
"metadata": map[string]interface{}{ | ||
"name": "test-deploy", | ||
"namespace": "test-namespace", | ||
}, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package templates | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/kyma-project/cli.v3/internal/clierror" | ||
"github.com/kyma-project/cli.v3/internal/cmd/alpha/templates/parameters" | ||
"github.com/kyma-project/cli.v3/internal/cmd/alpha/templates/types" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
) | ||
|
||
func setExtraValues(u *unstructured.Unstructured, extraValues []parameters.Value) clierror.Error { | ||
for _, extraValue := range extraValues { | ||
value := extraValue.GetValue() | ||
if value == nil { | ||
// value is not set and has no default value | ||
continue | ||
} | ||
|
||
fields := strings.Split( | ||
// remove optional dot at the beginning of the path | ||
strings.TrimPrefix(extraValue.GetPath(), "."), | ||
".", | ||
) | ||
|
||
err := unstructured.SetNestedField(u.Object, value, fields...) | ||
if err != nil { | ||
return clierror.Wrap(err, clierror.New( | ||
fmt.Sprintf("failed to set value %v for path %s", value, extraValue.GetPath()), | ||
)) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func commonResourceFlags(resourceScope types.Scope) []types.CustomFlag { | ||
params := []types.CustomFlag{ | ||
{ | ||
Name: "name", | ||
Type: types.StringCustomFlagType, | ||
Description: "name of the resource", | ||
Path: ".metadata.name", | ||
Required: true, | ||
}, | ||
} | ||
if resourceScope == types.NamespaceScope { | ||
params = append(params, types.CustomFlag{ | ||
Name: "namespace", | ||
Type: types.StringCustomFlagType, | ||
Description: "resource namespace", | ||
Path: ".metadata.namespace", | ||
DefaultValue: "default", | ||
}) | ||
} | ||
|
||
return params | ||
} | ||
|
||
func getResourceName(scope types.Scope, u *unstructured.Unstructured) string { | ||
if scope == types.NamespaceScope { | ||
return fmt.Sprintf("%s/%s", u.GetNamespace(), u.GetName()) | ||
} | ||
|
||
return u.GetName() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.