Merge pull request #76272 from liggitt/cleanup-legacy-printers

Remove legacy table printing and decoding
This commit is contained in:
Kubernetes Prow Robot 2019-04-08 22:31:17 -07:00 committed by GitHub
commit b8b7ab39ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 225 deletions

View File

@ -21,7 +21,6 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/printers"
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
)
@ -73,8 +72,6 @@ func (f *HumanPrintFlags) ToPrinter(outputFormat string) (printers.ResourcePrint
return nil, genericclioptions.NoCompatiblePrinterError{Options: f, AllowedFormats: f.AllowedFormats()}
}
decoder := scheme.Codecs.UniversalDecoder()
showKind := false
if f.ShowKind != nil {
showKind = *f.ShowKind
@ -90,7 +87,7 @@ func (f *HumanPrintFlags) ToPrinter(outputFormat string) (printers.ResourcePrint
columnLabels = *f.ColumnLabels
}
p := printers.NewHumanReadablePrinter(decoder, printers.PrintOptions{
p := printers.NewHumanReadablePrinter(printers.PrintOptions{
Kind: f.Kind,
WithKind: showKind,
NoHeaders: f.NoHeaders,

View File

@ -17,7 +17,6 @@ go_library(
deps = [
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",

View File

@ -27,7 +27,6 @@ import (
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
@ -40,7 +39,6 @@ type TablePrinter interface {
}
type PrintHandler interface {
Handler(columns, columnsWithWide []string, printFunc interface{}) error
TableHandler(columns []metav1beta1.TableColumnDefinition, printFunc interface{}) error
DefaultTableHandler(columns []metav1beta1.TableColumnDefinition, printFunc interface{}) error
}
@ -49,7 +47,6 @@ var withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print
type handlerEntry struct {
columnDefinitions []metav1beta1.TableColumnDefinition
printRows bool
printFunc reflect.Value
args []reflect.Value
}
@ -65,19 +62,15 @@ type HumanReadablePrinter struct {
lastType interface{}
lastColumns []metav1beta1.TableColumnDefinition
skipTabWriter bool
encoder runtime.Encoder
decoder runtime.Decoder
}
var _ PrintHandler = &HumanReadablePrinter{}
// NewHumanReadablePrinter creates a HumanReadablePrinter.
// If encoder and decoder are provided, an attempt to convert unstructured types to internal types is made.
func NewHumanReadablePrinter(decoder runtime.Decoder, options PrintOptions) *HumanReadablePrinter {
func NewHumanReadablePrinter(options PrintOptions) *HumanReadablePrinter {
printer := &HumanReadablePrinter{
handlerMap: make(map[reflect.Type]*handlerEntry),
options: options,
decoder: decoder,
}
return printer
}
@ -112,53 +105,6 @@ func (h *HumanReadablePrinter) EnsurePrintHeaders() {
h.lastType = nil
}
// Handler adds a print handler with a given set of columns to HumanReadablePrinter instance.
// See ValidatePrintHandlerFunc for required method signature.
func (h *HumanReadablePrinter) Handler(columns, columnsWithWide []string, printFunc interface{}) error {
var columnDefinitions []metav1beta1.TableColumnDefinition
for i, column := range columns {
format := ""
if i == 0 && strings.EqualFold(column, "name") {
format = "name"
}
columnDefinitions = append(columnDefinitions, metav1beta1.TableColumnDefinition{
Name: column,
Description: column,
Type: "string",
Format: format,
})
}
for _, column := range columnsWithWide {
columnDefinitions = append(columnDefinitions, metav1beta1.TableColumnDefinition{
Name: column,
Description: column,
Type: "string",
Priority: 1,
})
}
printFuncValue := reflect.ValueOf(printFunc)
if err := ValidatePrintHandlerFunc(printFuncValue); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to register print function: %v", err))
return err
}
entry := &handlerEntry{
columnDefinitions: columnDefinitions,
printFunc: printFuncValue,
}
objType := printFuncValue.Type().In(0)
if _, ok := h.handlerMap[objType]; ok {
err := fmt.Errorf("registered duplicate printer for %v", objType)
utilruntime.HandleError(err)
return err
}
h.handlerMap[objType] = entry
return nil
}
// TableHandler adds a print handler with a given set of columns to HumanReadablePrinter instance.
// See ValidateRowPrintHandlerFunc for required method signature.
func (h *HumanReadablePrinter) TableHandler(columnDefinitions []metav1beta1.TableColumnDefinition, printFunc interface{}) error {
@ -169,7 +115,6 @@ func (h *HumanReadablePrinter) TableHandler(columnDefinitions []metav1beta1.Tabl
}
entry := &handlerEntry{
columnDefinitions: columnDefinitions,
printRows: true,
printFunc: printFuncValue,
}
@ -194,7 +139,6 @@ func (h *HumanReadablePrinter) DefaultTableHandler(columnDefinitions []metav1bet
}
entry := &handlerEntry{
columnDefinitions: columnDefinitions,
printRows: true,
printFunc: printFuncValue,
}
@ -312,12 +256,6 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er
return PrintTable(table, output, localOptions)
}
// check if the object is unstructured. If so, let's attempt to convert it to a type we can understand before
// trying to print, since the printers are keyed by type. This is extremely expensive.
if h.decoder != nil {
obj, _ = decodeUnknownObject(obj, h.decoder)
}
// print with a registered handler
t := reflect.TypeOf(obj)
if handler := h.handlerMap[t]; handler != nil {
@ -516,9 +454,6 @@ func (h *HumanReadablePrinter) PrintTable(obj runtime.Object, options PrintOptio
if !ok {
return nil, fmt.Errorf("no table handler registered for this type %v", t)
}
if !handler.printRows {
return h.legacyPrinterToTable(obj, handler)
}
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(options)}
results := handler.printFunc.Call(args)
@ -567,12 +502,11 @@ func (h *HumanReadablePrinter) PrintTable(obj runtime.Object, options PrintOptio
// or an error, if any.
func printRowsForHandlerEntry(output io.Writer, handler *handlerEntry, obj runtime.Object, options PrintOptions, includeHeaders bool) error {
var results []reflect.Value
if handler.printRows {
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(options)}
results = handler.printFunc.Call(args)
if !results[1].IsNil() {
return results[1].Interface().(error)
}
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(options)}
results = handler.printFunc.Call(args)
if !results[1].IsNil() {
return results[1].Interface().(error)
}
if includeHeaders {
@ -592,16 +526,6 @@ func printRowsForHandlerEntry(output io.Writer, handler *handlerEntry, obj runti
printHeader(headers, output)
}
if !handler.printRows {
// TODO: this code path is deprecated and will be removed when all handlers are row printers
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(output), reflect.ValueOf(options)}
resultValue := handler.printFunc.Call(args)[0]
if resultValue.IsNil() {
return nil
}
return resultValue.Interface().(error)
}
if results[1].IsNil() {
rows := results[0].Interface().([]metav1beta1.TableRow)
printRows(output, rows, options)
@ -649,67 +573,6 @@ func printRows(output io.Writer, rows []metav1beta1.TableRow, options PrintOptio
}
}
// legacyPrinterToTable uses the old printFunc with tabbed writer to generate a table.
// TODO: remove when all legacy printers are removed.
func (h *HumanReadablePrinter) legacyPrinterToTable(obj runtime.Object, handler *handlerEntry) (*metav1beta1.Table, error) {
printFunc := handler.printFunc
table := &metav1beta1.Table{
ColumnDefinitions: handler.columnDefinitions,
}
options := PrintOptions{
NoHeaders: true,
Wide: true,
}
buf := &bytes.Buffer{}
args := []reflect.Value{reflect.ValueOf(obj), reflect.ValueOf(buf), reflect.ValueOf(options)}
if meta.IsListType(obj) {
listInterface, ok := obj.(metav1.ListInterface)
if ok {
table.ListMeta.SelfLink = listInterface.GetSelfLink()
table.ListMeta.ResourceVersion = listInterface.GetResourceVersion()
table.ListMeta.Continue = listInterface.GetContinue()
}
// TODO: this uses more memory than it has to, as we refactor printers we should remove the need
// for this.
args[0] = reflect.ValueOf(obj)
resultValue := printFunc.Call(args)[0]
if !resultValue.IsNil() {
return nil, resultValue.Interface().(error)
}
data := buf.Bytes()
i := 0
items, err := meta.ExtractList(obj)
if err != nil {
return nil, err
}
for len(data) > 0 {
cells, remainder := tabbedLineToCells(data, len(table.ColumnDefinitions))
table.Rows = append(table.Rows, metav1beta1.TableRow{
Cells: cells,
Object: runtime.RawExtension{Object: items[i]},
})
data = remainder
i++
}
} else {
args[0] = reflect.ValueOf(obj)
resultValue := printFunc.Call(args)[0]
if !resultValue.IsNil() {
return nil, resultValue.Interface().(error)
}
data := buf.Bytes()
cells, _ := tabbedLineToCells(data, len(table.ColumnDefinitions))
table.Rows = append(table.Rows, metav1beta1.TableRow{
Cells: cells,
Object: runtime.RawExtension{Object: obj},
})
}
return table, nil
}
// TODO: this method assumes the meta/v1 server API, so should be refactored out of this package
func printUnstructured(unstructured runtime.Unstructured, w io.Writer, additionalFields []string, options PrintOptions) error {
metadata, err := meta.Accessor(unstructured)
@ -848,46 +711,3 @@ func AppendAllLabels(showLabels bool, itemLabels map[string]string) string {
return buffer.String()
}
// check if the object is unstructured. If so, attempt to convert it to a type we can understand.
func decodeUnknownObject(obj runtime.Object, decoder runtime.Decoder) (runtime.Object, error) {
var err error
switch t := obj.(type) {
case runtime.Unstructured:
if objBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj); err == nil {
if decodedObj, err := runtime.Decode(decoder, objBytes); err == nil {
obj = decodedObj
}
}
case *runtime.Unknown:
if decodedObj, err := runtime.Decode(decoder, t.Raw); err == nil {
obj = decodedObj
}
}
return obj, err
}
func tabbedLineToCells(data []byte, expected int) ([]interface{}, []byte) {
var remainder []byte
max := bytes.Index(data, []byte("\n"))
if max != -1 {
remainder = data[max+1:]
data = data[:max]
}
cells := make([]interface{}, expected)
for i := 0; i < expected; i++ {
next := bytes.Index(data, []byte("\t"))
if next == -1 {
cells[i] = string(data)
// fill the remainder with empty strings, this indicates a printer bug
for j := i + 1; j < expected; j++ {
cells[j] = ""
}
break
}
cells[i] = string(data[:next])
data = data[next+1:]
}
return cells, remainder
}

View File

@ -61,7 +61,6 @@ func TestPrintRowsForHandlerEntry(t *testing.T) {
name: "no tablecolumndefinition and includeheader flase",
h: &handlerEntry{
columnDefinitions: []metav1beta1.TableColumnDefinition{},
printRows: true,
printFunc: printFunc,
},
opt: PrintOptions{},
@ -75,7 +74,6 @@ func TestPrintRowsForHandlerEntry(t *testing.T) {
name: "no tablecolumndefinition and includeheader true",
h: &handlerEntry{
columnDefinitions: []metav1beta1.TableColumnDefinition{},
printRows: true,
printFunc: printFunc,
},
opt: PrintOptions{},
@ -89,7 +87,6 @@ func TestPrintRowsForHandlerEntry(t *testing.T) {
name: "have tablecolumndefinition and includeheader true",
h: &handlerEntry{
columnDefinitions: testNamespaceColumnDefinitions,
printRows: true,
printFunc: printFunc,
},
opt: PrintOptions{},
@ -103,7 +100,6 @@ func TestPrintRowsForHandlerEntry(t *testing.T) {
name: "print namespace and withnamespace true, should not print header",
h: &handlerEntry{
columnDefinitions: testNamespaceColumnDefinitions,
printRows: true,
printFunc: printFunc,
},
opt: PrintOptions{

View File

@ -20,7 +20,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"reflect"
"regexp"
"strconv"
@ -30,7 +29,7 @@ import (
"sigs.k8s.io/yaml"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -172,7 +171,7 @@ func TestPrintUnstructuredObject(t *testing.T) {
for _, test := range tests {
out.Reset()
printer := printers.NewHumanReadablePrinter(nil, test.options).With(AddDefaultHandlers)
printer := printers.NewHumanReadablePrinter(test.options).With(AddDefaultHandlers)
printer.PrintObj(test.object, out)
matches, err := regexp.MatchString(test.expected, out.String())
@ -285,24 +284,23 @@ func TestFormatResourceName(t *testing.T) {
}
}
func PrintCustomType(obj *TestPrintType, w io.Writer, options printers.PrintOptions) error {
func PrintCustomType(obj *TestPrintType, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
data := obj.Data
kind := options.Kind
if options.WithKind {
data = kind.String() + "/" + data
}
_, err := fmt.Fprintf(w, "%s", data)
return err
return []metav1beta1.TableRow{{Cells: []interface{}{data}}}, nil
}
func ErrorPrintHandler(obj *TestPrintType, w io.Writer, options printers.PrintOptions) error {
return fmt.Errorf("ErrorPrintHandler error")
func ErrorPrintHandler(obj *TestPrintType, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
return nil, fmt.Errorf("ErrorPrintHandler error")
}
func TestCustomTypePrinting(t *testing.T) {
columns := []string{"Data"}
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{})
printer.Handler(columns, nil, PrintCustomType)
columns := []metav1beta1.TableColumnDefinition{{Name: "Data"}}
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
printer.TableHandler(columns, PrintCustomType)
obj := TestPrintType{"test object"}
buffer := &bytes.Buffer{}
@ -310,16 +308,16 @@ func TestCustomTypePrinting(t *testing.T) {
if err != nil {
t.Fatalf("An error occurred printing the custom type: %#v", err)
}
expectedOutput := "DATA\ntest object"
expectedOutput := "DATA\ntest object\n"
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, printers.PrintOptions{})
printer.Handler(columns, nil, ErrorPrintHandler)
columns := []metav1beta1.TableColumnDefinition{{Name: "Data"}}
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
printer.TableHandler(columns, ErrorPrintHandler)
obj := TestPrintType{"test object"}
buffer := &bytes.Buffer{}
err := printer.PrintObj(&obj, buffer)
@ -329,7 +327,7 @@ func TestPrintHandlerError(t *testing.T) {
}
func TestUnknownTypePrinting(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{})
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
buffer := &bytes.Buffer{}
err := printer.PrintObj(&TestUnknownType{}, buffer)
if err == nil {
@ -590,10 +588,10 @@ func TestPrinters(t *testing.T) {
// a humanreadable printer deals with internal-versioned objects
humanReadablePrinter := map[string]printers.ResourcePrinter{
"humanReadable": printers.NewHumanReadablePrinter(nil, printers.PrintOptions{
"humanReadable": printers.NewHumanReadablePrinter(printers.PrintOptions{
NoHeaders: true,
}),
"humanReadableHeaders": printers.NewHumanReadablePrinter(nil, printers.PrintOptions{}),
"humanReadableHeaders": printers.NewHumanReadablePrinter(printers.PrintOptions{}),
}
AddHandlers((humanReadablePrinter["humanReadable"]).(*printers.HumanReadablePrinter))
AddHandlers((humanReadablePrinter["humanReadableHeaders"]).(*printers.HumanReadablePrinter))
@ -613,7 +611,7 @@ func TestPrinters(t *testing.T) {
func TestPrintEventsResultSorted(t *testing.T) {
// Arrange
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{})
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
AddHandlers(printer)
obj := api.EventList{
@ -658,7 +656,7 @@ func TestPrintEventsResultSorted(t *testing.T) {
}
func TestPrintNodeStatus(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{})
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
AddHandlers(printer)
table := []struct {
node api.Node
@ -748,7 +746,7 @@ func TestPrintNodeStatus(t *testing.T) {
}
func TestPrintNodeRole(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{})
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{})
AddHandlers(printer)
table := []struct {
node api.Node
@ -793,7 +791,7 @@ func TestPrintNodeRole(t *testing.T) {
}
func TestPrintNodeOSImage(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
ColumnLabels: []string{},
Wide: true,
})
@ -838,7 +836,7 @@ func TestPrintNodeOSImage(t *testing.T) {
}
func TestPrintNodeKernelVersion(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
ColumnLabels: []string{},
Wide: true,
})
@ -883,7 +881,7 @@ func TestPrintNodeKernelVersion(t *testing.T) {
}
func TestPrintNodeContainerRuntimeVersion(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
ColumnLabels: []string{},
Wide: true,
})
@ -928,7 +926,7 @@ func TestPrintNodeContainerRuntimeVersion(t *testing.T) {
}
func TestPrintNodeName(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
Wide: true,
})
AddHandlers(printer)
@ -965,7 +963,7 @@ func TestPrintNodeName(t *testing.T) {
}
func TestPrintNodeExternalIP(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
Wide: true,
})
AddHandlers(printer)
@ -1013,7 +1011,7 @@ func TestPrintNodeExternalIP(t *testing.T) {
}
func TestPrintNodeInternalIP(t *testing.T) {
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
Wide: true,
})
AddHandlers(printer)
@ -1421,7 +1419,7 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) {
for i, test := range table {
if test.isNamespaced {
// Expect output to include namespace when requested.
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
WithNamespace: true,
})
AddHandlers(printer)
@ -1436,7 +1434,7 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) {
}
} else {
// Expect error when trying to get all namespaces for un-namespaced object.
printer := printers.NewHumanReadablePrinter(nil, printers.PrintOptions{
printer := printers.NewHumanReadablePrinter(printers.PrintOptions{
WithNamespace: true,
})
buffer := &bytes.Buffer{}
@ -1515,7 +1513,7 @@ func TestPrintPodTable(t *testing.T) {
}
verifyTable(t, table)
buf := &bytes.Buffer{}
p := printers.NewHumanReadablePrinter(nil, test.opts).With(AddHandlers).AddTabWriter(false)
p := printers.NewHumanReadablePrinter(test.opts).With(AddHandlers).AddTabWriter(false)
if err := p.PrintObj(table, buf); err != nil {
t.Fatal(err)
}