diff --git a/pkg/kubectl/cmd/get.go b/pkg/kubectl/cmd/get.go index fb85104f7ff..cc3c68ca632 100644 --- a/pkg/kubectl/cmd/get.go +++ b/pkg/kubectl/cmd/get.go @@ -23,6 +23,7 @@ import ( "github.com/spf13/cobra" "github.com/golang/glog" + kapierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -42,7 +43,8 @@ import ( type GetOptions struct { resource.FilenameOptions - Raw string + IgnoreNotFound bool + Raw string } var ( @@ -121,6 +123,7 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman cmd.Flags().Bool("watch-only", false, "Watch for changes to the requested object(s), without listing/getting first.") cmd.Flags().Bool("show-kind", false, "If present, list the resource type for the requested object(s).") cmd.Flags().Bool("all-namespaces", false, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.") + cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", false, "Treat \"resource not found\" as a successful retrieval.") cmd.Flags().StringSliceP("label-columns", "L", []string{}, "Accepts a comma separated list of labels that are going to be presented as columns. Names are case-sensitive. You can also use multiple flag options like -L label1 -L label2...") cmd.Flags().Bool("export", false, "If true, use 'export' for the resources. Exported resources are stripped of cluster-specific information.") usage := "identifying the resource to get from a server." @@ -305,6 +308,10 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ return err } + if options.IgnoreNotFound { + r.IgnoreErrors(kapierrors.IsNotFound) + } + if generic { // we flattened the data from the builder, so we have individual items, but now we'd like to either: // 1. if there is more than one item, combine them all into a single list @@ -320,6 +327,10 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ errs = append(errs, err) } + if len(infos) == 0 && options.IgnoreNotFound { + return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs))) + } + res := "" if len(infos) > 0 { res = infos[0].ResourceMapping().Resource @@ -395,7 +406,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ if err != nil { allErrs = append(allErrs, err) } - if len(infos) == 0 && len(allErrs) == 0 { + if len(infos) == 0 && len(allErrs) == 0 && !options.IgnoreNotFound { outputEmptyListWarning(errOut) } diff --git a/pkg/kubectl/cmd/get_test.go b/pkg/kubectl/cmd/get_test.go index 39200512d1f..8bd6e4be479 100644 --- a/pkg/kubectl/cmd/get_test.go +++ b/pkg/kubectl/cmd/get_test.go @@ -210,6 +210,53 @@ func TestGetObjects(t *testing.T) { } } +func TestGetObjectIgnoreNotFound(t *testing.T) { + initTestErrorHandler(t) + + ns := &api.NamespaceList{ + ListMeta: metav1.ListMeta{ + ResourceVersion: "1", + }, + Items: []api.Namespace{ + { + ObjectMeta: metav1.ObjectMeta{Name: "testns", Namespace: "test", ResourceVersion: "11"}, + Spec: api.NamespaceSpec{}, + }, + }, + } + + f, tf, codec, _ := cmdtesting.NewAPIFactory() + tf.Printer = &testPrinter{} + tf.UnstructuredClient = &fake.RESTClient{ + APIRegistry: api.Registry, + NegotiatedSerializer: unstructuredSerializer, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + switch p, m := req.URL.Path, req.Method; { + case p == "/namespaces/test/pods/nonexistentpod" && m == "GET": + return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: stringBody("")}, nil + case p == "/api/v1/namespaces/test" && m == "GET": + return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &ns.Items[0])}, nil + default: + t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) + return nil, nil + } + }), + } + tf.Namespace = "test" + buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) + + cmd := NewCmdGet(f, buf, errBuf) + cmd.SetOutput(buf) + cmd.Flags().Set("ignore-not-found", "true") + cmd.Flags().Set("output", "yaml") + cmd.Run(cmd, []string{"pods", "nonexistentpod"}) + + if buf.String() != "" { + t.Errorf("unexpected output: %s", buf.String()) + } +} + func TestGetSortedObjects(t *testing.T) { pods := &api.PodList{ ListMeta: metav1.ListMeta{