diff --git a/pkg/kubectl/cmd/resource/get.go b/pkg/kubectl/cmd/resource/get.go index e4b4256a97..9de4c14358 100644 --- a/pkg/kubectl/cmd/resource/get.go +++ b/pkg/kubectl/cmd/resource/get.go @@ -388,6 +388,11 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str updatePrintOptionsForOpenAPI(f, mapping, printOpts) } + if showKind && mapping != nil { + printOpts.WithKind = true + printOpts.Kind = mapping.GroupVersionKind.GroupKind() + } + printer, err = cmdutil.PrinterForOptions(printOpts) if err != nil { if !errs.Has(err.Error()) { @@ -409,33 +414,6 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str typedObj := info.AsInternal() - if resourcePrinter, found := printer.(*printers.HumanReadablePrinter); found { - resourceName := resourcePrinter.GetResourceKind() - if mapping != nil { - if resourceName == "" { - resourceName = mapping.Resource - } - if alias, ok := kubectl.ResourceShortFormFor(mapping.Resource); ok { - resourceName = alias - } else if resourceName == "" { - resourceName = "none" - } - } else { - resourceName = "none" - } - - if showKind { - resourcePrinter.EnsurePrintWithKind(resourceName) - } - - if err := printer.PrintObj(typedObj, w); err != nil { - if !errs.Has(err.Error()) { - errs.Insert(err.Error()) - allErrs = append(allErrs, err) - } - } - continue - } objToPrint := typedObj if printer.IsGeneric() { // use raw object as received from the builder when using generic diff --git a/pkg/kubectl/cmd/resource/get_test.go b/pkg/kubectl/cmd/resource/get_test.go index 7ee21d8a19..0c45b920c4 100644 --- a/pkg/kubectl/cmd/resource/get_test.go +++ b/pkg/kubectl/cmd/resource/get_test.go @@ -658,10 +658,10 @@ func TestGetMultipleTypeObjects(t *testing.T) { cmd.Run(cmd, []string{"pods,services"}) expected := `NAME READY STATUS RESTARTS AGE -foo 0/0 0 -bar 0/0 0 -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -baz ClusterIP +pod/foo 0/0 0 +pod/bar 0/0 0 +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/baz ClusterIP ` if e, a := expected, buf.String(); e != a { t.Errorf("expected %v, got %v", e, a) @@ -806,10 +806,10 @@ func TestGetMultipleTypeObjectsWithLabelSelector(t *testing.T) { cmd.Run(cmd, []string{"pods,services"}) expected := `NAME READY STATUS RESTARTS AGE -foo 0/0 0 -bar 0/0 0 -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -baz ClusterIP +pod/foo 0/0 0 +pod/bar 0/0 0 +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/baz ClusterIP ` if e, a := expected, buf.String(); e != a { t.Errorf("expected %v, got %v", e, a) @@ -851,10 +851,10 @@ func TestGetMultipleTypeObjectsWithFieldSelector(t *testing.T) { cmd.Run(cmd, []string{"pods,services"}) expected := `NAME READY STATUS RESTARTS AGE -foo 0/0 0 -bar 0/0 0 -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -baz ClusterIP +pod/foo 0/0 0 +pod/bar 0/0 0 +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/baz ClusterIP ` if e, a := expected, buf.String(); e != a { t.Errorf("expected %v, got %v", e, a) @@ -899,10 +899,10 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) { cmd.Run(cmd, []string{"services/bar", "node/foo"}) - expected := `NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -baz ClusterIP -NAME STATUS ROLES AGE VERSION -foo Unknown + expected := `NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/baz ClusterIP +NAME STATUS ROLES AGE VERSION +node/foo Unknown ` if e, a := expected, buf.String(); e != a { t.Errorf("expected %v, got %v", e, a) diff --git a/pkg/printers/humanreadable.go b/pkg/printers/humanreadable.go index 9a9be21469..79f580df7f 100644 --- a/pkg/printers/humanreadable.go +++ b/pkg/printers/humanreadable.go @@ -101,19 +101,6 @@ func (a *HumanReadablePrinter) With(fns ...func(PrintHandler)) *HumanReadablePri return a } -// GetResourceKind returns the type currently set for a resource -func (h *HumanReadablePrinter) GetResourceKind() string { - return h.options.Kind -} - -// EnsurePrintWithKind sets HumanReadablePrinter options "WithKind" to true -// and "Kind" to the string arg it receives, pre-pending this string -// to the "NAME" column in an output of resources. -func (h *HumanReadablePrinter) EnsurePrintWithKind(kind string) { - h.options.WithKind = true - h.options.Kind = kind -} - // EnsurePrintHeaders sets the HumanReadablePrinter option "NoHeaders" to false // and removes the .lastType that was printed, which forces headers to be // printed in cases where multiple lists of the same resource are printed @@ -411,7 +398,7 @@ func DecorateTable(table *metav1beta1.Table, options PrintOptions) error { columns := table.ColumnDefinitions nameColumn := -1 - if options.WithKind && len(options.Kind) > 0 { + if options.WithKind && !options.Kind.Empty() { for i := range columns { if columns[i].Format == "name" && columns[i].Type == "string" { nameColumn = i @@ -451,7 +438,7 @@ func DecorateTable(table *metav1beta1.Table, options PrintOptions) error { row := rows[i] if nameColumn != -1 { - row.Cells[nameColumn] = fmt.Sprintf("%s/%s", options.Kind, row.Cells[nameColumn]) + row.Cells[nameColumn] = fmt.Sprintf("%s/%s", strings.ToLower(options.Kind.String()), row.Cells[nameColumn]) } var m metav1.Object @@ -607,8 +594,8 @@ func printRows(output io.Writer, rows []metav1beta1.TableRow, options PrintOptio fmt.Fprint(output, "\t") } else { // TODO: remove this once we drop the legacy printers - if options.WithKind && len(options.Kind) > 0 { - fmt.Fprintf(output, "%s/%s", options.Kind, cell) + if options.WithKind && !options.Kind.Empty() { + fmt.Fprintf(output, "%s/%s", strings.ToLower(options.Kind.String()), cell) continue } } @@ -785,12 +772,12 @@ func appendLabelCells(values []interface{}, itemLabels map[string]string, opts P // FormatResourceName receives a resource kind, name, and boolean specifying // whether or not to update the current name to "kind/name" -func FormatResourceName(kind, name string, withKind bool) string { - if !withKind || kind == "" { +func FormatResourceName(kind schema.GroupKind, name string, withKind bool) string { + if !withKind || kind.Empty() { return name } - return kind + "/" + name + return strings.ToLower(kind.String()) + "/" + name } func AppendLabels(itemLabels map[string]string, columnLabels []string) string { diff --git a/pkg/printers/interface.go b/pkg/printers/interface.go index 5bda6c6175..840ae08593 100644 --- a/pkg/printers/interface.go +++ b/pkg/printers/interface.go @@ -21,6 +21,7 @@ import ( "io" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" ) // ResourcePrinter is an interface that knows how to print runtime objects. @@ -68,7 +69,7 @@ type PrintOptions struct { ShowAll bool ShowLabels bool AbsoluteTimestamps bool - Kind string + Kind schema.GroupKind ColumnLabels []string SortBy string diff --git a/pkg/printers/internalversion/printers.go b/pkg/printers/internalversion/printers.go index 8bd16016bd..08475be5c0 100644 --- a/pkg/printers/internalversion/printers.go +++ b/pkg/printers/internalversion/printers.go @@ -40,6 +40,7 @@ import ( metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/duration" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kubernetes/pkg/api/events" @@ -1759,7 +1760,12 @@ func printControllerRevision(obj *apps.ControllerRevision, options printers.Prin controllerName := "" if controllerRef != nil { withKind := true - controllerName = printers.FormatResourceName(controllerRef.Kind, controllerRef.Name, withKind) + gv, err := schema.ParseGroupVersion(controllerRef.APIVersion) + if err != nil { + return nil, err + } + gvk := gv.WithKind(controllerRef.Kind) + controllerName = printers.FormatResourceName(gvk.GroupKind(), controllerRef.Name, withKind) } revision := obj.Revision age := translateTimestamp(obj.CreationTimestamp) diff --git a/pkg/printers/internalversion/printers_test.go b/pkg/printers/internalversion/printers_test.go index 5e5ca00ba7..9fda8a66cb 100644 --- a/pkg/printers/internalversion/printers_test.go +++ b/pkg/printers/internalversion/printers_test.go @@ -375,13 +375,15 @@ func TestJSONPrinter(t *testing.T) { func TestFormatResourceName(t *testing.T) { tests := []struct { - kind, name string - want string + kind schema.GroupKind + name string + want string }{ - {"", "", ""}, - {"", "name", "name"}, - {"kind", "", "kind/"}, // should not happen in practice - {"kind", "name", "kind/name"}, + {schema.GroupKind{}, "", ""}, + {schema.GroupKind{}, "name", "name"}, + {schema.GroupKind{Kind: "Kind"}, "", "kind/"}, // should not happen in practice + {schema.GroupKind{Kind: "Kind"}, "name", "kind/name"}, + {schema.GroupKind{Group: "group", Kind: "Kind"}, "name", "kind.group/name"}, } for _, tt := range tests { if got := printers.FormatResourceName(tt.kind, tt.name, true); got != tt.want { @@ -394,7 +396,7 @@ func PrintCustomType(obj *TestPrintType, w io.Writer, options printers.PrintOpti data := obj.Data kind := options.Kind if options.WithKind { - data = kind + "/" + data + data = kind.String() + "/" + data } _, err := fmt.Fprintf(w, "%s", data) return err @@ -421,24 +423,6 @@ func TestCustomTypePrinting(t *testing.T) { } } -func TestCustomTypePrintingWithKind(t *testing.T) { - columns := []string{"Data"} - printer := printers.NewHumanReadablePrinter(nil, nil, printers.PrintOptions{}) - printer.Handler(columns, nil, PrintCustomType) - printer.EnsurePrintWithKind("test") - - obj := TestPrintType{"test object"} - buffer := &bytes.Buffer{} - err := printer.PrintObj(&obj, buffer) - if err != nil { - t.Fatalf("An error occurred printing the custom type: %#v", err) - } - expectedOutput := "DATA\ntest/test object" - if buffer.String() != expectedOutput { - t.Errorf("The data was not printed as expected. Expected:\n%s\nGot:\n%s", expectedOutput, buffer.String()) - } -} - func TestPrintHandlerError(t *testing.T) { columns := []string{"Data"} printer := printers.NewHumanReadablePrinter(nil, nil, printers.PrintOptions{}) @@ -1582,8 +1566,8 @@ func TestPrintPodTable(t *testing.T) { expect: "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\ntest1\t1/2\tRunning\t6\t\n", }, { - obj: runningPod, opts: printers.PrintOptions{WithKind: true, Kind: "pods"}, - expect: "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\npods/test1\t1/2\tRunning\t6\t\n", + obj: runningPod, opts: printers.PrintOptions{WithKind: true, Kind: schema.GroupKind{Kind: "Pod"}}, + expect: "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\npod/test1\t1/2\tRunning\t6\t\n", }, { obj: runningPod, opts: printers.PrintOptions{ShowLabels: true}, @@ -3058,6 +3042,7 @@ func TestPrintControllerRevision(t *testing.T) { OwnerReferences: []metav1.OwnerReference{ { Controller: boolP(true), + APIVersion: "apps/v1", Kind: "DaemonSet", Name: "foo", }, @@ -3065,7 +3050,7 @@ func TestPrintControllerRevision(t *testing.T) { }, Revision: 1, }, - "test1\tDaemonSet/foo\t1\t0s\n", + "test1\tdaemonset.apps/foo\t1\t0s\n", }, { apps.ControllerRevision{