From 20b28312ea9278c7b93340d0eca71023c45a43b3 Mon Sep 17 00:00:00 2001 From: Craig Newton Date: Fri, 1 Mar 2024 08:57:23 +0100 Subject: [PATCH] Add namespace to NotFound error for kubectl logs command (#120111) Signed-off-by: Craig Newton --- .../src/k8s.io/kubectl/pkg/cmd/logs/logs.go | 4 ++ .../k8s.io/kubectl/pkg/cmd/logs/logs_test.go | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go b/staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go index 92a986bc4e3..0df11878547 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go @@ -29,6 +29,7 @@ import ( "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/cli-runtime/pkg/genericclioptions" @@ -276,6 +277,9 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []str } infos, err := builder.Do().Infos() if err != nil { + if apierrors.IsNotFound(err) { + err = fmt.Errorf("error from server (NotFound): %w in namespace %q", err, o.Namespace) + } return err } if o.Selector == "" && len(infos) != 1 { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/logs/logs_test.go b/staging/src/k8s.io/kubectl/pkg/cmd/logs/logs_test.go index 9300413ac36..80d584fd076 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/logs/logs_test.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/logs/logs_test.go @@ -30,8 +30,10 @@ import ( "time" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericiooptions" restclient "k8s.io/client-go/rest" @@ -833,6 +835,48 @@ func TestNoResourceFoundMessage(t *testing.T) { } } +func TestNoPodInNamespaceFoundMessage(t *testing.T) { + namespace, podName := "test", "bar" + + tf := cmdtesting.NewTestFactory().WithNamespace(namespace) + defer tf.Cleanup() + + ns := scheme.Codecs.WithoutConversion() + codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...) + errStatus := apierrors.NewNotFound(schema.GroupResource{Resource: "pods"}, podName).Status() + + tf.UnstructuredClient = &fake.RESTClient{ + NegotiatedSerializer: ns, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + switch req.URL.Path { + case fmt.Sprintf("/namespaces/%s/pods/%s", namespace, podName): + fallthrough + case fmt.Sprintf("/namespaces/%s/pods", namespace): + fallthrough + case fmt.Sprintf("/api/v1/namespaces/%s", namespace): + return &http.Response{StatusCode: http.StatusNotFound, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &errStatus)}, nil + default: + t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) + return nil, nil + } + }), + } + + streams, _, _, _ := genericiooptions.NewTestIOStreams() + cmd := NewCmdLogs(tf, streams) + o := NewLogsOptions(streams, false) + err := o.Complete(tf, cmd, []string{podName}) + + if err == nil { + t.Fatal("Expected NotFound error, got nil") + } + + expected := fmt.Sprintf("error from server (NotFound): pods %q not found in namespace %q", podName, namespace) + if e, a := expected, err.Error(); e != a { + t.Errorf("expected to find:\n\t%s\nfound:\n\t%s\n", e, a) + } +} + type responseWrapperMock struct { data io.Reader err error