Merge pull request #56629 from luksa/fix_custom_column_alignment

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

Fix bad column alignment when using custom columns from OpenAPI schema

Columns printed by `kubectl get` weren't aligned properly when they were coming from the OpenAPI schema. 

This was caused by `CustomColumnPrinter.PrintObj`, which was creating a new `tabwriter.Writer` instead of re-using the tabwriter received through the `out` method parameter (basically, a tabwriter was writing to another tabwriter). Because the PrintObj flushed the tabwriter after writing each individual line, the column widths would reset.

**What this PR does / why we need it**:
This PR fixes the bad column alignment.

**Which issue(s) this PR fixes** 
Fixes #56282 

**Special notes for your reviewer**:
I've aligned how `CustomColumnPrinter.PrintObj` handles tabwriter with how `HumanReadablePrinter.PrintObj` does it (see https://github.com/kubernetes/kubernetes/blob/master/pkg/printers/humanreadable.go#L299-L303)

**Release note**:
```release-note
Fixed column alignment when kubectl get is used with custom columns from OpenAPI schema
```
This commit is contained in:
Kubernetes Submit Queue 2018-04-05 09:56:41 -07:00 committed by GitHub
commit 9f4b851e91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 13 deletions

View File

@ -31,14 +31,6 @@ import (
"k8s.io/client-go/util/jsonpath"
)
const (
columnwidth = 10
tabwidth = 4
padding = 3
padding_character = ' '
flags = 0
)
var jsonRegexp = regexp.MustCompile("^\\{\\.?([^{}]+)\\}$|^\\.?([^{}]+)$")
// RelaxedJSONPathExpression attempts to be flexible with JSONPath expressions, it accepts:
@ -163,7 +155,11 @@ func (s *CustomColumnsPrinter) AfterPrint(w io.Writer, res string) error {
}
func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
w := tabwriter.NewWriter(out, columnwidth, tabwidth, padding, padding_character, flags)
if w, found := out.(*tabwriter.Writer); !found {
w = GetNewTabWriter(out)
out = w
defer w.Flush()
}
t := reflect.TypeOf(obj)
if !s.NoHeaders && t != s.lastType {
@ -171,7 +167,7 @@ func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error
for ix := range s.Columns {
headers[ix] = s.Columns[ix].Header
}
fmt.Fprintln(w, strings.Join(headers, "\t"))
fmt.Fprintln(out, strings.Join(headers, "\t"))
s.lastType = t
}
parsers := make([]*jsonpath.JSONPath, len(s.Columns))
@ -188,16 +184,16 @@ func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error
return err
}
for ix := range objs {
if err := s.printOneObject(objs[ix], parsers, w); err != nil {
if err := s.printOneObject(objs[ix], parsers, out); err != nil {
return err
}
}
} else {
if err := s.printOneObject(obj, parsers, w); err != nil {
if err := s.printOneObject(obj, parsers, out); err != nil {
return err
}
}
return w.Flush()
return nil
}
func (s *CustomColumnsPrinter) printOneObject(obj runtime.Object, parsers []*jsonpath.JSONPath, out io.Writer) error {

View File

@ -323,3 +323,45 @@ foo baz <none>
}
}
}
// this mimics how resource/get.go calls the customcolumn printer
func TestIndividualPrintObjOnExistingTabWriter(t *testing.T) {
columns := []printers.Column{
{
Header: "NAME",
FieldSpec: "{.metadata.name}",
},
{
Header: "LONG COLUMN NAME", // name is longer than all values of label1
FieldSpec: "{.metadata.labels.label1}",
},
{
Header: "LABEL 2",
FieldSpec: "{.metadata.labels.label2}",
},
}
objects := []*v1.Pod{
{ObjectMeta: metav1.ObjectMeta{Name: "foo", Labels: map[string]string{"label1": "foo", "label2": "foo"}}},
{ObjectMeta: metav1.ObjectMeta{Name: "bar", Labels: map[string]string{"label1": "bar", "label2": "bar"}}},
}
expectedOutput := `NAME LONG COLUMN NAME LABEL 2
foo foo foo
bar bar bar
`
buffer := &bytes.Buffer{}
tabWriter := printers.GetNewTabWriter(buffer)
printer := &printers.CustomColumnsPrinter{
Columns: columns,
Decoder: legacyscheme.Codecs.UniversalDecoder(),
}
for _, obj := range objects {
if err := printer.PrintObj(obj, tabWriter); err != nil {
t.Errorf("unexpected error: %v", err)
}
}
tabWriter.Flush()
if buffer.String() != expectedOutput {
t.Errorf("\nexpected:\n'%s'\nsaw\n'%s'\n", expectedOutput, buffer.String())
}
}