From 3e7f6e508a03f77170e7251863085ecd813c18ad Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Fri, 28 Jun 2019 11:55:31 -0700 Subject: [PATCH] Add client-side status object handling --- pkg/kubectl/cmd/get/get_test.go | 47 +++++++++++++++++++++++++++++++++ pkg/printers/tableprinter.go | 42 ++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 6 deletions(-) diff --git a/pkg/kubectl/cmd/get/get_test.go b/pkg/kubectl/cmd/get/get_test.go index 58fa55e1c52..85f7de6ab30 100644 --- a/pkg/kubectl/cmd/get/get_test.go +++ b/pkg/kubectl/cmd/get/get_test.go @@ -1855,6 +1855,53 @@ foo } } +func TestWatchStatus(t *testing.T) { + pods, events := watchTestData() + events = append(events, watch.Event{Type: "ERROR", Object: &metav1.Status{Status: "Failure", Reason: "InternalServerError", Message: "Something happened"}}) + + tf := cmdtesting.NewTestFactory().WithNamespace("test") + defer tf.Cleanup() + codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...) + + tf.UnstructuredClient = &fake.RESTClient{ + NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + switch req.URL.Path { + case "/namespaces/test/pods/foo": + return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil + case "/namespaces/test/pods": + if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=foo" { + return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[1:])}, nil + } + t.Fatalf("request url: %#v,and request: %#v", req.URL, req) + return nil, nil + default: + t.Fatalf("request url: %#v,and request: %#v", req.URL, req) + return nil, nil + } + }), + } + + streams, _, buf, _ := genericclioptions.NewTestIOStreams() + cmd := NewCmdGet("kubectl", tf, streams) + cmd.SetOutput(buf) + + cmd.Flags().Set("watch", "true") + cmd.Run(cmd, []string{"pods", "foo"}) + + expected := `NAME AGE +foo +foo +foo + +STATUS REASON MESSAGE +Failure InternalServerError Something happened +` + if e, a := expected, buf.String(); e != a { + t.Errorf("expected\n%v\ngot\n%v", e, a) + } +} + func TestWatchTableResource(t *testing.T) { pods, events := watchTestData() diff --git a/pkg/printers/tableprinter.go b/pkg/printers/tableprinter.go index 2e0ec209193..94acaade978 100644 --- a/pkg/printers/tableprinter.go +++ b/pkg/printers/tableprinter.go @@ -35,6 +35,17 @@ import ( var _ ResourcePrinter = &HumanReadablePrinter{} var ( + statusHandlerEntry = &handlerEntry{ + columnDefinitions: statusColumnDefinitions, + printFunc: reflect.ValueOf(printStatus), + } + + statusColumnDefinitions = []metav1beta1.TableColumnDefinition{ + {Name: "Status", Type: "string"}, + {Name: "Reason", Type: "string"}, + {Name: "Message", Type: "string"}, + } + defaultHandlerEntry = &handlerEntry{ columnDefinitions: objectMetaColumnDefinitions, printFunc: reflect.ValueOf(printObjectMeta), @@ -122,18 +133,26 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er return nil } - // Case 3: Could not find print handler for "obj"; use the default print handler. - // Print with the default handler, and use the columns from the last time - includeHeaders := h.lastType != defaultHandlerEntry && !h.options.NoHeaders + // Case 3: Could not find print handler for "obj"; use the default or status print handler. + // Print with the default or status handler, and use the columns from the last time + var handler *handlerEntry + if _, isStatus := obj.(*metav1.Status); isStatus { + handler = statusHandlerEntry + } else { + handler = defaultHandlerEntry + } - if h.lastType != nil && h.lastType != defaultHandlerEntry && !h.options.NoHeaders { + includeHeaders := h.lastType != handler && !h.options.NoHeaders + + if h.lastType != nil && h.lastType != handler && !h.options.NoHeaders { fmt.Fprintln(output) } - if err := printRowsForHandlerEntry(output, defaultHandlerEntry, obj, h.options, includeHeaders); err != nil { + if err := printRowsForHandlerEntry(output, handler, obj, h.options, includeHeaders); err != nil { return err } - h.lastType = defaultHandlerEntry + h.lastType = handler + return nil } @@ -399,6 +418,17 @@ func appendLabelCells(values []interface{}, itemLabels map[string]string, opts P return values } +func printStatus(obj runtime.Object, options PrintOptions) ([]metav1beta1.TableRow, error) { + status, ok := obj.(*metav1.Status) + if !ok { + return nil, fmt.Errorf("expected *v1.Status, got %T", obj) + } + return []metav1beta1.TableRow{{ + Object: runtime.RawExtension{Object: obj}, + Cells: []interface{}{status.Status, status.Reason, status.Message}, + }}, nil +} + func printObjectMeta(obj runtime.Object, options PrintOptions) ([]metav1beta1.TableRow, error) { if meta.IsListType(obj) { rows := make([]metav1beta1.TableRow, 0, 16)