Allow delete multiple resources with the same name
This commit is contained in:
		@@ -174,6 +174,9 @@ $ kubectl delete \-f ./pod.json
 | 
				
			|||||||
# Delete a pod based on the type and name in the JSON passed into stdin.
 | 
					# Delete a pod based on the type and name in the JSON passed into stdin.
 | 
				
			||||||
$ cat pod.json | kubectl delete \-f \-
 | 
					$ cat pod.json | kubectl delete \-f \-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Delete pods and services with same names "baz" and "foo"
 | 
				
			||||||
 | 
					$ kubectl delete pod,service baz foo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Delete pods and services with label name=myLabel.
 | 
					# Delete pods and services with label name=myLabel.
 | 
				
			||||||
$ kubectl delete pods,services \-l name=myLabel
 | 
					$ kubectl delete pods,services \-l name=myLabel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,6 +61,9 @@ $ kubectl delete -f ./pod.json
 | 
				
			|||||||
# Delete a pod based on the type and name in the JSON passed into stdin.
 | 
					# Delete a pod based on the type and name in the JSON passed into stdin.
 | 
				
			||||||
$ cat pod.json | kubectl delete -f -
 | 
					$ cat pod.json | kubectl delete -f -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Delete pods and services with same names "baz" and "foo"
 | 
				
			||||||
 | 
					$ kubectl delete pod,service baz foo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Delete pods and services with label name=myLabel.
 | 
					# Delete pods and services with label name=myLabel.
 | 
				
			||||||
