add kn service delete --all (#836)

This commit is contained in:
Daniel Helfand 2020-05-14 06:51:59 -04:00 committed by GitHub
parent 9bbce80ffa
commit 6f615c6595
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 124 additions and 3 deletions

View File

@ -16,6 +16,10 @@
|=== |===
| | Description | PR | | Description | PR
| 🎁
| Add kn service delete --all
| https://github.com/knative/client/pull/836[#836]
| 🐛 | 🐛
| Skip LatestReadyRevisionName if Revision is Pending or Unknown | Skip LatestReadyRevisionName if Revision is Pending or Unknown
| https://github.com/knative/client/pull/825[#825] | https://github.com/knative/client/pull/825[#825]

View File

@ -19,11 +19,15 @@ kn service delete NAME [flags]
# Delete a service 'svc2' in 'ns1' namespace # Delete a service 'svc2' in 'ns1' namespace
kn service delete svc2 -n ns1 kn service delete svc2 -n ns1
# Delete all services in 'ns1' namespace
kn service delete --all -n ns1
``` ```
### Options ### Options
``` ```
--all Delete all services in a namespace.
--async DEPRECATED: please use --no-wait instead. Do not wait for 'service delete' operation to be completed. (default true) --async DEPRECATED: please use --no-wait instead. Do not wait for 'service delete' operation to be completed. (default true)
-h, --help help for delete -h, --help help for delete
-n, --namespace string Specify the namespace to operate in. -n, --namespace string Specify the namespace to operate in.

View File

@ -22,6 +22,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"knative.dev/client/pkg/kn/commands" "knative.dev/client/pkg/kn/commands"
clientservingv1 "knative.dev/client/pkg/serving/v1"
) )
// NewServiceDeleteCommand represent 'service delete' command // NewServiceDeleteCommand represent 'service delete' command
@ -36,13 +37,26 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command {
kn service delete svc1 kn service delete svc1
# Delete a service 'svc2' in 'ns1' namespace # Delete a service 'svc2' in 'ns1' namespace
kn service delete svc2 -n ns1`, kn service delete svc2 -n ns1
# Delete all services in 'ns1' namespace
kn service delete --all -n ns1`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 { all, err := cmd.Flags().GetBool("all")
if err != nil {
return err
}
argsLen := len(args)
if argsLen < 1 && !all {
return errors.New("'service delete' requires the service name(s)") return errors.New("'service delete' requires the service name(s)")
} }
if argsLen > 0 && all {
return errors.New("'service delete' with --all flag requires no arguments")
}
namespace, err := p.GetNamespace(cmd) namespace, err := p.GetNamespace(cmd)
if err != nil { if err != nil {
return err return err
@ -51,6 +65,18 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command {
if err != nil { if err != nil {
return err return err
} }
if all {
args, err = getServiceNames(client)
if err != nil {
return err
}
if len(args) == 0 {
fmt.Fprintf(cmd.OutOrStdout(), "No services found.\n")
return nil
}
}
for _, name := range args { for _, name := range args {
timeout := time.Duration(0) timeout := time.Duration(0)
if waitFlags.Wait { if waitFlags.Wait {
@ -66,7 +92,21 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command {
return nil return nil
}, },
} }
flags := serviceDeleteCommand.Flags()
flags.Bool("all", false, "Delete all services in a namespace.")
commands.AddNamespaceFlags(serviceDeleteCommand.Flags(), false) commands.AddNamespaceFlags(serviceDeleteCommand.Flags(), false)
waitFlags.AddConditionWaitFlags(serviceDeleteCommand, commands.WaitDefaultTimeout, "delete", "service", "deleted") waitFlags.AddConditionWaitFlags(serviceDeleteCommand, commands.WaitDefaultTimeout, "delete", "service", "deleted")
return serviceDeleteCommand return serviceDeleteCommand
} }
func getServiceNames(client clientservingv1.KnServingClient) ([]string, error) {
serviceList, err := client.ListServices()
if err != nil {
return []string{}, err
}
serviceNames := []string{}
for _, service := range serviceList.Items {
serviceNames = append(serviceNames, service.Name)
}
return serviceNames, nil
}

View File

@ -22,6 +22,7 @@ import (
clientservingv1 "knative.dev/client/pkg/serving/v1" clientservingv1 "knative.dev/client/pkg/serving/v1"
"knative.dev/client/pkg/util" "knative.dev/client/pkg/util"
"knative.dev/client/pkg/util/mock" "knative.dev/client/pkg/util/mock"
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
) )
func TestServiceDeleteMock(t *testing.T) { func TestServiceDeleteMock(t *testing.T) {
@ -77,6 +78,56 @@ func TestMultipleServiceDeleteMock(t *testing.T) {
r.Validate() r.Validate()
} }
func TestServiceDeleteAllMock(t *testing.T) {
// New mock client
client := clientservingv1.NewMockKnServiceClient(t)
// Recording:
r := client.Recorder()
// Wait for delete event
r.DeleteService("foo", mock.Any(), nil)
r.DeleteService("bar", mock.Any(), nil)
r.DeleteService("baz", mock.Any(), nil)
service1 := createMockServiceWithParams("foo", "default", "http://foo.default.example.com", "foo-xyz")
service2 := createMockServiceWithParams("bar", "default", "http://bar.default.example.com", "bar-xyz")
service3 := createMockServiceWithParams("baz", "default", "http://baz.default.example.com", "baz-xyz")
serviceList := &servingv1.ServiceList{Items: []servingv1.Service{*service1, *service2, *service3}}
r.ListServices(mock.Any(), serviceList, nil)
output, err := executeServiceCommand(client, "delete", "--all")
assert.NilError(t, err)
assert.Assert(t, util.ContainsAll(output, "deleted", "foo", "bar", "baz", "default"))
r.Validate()
}
func TestServiceDeleteAllErrorFromArgMock(t *testing.T) {
// New mock client
client := clientservingv1.NewMockKnServiceClient(t)
_, err := executeServiceCommand(client, "delete", "foo", "--all")
assert.Error(t, err, "'service delete' with --all flag requires no arguments")
}
func TestServiceDeleteAllNoServicesMock(t *testing.T) {
// New mock client
client := clientservingv1.NewMockKnServiceClient(t)
// Recording:
r := client.Recorder()
serviceList := &servingv1.ServiceList{Items: []servingv1.Service{}}
r.ListServices(mock.Any(), serviceList, nil)
output, err := executeServiceCommand(client, "delete", "--all")
assert.NilError(t, err)
assert.Assert(t, util.ContainsAll(output, "No", "services", "found"))
r.Validate()
}
func TestServiceDeleteNoSvcNameMock(t *testing.T) { func TestServiceDeleteNoSvcNameMock(t *testing.T) {
// New mock client // New mock client
client := clientservingv1.NewMockKnServiceClient(t) client := clientservingv1.NewMockKnServiceClient(t)

View File

@ -94,8 +94,8 @@ func TestServiceListDefaultOutputMock(t *testing.T) {
r := client.Recorder() r := client.Recorder()
service1 := createMockServiceWithParams("foo", "default", "http://foo.default.example.com", "foo-xyz") service1 := createMockServiceWithParams("foo", "default", "http://foo.default.example.com", "foo-xyz")
service3 := createMockServiceWithParams("sss", "default", "http://sss.default.example.com", "sss-xyz")
service2 := createMockServiceWithParams("bar", "default", "http://bar.default.example.com", "bar-xyz") service2 := createMockServiceWithParams("bar", "default", "http://bar.default.example.com", "bar-xyz")
service3 := createMockServiceWithParams("sss", "default", "http://sss.default.example.com", "sss-xyz")
serviceList := &servingv1.ServiceList{Items: []servingv1.Service{*service1, *service2, *service3}} serviceList := &servingv1.ServiceList{Items: []servingv1.Service{*service1, *service2, *service3}}
r.ListServices(mock.Any(), serviceList, nil) r.ListServices(mock.Any(), serviceList, nil)

View File

@ -58,6 +58,12 @@ func TestService(t *testing.T) {
t.Log("create service private and make public") t.Log("create service private and make public")
serviceCreatePrivateUpdatePublic(r, "hello-private-public") serviceCreatePrivateUpdatePublic(r, "hello-private-public")
t.Log("delete all services in a namespace")
test.ServiceCreate(r, "svc1")
test.ServiceCreate(r, "service2")
test.ServiceCreate(r, "ksvc3")
serviceDeleteAll(r, "svc1", "service2", "ksvc3")
} }
func serviceCreatePrivate(r *test.KnRunResultCollector, serviceName string) { func serviceCreatePrivate(r *test.KnRunResultCollector, serviceName string) {
@ -133,3 +139,19 @@ func serviceMultipleDelete(r *test.KnRunResultCollector, existService, nonexistS
assert.Check(r.T(), strings.Contains(out.Stdout, expectedSuccess), "Failed to get 'successfully deleted' message") assert.Check(r.T(), strings.Contains(out.Stdout, expectedSuccess), "Failed to get 'successfully deleted' message")
assert.Check(r.T(), strings.Contains(out.Stdout, expectedErr), "Failed to get 'not found' error") assert.Check(r.T(), strings.Contains(out.Stdout, expectedErr), "Failed to get 'not found' error")
} }
func serviceDeleteAll(r *test.KnRunResultCollector, service1 string, service2 string, service3 string) {
out := r.KnTest().Kn().Run("service", "list")
r.AssertNoError(out)
assert.Check(r.T(), strings.Contains(out.Stdout, service1), "The service ", service1, " does not exist (but is expected to exist)")
assert.Check(r.T(), strings.Contains(out.Stdout, service2), "The service ", service2, " does not exist (but is expected to exist)")
assert.Check(r.T(), strings.Contains(out.Stdout, service3), "The service ", service3, " does not exist (but is expected to exist)")
out = r.KnTest().Kn().Run("service", "delete", "--all")
r.AssertNoError(out)
namespace := r.KnTest().Kn().Namespace()
expectedSuccess := fmt.Sprintf("Service '%s' successfully deleted in namespace '%s'.\nService '%s' successfully deleted in namespace '%s'.\nService '%s' successfully deleted in namespace '%s'.\n",
service3, namespace, service2, namespace, service1, namespace)
assert.Check(r.T(), strings.Contains(out.Stdout, expectedSuccess), "Failed to get 'successfully deleted' message")
}