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

add --ignore-not-found option #41433

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 13 additions & 2 deletions pkg/kubectl/cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -42,7 +43,8 @@ import (
type GetOptions struct {
resource.FilenameOptions

Raw string
IgnoreNotFound bool
Raw string
}

var (
Expand Down Expand Up @@ -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."
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
}

Expand Down
47 changes: 47 additions & 0 deletions pkg/kubectl/cmd/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down