Merge pull request #61985 from liggitt/show-kind

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Restore show-kind function when printing multiple kinds

Fixes #61979 

* Makes the human readable printer work off the options given to it for displaying kind
* Simplifies get.go to pass showkind/kind options into the printer rather than doing conditional fixup afterward

```release-note
kubectl: restore the ability to show resource kinds when displaying multiple objects
```
pull/8/head
Kubernetes Submit Queue 2018-04-01 20:07:56 -07:00 committed by GitHub
commit d3bed1e5c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 93 deletions

View File

@ -388,6 +388,11 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str
updatePrintOptionsForOpenAPI(f, mapping, printOpts) updatePrintOptionsForOpenAPI(f, mapping, printOpts)
} }
if showKind && mapping != nil {
printOpts.WithKind = true
printOpts.Kind = mapping.GroupVersionKind.GroupKind()
}
printer, err = cmdutil.PrinterForOptions(printOpts) printer, err = cmdutil.PrinterForOptions(printOpts)
if err != nil { if err != nil {
if !errs.Has(err.Error()) { if !errs.Has(err.Error()) {
@ -409,33 +414,6 @@ func (options *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []str
typedObj := info.AsInternal() 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 objToPrint := typedObj
if printer.IsGeneric() { if printer.IsGeneric() {
// use raw object as received from the builder when using generic // use raw object as received from the builder when using generic

View File

@ -658,10 +658,10 @@ func TestGetMultipleTypeObjects(t *testing.T) {
cmd.Run(cmd, []string{"pods,services"}) cmd.Run(cmd, []string{"pods,services"})
expected := `NAME READY STATUS RESTARTS AGE expected := `NAME READY STATUS RESTARTS AGE
foo 0/0 0 <unknown> pod/foo 0/0 0 <unknown>
bar 0/0 0 <unknown> pod/bar 0/0 0 <unknown>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
baz ClusterIP <none> <none> <none> <unknown> service/baz ClusterIP <none> <none> <none> <unknown>
` `
if e, a := expected, buf.String(); e != a { if e, a := expected, buf.String(); e != a {
t.Errorf("expected %v, got %v", 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"}) cmd.Run(cmd, []string{"pods,services"})
expected := `NAME READY STATUS RESTARTS AGE expected := `NAME READY STATUS RESTARTS AGE
foo 0/0 0 <unknown> pod/foo 0/0 0 <unknown>
bar 0/0 0 <unknown> pod/bar 0/0 0 <unknown>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
baz ClusterIP <none> <none> <none> <unknown> service/baz ClusterIP <none> <none> <none> <unknown>
` `
if e, a := expected, buf.String(); e != a { if e, a := expected, buf.String(); e != a {
t.Errorf("expected %v, got %v", 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"}) cmd.Run(cmd, []string{"pods,services"})
expected := `NAME READY STATUS RESTARTS AGE expected := `NAME READY STATUS RESTARTS AGE
foo 0/0 0 <unknown> pod/foo 0/0 0 <unknown>
bar 0/0 0 <unknown> pod/bar 0/0 0 <unknown>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
baz ClusterIP <none> <none> <none> <unknown> service/baz ClusterIP <none> <none> <none> <unknown>
` `
if e, a := expected, buf.String(); e != a { if e, a := expected, buf.String(); e != a {
t.Errorf("expected %v, got %v", 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"}) cmd.Run(cmd, []string{"services/bar", "node/foo"})
expected := `NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE expected := `NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
baz ClusterIP <none> <none> <none> <unknown> service/baz ClusterIP <none> <none> <none> <unknown>
NAME STATUS ROLES AGE VERSION NAME STATUS ROLES AGE VERSION
foo Unknown <none> <unknown> node/foo Unknown <none> <unknown>
` `
if e, a := expected, buf.String(); e != a { if e, a := expected, buf.String(); e != a {
t.Errorf("expected %v, got %v", e, a) t.Errorf("expected %v, got %v", e, a)

View File

@ -101,19 +101,6 @@ func (a *HumanReadablePrinter) With(fns ...func(PrintHandler)) *HumanReadablePri
return a 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 // EnsurePrintHeaders sets the HumanReadablePrinter option "NoHeaders" to false
// and removes the .lastType that was printed, which forces headers to be // and removes the .lastType that was printed, which forces headers to be
// printed in cases where multiple lists of the same resource are printed // 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 columns := table.ColumnDefinitions
nameColumn := -1 nameColumn := -1
if options.WithKind && len(options.Kind) > 0 { if options.WithKind && !options.Kind.Empty() {
for i := range columns { for i := range columns {
if columns[i].Format == "name" && columns[i].Type == "string" { if columns[i].Format == "name" && columns[i].Type == "string" {
nameColumn = i nameColumn = i
@ -451,7 +438,7 @@ func DecorateTable(table *metav1beta1.Table, options PrintOptions) error {
row := rows[i] row := rows[i]
if nameColumn != -1 { 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 var m metav1.Object
@ -607,8 +594,8 @@ func printRows(output io.Writer, rows []metav1beta1.TableRow, options PrintOptio
fmt.Fprint(output, "\t") fmt.Fprint(output, "\t")
} else { } else {
// TODO: remove this once we drop the legacy printers // TODO: remove this once we drop the legacy printers
if options.WithKind && len(options.Kind) > 0 { if options.WithKind && !options.Kind.Empty() {
fmt.Fprintf(output, "%s/%s", options.Kind, cell) fmt.Fprintf(output, "%s/%s", strings.ToLower(options.Kind.String()), cell)
continue continue
} }
} }
@ -785,12 +772,12 @@ func appendLabelCells(values []interface{}, itemLabels map[string]string, opts P
// FormatResourceName receives a resource kind, name, and boolean specifying // FormatResourceName receives a resource kind, name, and boolean specifying
// whether or not to update the current name to "kind/name" // whether or not to update the current name to "kind/name"
func FormatResourceName(kind, name string, withKind bool) string { func FormatResourceName(kind schema.GroupKind, name string, withKind bool) string {
if !withKind || kind == "" { if !withKind || kind.Empty() {
return name return name
} }
return kind + "/" + name return strings.ToLower(kind.String()) + "/" + name
} }
func AppendLabels(itemLabels map[string]string, columnLabels []string) string { func AppendLabels(itemLabels map[string]string, columnLabels []string) string {

View File

@ -21,6 +21,7 @@ import (
"io" "io"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
) )
// ResourcePrinter is an interface that knows how to print runtime objects. // ResourcePrinter is an interface that knows how to print runtime objects.
@ -68,7 +69,7 @@ type PrintOptions struct {
ShowAll bool ShowAll bool
ShowLabels bool ShowLabels bool
AbsoluteTimestamps bool AbsoluteTimestamps bool
Kind string Kind schema.GroupKind
ColumnLabels []string ColumnLabels []string
SortBy string SortBy string

View File

@ -40,6 +40,7 @@ import (
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/duration" "k8s.io/apimachinery/pkg/util/duration"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/api/events" "k8s.io/kubernetes/pkg/api/events"
@ -1759,7 +1760,12 @@ func printControllerRevision(obj *apps.ControllerRevision, options printers.Prin
controllerName := "<none>" controllerName := "<none>"
if controllerRef != nil { if controllerRef != nil {
withKind := true 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 revision := obj.Revision
age := translateTimestamp(obj.CreationTimestamp) age := translateTimestamp(obj.CreationTimestamp)

View File

@ -375,13 +375,15 @@ func TestJSONPrinter(t *testing.T) {
func TestFormatResourceName(t *testing.T) { func TestFormatResourceName(t *testing.T) {
tests := []struct { tests := []struct {
kind, name string kind schema.GroupKind
want string name string
want string
}{ }{
{"", "", ""}, {schema.GroupKind{}, "", ""},
{"", "name", "name"}, {schema.GroupKind{}, "name", "name"},
{"kind", "", "kind/"}, // should not happen in practice {schema.GroupKind{Kind: "Kind"}, "", "kind/"}, // should not happen in practice
{"kind", "name", "kind/name"}, {schema.GroupKind{Kind: "Kind"}, "name", "kind/name"},
{schema.GroupKind{Group: "group", Kind: "Kind"}, "name", "kind.group/name"},
} }
for _, tt := range tests { for _, tt := range tests {
if got := printers.FormatResourceName(tt.kind, tt.name, true); got != tt.want { 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 data := obj.Data
kind := options.Kind kind := options.Kind
if options.WithKind { if options.WithKind {
data = kind + "/" + data data = kind.String() + "/" + data
} }
_, err := fmt.Fprintf(w, "%s", data) _, err := fmt.Fprintf(w, "%s", data)
return err 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) { func TestPrintHandlerError(t *testing.T) {
columns := []string{"Data"} columns := []string{"Data"}
printer := printers.NewHumanReadablePrinter(nil, nil, printers.PrintOptions{}) 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<unknown>\n", expect: "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\ntest1\t1/2\tRunning\t6\t<unknown>\n",
}, },
{ {
obj: runningPod, opts: printers.PrintOptions{WithKind: true, Kind: "pods"}, obj: runningPod, opts: printers.PrintOptions{WithKind: true, Kind: schema.GroupKind{Kind: "Pod"}},
expect: "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\npods/test1\t1/2\tRunning\t6\t<unknown>\n", expect: "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\npod/test1\t1/2\tRunning\t6\t<unknown>\n",
}, },
{ {
obj: runningPod, opts: printers.PrintOptions{ShowLabels: true}, obj: runningPod, opts: printers.PrintOptions{ShowLabels: true},
@ -3058,6 +3042,7 @@ func TestPrintControllerRevision(t *testing.T) {
OwnerReferences: []metav1.OwnerReference{ OwnerReferences: []metav1.OwnerReference{
{ {
Controller: boolP(true), Controller: boolP(true),
APIVersion: "apps/v1",
Kind: "DaemonSet", Kind: "DaemonSet",
Name: "foo", Name: "foo",
}, },
@ -3065,7 +3050,7 @@ func TestPrintControllerRevision(t *testing.T) {
}, },
Revision: 1, Revision: 1,
}, },
"test1\tDaemonSet/foo\t1\t0s\n", "test1\tdaemonset.apps/foo\t1\t0s\n",
}, },
{ {
apps.ControllerRevision{ apps.ControllerRevision{