mirror of https://github.com/k3s-io/k3s
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
commit
d3bed1e5c9
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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{
|
||||||
|
|
Loading…
Reference in New Issue