$ kubectl delete pods,services -l name=myLabel
 | 
					$ kubectl delete pods,services -l name=myLabel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -118,7 +121,7 @@ $ kubectl delete pods --all
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
* [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager
 | 
					* [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###### Auto generated by spf13/cobra at 2015-08-20 22:01:12.476048394 +0000 UTC
 | 
					###### Auto generated by spf13/cobra at 2015-08-21 06:18:47.444397685 +0000 UTC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
 | 
					<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
 | 
				
			||||||
[]()
 | 
					[]()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,9 @@ $ kubectl delete -f ./pod.json
 | 
				
			|||||||
# Delete a pod based on the type and name in the JSON passed into stdin.
 | 
					# Delete a pod based on the type and name in the JSON passed into stdin.
 | 
				
			||||||
$ cat pod.json | kubectl delete -f -
 | 
					$ cat pod.json | kubectl delete -f -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Delete pods and services with same names "baz" and "foo"
 | 
				
			||||||
 | 
					$ kubectl delete pod,service baz foo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Delete pods and services with label name=myLabel.
 | 
					# Delete pods and services with label name=myLabel.
 | 
				
			||||||
$ kubectl delete pods,services -l name=myLabel
 | 
					$ kubectl delete pods,services -l name=myLabel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -335,6 +335,41 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDeleteMultipleResourcesWithTheSameName(t *testing.T) {
 | 
				
			||||||
 | 
						_, svc, rc := testData()
 | 
				
			||||||
 | 
						f, tf, codec := NewAPIFactory()
 | 
				
			||||||
 | 
						tf.Printer = &testPrinter{}
 | 
				
			||||||
 | 
						tf.Client = &client.FakeRESTClient{
 | 
				
			||||||
 | 
							Codec: codec,
 | 
				
			||||||
 | 
							Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
 | 
								switch p, m := req.URL.Path, req.Method; {
 | 
				
			||||||
 | 
								case p == "/namespaces/test/replicationcontrollers/baz" && m == "DELETE":
 | 
				
			||||||
 | 
									return &http.Response{StatusCode: 200, Body: objBody(codec, &rc.Items[0])}, nil
 | 
				
			||||||
 | 
								case p == "/namespaces/test/replicationcontrollers/foo" && m == "DELETE":
 | 
				
			||||||
 | 
									return &http.Response{StatusCode: 200, Body: objBody(codec, &rc.Items[0])}, nil
 | 
				
			||||||
 | 
								case p == "/namespaces/test/services/baz" && m == "DELETE":
 | 
				
			||||||
 | 
									return &http.Response{StatusCode: 200, Body: objBody(codec, &svc.Items[0])}, nil
 | 
				
			||||||
 | 
								case p == "/namespaces/test/services/foo" && m == "DELETE":
 | 
				
			||||||
 | 
									return &http.Response{StatusCode: 200, Body: objBody(codec, &svc.Items[0])}, nil
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									// Ensures no GET is performed when deleting by name
 | 
				
			||||||
 | 
									t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
 | 
				
			||||||
 | 
									return nil, nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tf.Namespace = "test"
 | 
				
			||||||
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
						cmd := NewCmdDelete(f, buf)
 | 
				
			||||||
 | 
						cmd.Flags().Set("namespace", "test")
 | 
				
			||||||
 | 
						cmd.Flags().Set("cascade", "false")
 | 
				
			||||||
 | 
						cmd.Flags().Set("output", "name")
 | 
				
			||||||
 | 
						cmd.Run(cmd, []string{"replicationcontrollers,services", "baz", "foo"})
 | 
				
			||||||
 | 
						if buf.String() != "replicationcontroller/baz\nreplicationcontroller/foo\nservice/baz\nservice/foo\n" {
 | 
				
			||||||
 | 
							t.Errorf("unexpected output: %s", buf.String())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDeleteDirectory(t *testing.T) {
 | 
					func TestDeleteDirectory(t *testing.T) {
 | 
				
			||||||
	_, svc, rc := testData()
 | 
						_, svc, rc := testData()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -256,6 +256,23 @@ func (b *Builder) SelectAllParam(selectAll bool) *Builder {
 | 
				
			|||||||
// When two or more arguments are received, they must be a single type and resource name(s).
 | 
					// When two or more arguments are received, they must be a single type and resource name(s).
 | 
				
			||||||
// The allowEmptySelector permits to select all the resources (via Everything func).
 | 
					// The allowEmptySelector permits to select all the resources (via Everything func).
 | 
				
			||||||
func (b *Builder) ResourceTypeOrNameArgs(allowEmptySelector bool, args ...string) *Builder {
 | 
					func (b *Builder) ResourceTypeOrNameArgs(allowEmptySelector bool, args ...string) *Builder {
 | 
				
			||||||
 | 
						// convert multiple resources to resource tuples, a,b,c d as a transform to a/d b/d c/d
 | 
				
			||||||
 | 
						if len(args) >= 2 {
 | 
				
			||||||
 | 
							resources := []string{}
 | 
				
			||||||
 | 
							resources = append(resources, SplitResourceArgument(args[0])...)
 | 
				
			||||||
 | 
							if len(resources) > 1 {
 | 
				
			||||||
 | 
								names := []string{}
 | 
				
			||||||
 | 
								names = append(names, args[1:]...)
 | 
				
			||||||
 | 
								newArgs := []string{}
 | 
				
			||||||
 | 
								for _, resource := range resources {
 | 
				
			||||||
 | 
									for _, name := range names {
 | 
				
			||||||
 | 
										newArgs = append(newArgs, strings.Join([]string{resource, name}, "/"))
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								args = newArgs
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ok, err := hasCombinedTypeArgs(args); ok {
 | 
						if ok, err := hasCombinedTypeArgs(args); ok {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			b.errs = append(b.errs, err)
 | 
								b.errs = append(b.errs, err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -380,6 +380,38 @@ func TestResourceByName(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMultipleResourceByTheSameName(t *testing.T) {
 | 
				
			||||||
 | 
						pods, svcs := testData()
 | 
				
			||||||
 | 
						b := NewBuilder(latest.RESTMapper, api.Scheme, fakeClientWith("", t, map[string]string{
 | 
				
			||||||
 | 
							"/namespaces/test/pods/foo":     runtime.EncodeOrDie(latest.Codec, &pods.Items[0]),
 | 
				
			||||||
 | 
							"/namespaces/test/pods/baz":     runtime.EncodeOrDie(latest.Codec, &pods.Items[1]),
 | 
				
			||||||
 | 
							"/namespaces/test/services/foo": runtime.EncodeOrDie(latest.Codec, &svcs.Items[0]),
 | 
				
			||||||
 | 
							"/namespaces/test/services/baz": runtime.EncodeOrDie(latest.Codec, &svcs.Items[0]),
 | 
				
			||||||
 | 
						})).
 | 
				
			||||||
 | 
							NamespaceParam("test")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test := &testVisitor{}
 | 
				
			||||||
 | 
						singular := false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if b.Do().Err() == nil {
 | 
				
			||||||
 | 
							t.Errorf("unexpected non-error")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b.ResourceTypeOrNameArgs(true, "pods,services", "foo", "baz")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := b.Do().IntoSingular(&singular).Visit(test.Handle)
 | 
				
			||||||
 | 
						if err != nil || singular || len(test.Infos) != 4 {
 | 
				
			||||||
 | 
							t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !api.Semantic.DeepDerivative([]runtime.Object{&pods.Items[0], &pods.Items[1], &svcs.Items[0], &svcs.Items[0]}, test.Objects()) {
 | 
				
			||||||
 | 
							t.Errorf("unexpected visited objects: %#v", test.Objects())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := b.Do().ResourceMapping(); err == nil {
 | 
				
			||||||
 | 
							t.Errorf("unexpected non-error")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestResourceByNameWithoutRequireObject(t *testing.T) {
 | 
					func TestResourceByNameWithoutRequireObject(t *testing.T) {
 | 
				
			||||||
	b := NewBuilder(latest.RESTMapper, api.Scheme, fakeClientWith("", t, map[string]string{})).
 | 
						b := NewBuilder(latest.RESTMapper, api.Scheme, fakeClientWith("", t, map[string]string{})).
 | 
				
			||||||
		NamespaceParam("test")
 | 
							NamespaceParam("test")
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user