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)
}
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

View File

@ -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 <unknown>
bar 0/0 0 <unknown>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
baz ClusterIP <none> <none> <none> <unknown>
pod/foo 0/0 0 <unknown>
pod/bar 0/0 0 <unknown>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/baz ClusterIP <none> <none> <none> <unknown>
`
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 <unknown>
bar 0/0 0 <unknown>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
baz ClusterIP <none> <none> <none> <unknown>
pod/foo 0/0 0 <unknown>
pod/bar 0/0 0 <unknown>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/baz ClusterIP <none> <none> <none> <unknown>
`
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 <unknown>
bar 0/0 0 <unknown>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
baz ClusterIP <none> <none> <none> <unknown>
pod/foo 0/0 0 <unknown>
pod/bar 0/0 0 <unknown>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/baz ClusterIP <none> <none> <none> <unknown>
`
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 <none> <none> <none> <unknown>
NAME STATUS ROLES AGE VERSION
foo Unknown <none> <unknown>
expected := `NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/baz ClusterIP <none> <none> <none> <unknown>
NAME STATUS ROLES AGE VERSION
node/foo Unknown <none> <unknown>
`
if e, a := expected, buf.String(); 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
}
// 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 {

View File

@ -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

View File

@ -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 := "<none>"
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)

View File

@ -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<unknown>\n",
},
{
obj: runningPod, opts: printers.PrintOptions{WithKind: true, Kind: "pods"},
expect: "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\npods/test1\t1/2\tRunning\t6\t<unknown>\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<unknown>\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{