diff --git a/pkg/kubectl/cmd/clusterinfo_dump.go b/pkg/kubectl/cmd/clusterinfo_dump.go index db9abd85e93..895f178c835 100644 --- a/pkg/kubectl/cmd/clusterinfo_dump.go +++ b/pkg/kubectl/cmd/clusterinfo_dump.go @@ -60,13 +60,13 @@ based on namespace and pod name. dumpExample = `# Dump current cluster state to stdout kubectl cluster-info dump - + # Dump current cluster state to /path/to/cluster-state kubectl cluster-info dump --output-directory=/path/to/cluster-state - + # Dump all namespaces to stdout kubectl cluster-info dump --all-namespaces - + # Dump a set of namespaces to /path/to/cluster-state kubectl cluster-info dump --namespaces default,kube-system --output-directory=/path/to/cluster-state` ) @@ -91,7 +91,7 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out if c, err = f.Client(); err != nil { return err } - printer, _, err := kubectl.GetPrinter("json", "") + printer, _, err := kubectl.GetPrinter("json", "", false) if err != nil { return err } diff --git a/pkg/kubectl/cmd/convert.go b/pkg/kubectl/cmd/convert.go index 34aeda44f90..bad2e5565e7 100644 --- a/pkg/kubectl/cmd/convert.go +++ b/pkg/kubectl/cmd/convert.go @@ -150,7 +150,7 @@ func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra. } } o.encoder = f.JSONEncoder() - o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile) + o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile, false) if err != nil { return err } diff --git a/pkg/kubectl/cmd/util/printing.go b/pkg/kubectl/cmd/util/printing.go index 7d4592d148c..e95e4ca687b 100644 --- a/pkg/kubectl/cmd/util/printing.go +++ b/pkg/kubectl/cmd/util/printing.go @@ -52,7 +52,7 @@ func AddOutputFlags(cmd *cobra.Command) { // AddNoHeadersFlags adds no-headers flags to a command. func AddNoHeadersFlags(cmd *cobra.Command) { - cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers.") + cmd.Flags().Bool("no-headers", false, "When using the default or custom-column output format, don't print headers.") } // PrintSuccess prints message after finishing mutating operations @@ -121,7 +121,7 @@ func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error } } - printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile) + printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile, GetFlagBool(cmd, "no-headers")) if err != nil { return nil, generic, err } diff --git a/pkg/kubectl/custom_column_printer.go b/pkg/kubectl/custom_column_printer.go index 93d7d754d72..3d51f63cb30 100644 --- a/pkg/kubectl/custom_column_printer.go +++ b/pkg/kubectl/custom_column_printer.go @@ -73,7 +73,7 @@ func massageJSONPath(pathExpression string) (string, error) { // // NAME API_VERSION // foo bar -func NewCustomColumnsPrinterFromSpec(spec string, decoder runtime.Decoder) (*CustomColumnsPrinter, error) { +func NewCustomColumnsPrinterFromSpec(spec string, decoder runtime.Decoder, noHeaders bool) (*CustomColumnsPrinter, error) { if len(spec) == 0 { return nil, fmt.Errorf("custom-columns format specified but no custom columns given") } @@ -90,7 +90,7 @@ func NewCustomColumnsPrinterFromSpec(spec string, decoder runtime.Decoder) (*Cus } columns[ix] = Column{Header: colSpec[0], FieldSpec: spec} } - return &CustomColumnsPrinter{Columns: columns, Decoder: decoder}, nil + return &CustomColumnsPrinter{Columns: columns, Decoder: decoder, NoHeaders: noHeaders}, nil } func splitOnWhitespace(line string) []string { @@ -135,7 +135,7 @@ func NewCustomColumnsPrinterFromTemplate(templateReader io.Reader, decoder runti FieldSpec: spec, } } - return &CustomColumnsPrinter{Columns: columns, Decoder: decoder}, nil + return &CustomColumnsPrinter{Columns: columns, Decoder: decoder, NoHeaders: false}, nil } // Column represents a user specified column @@ -150,17 +150,21 @@ type Column struct { // CustomColumnPrinter is a printer that knows how to print arbitrary columns // of data from templates specified in the `Columns` array type CustomColumnsPrinter struct { - Columns []Column - Decoder runtime.Decoder + Columns []Column + Decoder runtime.Decoder + NoHeaders bool } func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error { w := tabwriter.NewWriter(out, columnwidth, tabwidth, padding, padding_character, flags) - headers := make([]string, len(s.Columns)) - for ix := range s.Columns { - headers[ix] = s.Columns[ix].Header + + if !s.NoHeaders { + headers := make([]string, len(s.Columns)) + for ix := range s.Columns { + headers[ix] = s.Columns[ix].Header + } + fmt.Fprintln(w, strings.Join(headers, "\t")) } - fmt.Fprintln(w, strings.Join(headers, "\t")) parsers := make([]*jsonpath.JSONPath, len(s.Columns)) for ix := range s.Columns { parsers[ix] = jsonpath.New(fmt.Sprintf("column%d", ix)) diff --git a/pkg/kubectl/custom_column_printer_test.go b/pkg/kubectl/custom_column_printer_test.go index 73ed60e7791..9ba653dff4d 100644 --- a/pkg/kubectl/custom_column_printer_test.go +++ b/pkg/kubectl/custom_column_printer_test.go @@ -19,6 +19,7 @@ package kubectl import ( "bytes" "reflect" + "strings" "testing" "k8s.io/kubernetes/pkg/api" @@ -67,6 +68,7 @@ func TestNewColumnPrinterFromSpec(t *testing.T) { expectedColumns []Column expectErr bool name string + noHeaders bool }{ { spec: "", @@ -102,9 +104,14 @@ func TestNewColumnPrinterFromSpec(t *testing.T) { }, }, }, + { + spec: "API_VERSION:apiVersion", + name: "no-headers", + noHeaders: true, + }, } for _, test := range tests { - printer, err := NewCustomColumnsPrinterFromSpec(test.spec, api.Codecs.UniversalDecoder()) + printer, err := NewCustomColumnsPrinterFromSpec(test.spec, api.Codecs.UniversalDecoder(), test.noHeaders) if test.expectErr { if err == nil { t.Errorf("[%s] unexpected non-error", test.name) @@ -115,8 +122,19 @@ func TestNewColumnPrinterFromSpec(t *testing.T) { t.Errorf("[%s] unexpected error: %v", test.name, err) continue } + if test.noHeaders { + buffer := &bytes.Buffer{} - if !reflect.DeepEqual(test.expectedColumns, printer.Columns) { + printer.PrintObj(&api.Pod{}, buffer) + if err != nil { + t.Fatalf("An error occurred printing Pod: %#v", err) + } + + if contains(strings.Fields(buffer.String()), "API_VERSION") { + t.Errorf("unexpected header API_VERSION") + } + + } else if !reflect.DeepEqual(test.expectedColumns, printer.Columns) { t.Errorf("[%s]\nexpected:\n%v\nsaw:\n%v\n", test.name, test.expectedColumns, printer.Columns) } diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index 811d5b289b6..2e046f9e2ba 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -62,7 +62,7 @@ const ( // is agnostic to schema versions, so you must send arguments to PrintObj in the // version you wish them to be shown using a VersionedPrinter (typically when // generic is true). -func GetPrinter(format, formatArgument string) (ResourcePrinter, bool, error) { +func GetPrinter(format, formatArgument string, noHeaders bool) (ResourcePrinter, bool, error) { var printer ResourcePrinter switch format { case "json": @@ -119,7 +119,7 @@ func GetPrinter(format, formatArgument string) (ResourcePrinter, bool, error) { } case "custom-columns": var err error - if printer, err = NewCustomColumnsPrinterFromSpec(formatArgument, api.Codecs.UniversalDecoder()); err != nil { + if printer, err = NewCustomColumnsPrinterFromSpec(formatArgument, api.Codecs.UniversalDecoder(), noHeaders); err != nil { return nil, false, err } case "custom-columns-file": diff --git a/pkg/kubectl/resource_printer_test.go b/pkg/kubectl/resource_printer_test.go index 5e1f558acfa..bacaa1086bf 100644 --- a/pkg/kubectl/resource_printer_test.go +++ b/pkg/kubectl/resource_printer_test.go @@ -75,7 +75,7 @@ func TestVersionedPrinter(t *testing.T) { } func TestPrintDefault(t *testing.T) { - printer, found, err := GetPrinter("", "") + printer, found, err := GetPrinter("", "", false) if err != nil { t.Fatalf("unexpected error: %#v", err) } @@ -129,7 +129,7 @@ func TestPrinter(t *testing.T) { } for _, test := range printerTests { buf := bytes.NewBuffer([]byte{}) - printer, found, err := GetPrinter(test.Format, test.FormatArgument) + printer, found, err := GetPrinter(test.Format, test.FormatArgument, false) if err != nil || !found { t.Errorf("in %s, unexpected error: %#v", test.Name, err) } @@ -156,7 +156,7 @@ func TestBadPrinter(t *testing.T) { {"bad jsonpath", "jsonpath", "{.Name", fmt.Errorf("error parsing jsonpath {.Name, unclosed action\n")}, } for _, test := range badPrinterTests { - _, _, err := GetPrinter(test.Format, test.FormatArgument) + _, _, err := GetPrinter(test.Format, test.FormatArgument, false) if err == nil || err.Error() != test.Error.Error() { t.Errorf("in %s, expect %s, got %s", test.Name, test.Error, err) } @@ -333,7 +333,7 @@ func TestNamePrinter(t *testing.T) { }, "pod/foo\npod/bar\n"}, } - printer, _, _ := GetPrinter("name", "") + printer, _, _ := GetPrinter("name", "", false) for name, item := range tests { buff := &bytes.Buffer{} err := printer.PrintObj(item.obj, buff)