diff --git a/pkg/kubectl/cmd/cmd.go b/pkg/kubectl/cmd/cmd.go index b362ff5d0f5..958cc533351 100644 --- a/pkg/kubectl/cmd/cmd.go +++ b/pkg/kubectl/cmd/cmd.go @@ -233,7 +233,7 @@ Find more information at https://github.com/kubernetes/kubernetes.`, // From this point and forward we get warnings on flags that contain "_" separators cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc) - cmds.AddCommand(NewCmdGet(f, out)) + cmds.AddCommand(NewCmdGet(f, out, err)) cmds.AddCommand(set.NewCmdSet(f, out)) cmds.AddCommand(NewCmdDescribe(f, out)) cmds.AddCommand(NewCmdCreate(f, out)) diff --git a/pkg/kubectl/cmd/cmd_test.go b/pkg/kubectl/cmd/cmd_test.go index 05b8476eb3a..1e5ebcf187e 100644 --- a/pkg/kubectl/cmd/cmd_test.go +++ b/pkg/kubectl/cmd/cmd_test.go @@ -165,6 +165,10 @@ func (t *testPrinter) HandledResources() []string { return []string{} } +func (t *testPrinter) FinishPrint(output io.Writer, res string) error { + return nil +} + type testDescriber struct { Name, Namespace string Settings kubectl.DescriberSettings diff --git a/pkg/kubectl/cmd/get.go b/pkg/kubectl/cmd/get.go index 675e1d7dd70..82dac9d09f9 100644 --- a/pkg/kubectl/cmd/get.go +++ b/pkg/kubectl/cmd/get.go @@ -44,6 +44,9 @@ var ( `) + kubectl.PossibleResourceTypes + dedent.Dedent(` + This command will hide resources that have completed. For instance, pods that are in the Succeeded or Failed phases. + You can see the full results for any resource by providing the '--show-all' flag. + By specifying the output as 'template' and providing a Go template as the value of the --template flag, you can filter the attributes of the fetched resource(s).`) get_example = dedent.Dedent(` @@ -74,7 +77,7 @@ var ( // NewCmdGet creates a command object for the generic "get" action, which // retrieves one or more resources from a server. -func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command { +func NewCmdGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &GetOptions{} // retrieve a list of handled resources from printer as valid args @@ -94,7 +97,7 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command { Long: get_long, Example: get_example, Run: func(cmd *cobra.Command, args []string) { - err := RunGet(f, out, cmd, args, options) + err := RunGet(f, out, errOut, cmd, args, options) cmdutil.CheckErr(err) }, SuggestFor: []string{"list", "ps"}, @@ -118,7 +121,7 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command { // RunGet implements the generic Get command // TODO: convert all direct flag accessors to a struct and pass that instead of cmd -func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *GetOptions) error { +func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Command, args []string, options *GetOptions) error { selector := cmdutil.GetFlagString(cmd, "selector") allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces") showKind := cmdutil.GetFlagBool(cmd, "show-kind") @@ -177,7 +180,6 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string if err != nil { return err } - obj, err := r.Object() if err != nil { return err @@ -203,6 +205,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string if err := printer.PrintObj(obj, out); err != nil { return fmt.Errorf("unable to output the provided object: %v", err) } + printer.FinishPrint(errOut, mapping.Resource) } // print watched changes @@ -218,7 +221,11 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string first = false return nil } - return printer.PrintObj(e.Object, out) + err := printer.PrintObj(e.Object, out) + if err == nil { + printer.FinishPrint(errOut, mapping.Resource) + } + return err }) return nil } @@ -265,6 +272,10 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string if err != nil { return err } + res := "" + if len(infos) > 0 { + res = infos[0].ResourceMapping().Resource + } obj, err := resource.AsVersionedObject(infos, !singular, version, f.JSONEncoder()) if err != nil { @@ -274,6 +285,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string if err := printer.PrintObj(obj, out); err != nil { allErrs = append(allErrs, err) } + printer.FinishPrint(errOut, res) return utilerrors.NewAggregate(allErrs) } @@ -322,7 +334,6 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string printer = nil var lastMapping *meta.RESTMapping w := kubectl.GetNewTabWriter(out) - defer w.Flush() if mustPrintWithKinds(objs, infos, sorter) { showKind = true @@ -339,6 +350,10 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string original = infos[ix].Object } if printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource { + if printer != nil { + w.Flush() + printer.FinishPrint(errOut, lastMapping.Resource) + } printer, err = f.PrinterForMapping(cmd, mapping, allNamespaces) if err != nil { allErrs = append(allErrs, err) @@ -375,6 +390,10 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string continue } } + w.Flush() + if printer != nil { + printer.FinishPrint(errOut, lastMapping.Resource) + } return utilerrors.NewAggregate(allErrs) } diff --git a/pkg/kubectl/cmd/get_test.go b/pkg/kubectl/cmd/get_test.go index 705bdc6861c..b122ebae078 100644 --- a/pkg/kubectl/cmd/get_test.go +++ b/pkg/kubectl/cmd/get_test.go @@ -127,8 +127,9 @@ func TestGetUnknownSchemaObject(t *testing.T) { tf.Namespace = "test" tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}} buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Run(cmd, []string{"type", "foo"}) @@ -203,12 +204,13 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) { tf.Namespace = "test" tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}} buf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + errBuf := bytes.NewBuffer([]byte{}) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("output", "json") cmd.Flags().Set("output-version", test.outputVersion) - err := RunGet(f, buf, cmd, []string{"type/foo", "replicationcontrollers/foo"}, &GetOptions{}) + err := RunGet(f, buf, errBuf, cmd, []string{"type/foo", "replicationcontrollers/foo"}, &GetOptions{}) if err != nil { t.Errorf("%s: unexpected error: %v", k, err) continue @@ -246,8 +248,9 @@ func TestGetSchemaObject(t *testing.T) { tf.Namespace = "test" tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: "v1"}}} buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.Run(cmd, []string{"replicationcontrollers", "foo"}) if !strings.Contains(buf.String(), "\"foo\"") { @@ -266,8 +269,9 @@ func TestGetObjects(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Run(cmd, []string{"pods", "foo"}) @@ -312,7 +316,9 @@ func TestGetSortedObjects(t *testing.T) { tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: "v1"}}} buf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + errBuf := bytes.NewBuffer([]byte{}) + + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) // sorting with metedata.name @@ -342,8 +348,9 @@ func TestGetObjectsIdentifiedByFile(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("filename", "../../../examples/storage/cassandra/cassandra-controller.yaml") cmd.Run(cmd, []string{}) @@ -369,8 +376,9 @@ func TestGetListObjects(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Run(cmd, []string{"pods"}) @@ -412,8 +420,9 @@ func TestGetAllListObjects(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("show-all", "true") cmd.Run(cmd, []string{"pods"}) @@ -442,8 +451,9 @@ func TestGetListComponentStatus(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Run(cmd, []string{"componentstatuses"}) @@ -481,8 +491,9 @@ func TestGetMultipleTypeObjects(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Run(cmd, []string{"pods,services"}) @@ -521,8 +532,9 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) { tf.Namespace = "test" tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}} buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("output", "json") @@ -583,8 +595,9 @@ func TestGetMultipleTypeObjectsWithSelector(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("selector", "a=b") @@ -632,8 +645,9 @@ func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Run(cmd, []string{"services/bar", "node/foo"}) @@ -659,8 +673,9 @@ func TestGetByNameForcesFlag(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Run(cmd, []string{"pods", "foo"}) @@ -770,8 +785,9 @@ func TestWatchSelector(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("watch", "true") @@ -809,8 +825,9 @@ func TestWatchResource(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("watch", "true") @@ -847,7 +864,9 @@ func TestWatchResourceIdentifiedByFile(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + errBuf := bytes.NewBuffer([]byte{}) + + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("watch", "true") @@ -886,8 +905,9 @@ func TestWatchOnlyResource(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("watch-only", "true") @@ -930,8 +950,9 @@ func TestWatchOnlyList(t *testing.T) { } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) - cmd := NewCmdGet(f, buf) + cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("watch-only", "true") diff --git a/pkg/kubectl/custom_column_printer.go b/pkg/kubectl/custom_column_printer.go index a532a72a9d0..379f4637660 100644 --- a/pkg/kubectl/custom_column_printer.go +++ b/pkg/kubectl/custom_column_printer.go @@ -155,6 +155,10 @@ type CustomColumnsPrinter struct { NoHeaders bool } +func (s *CustomColumnsPrinter) FinishPrint(w io.Writer, res string) error { + return nil +} + func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error { w := tabwriter.NewWriter(out, columnwidth, tabwidth, padding, padding_character, flags) diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index ddf99d0ebb1..29630abfb2d 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -147,6 +147,9 @@ type ResourcePrinter interface { // Print receives a runtime object, formats it and prints it to a writer. PrintObj(runtime.Object, io.Writer) error HandledResources() []string + //Can be used to print out warning/clarifications if needed + //after all objects were printed + FinishPrint(io.Writer, string) error } // ResourcePrinterFunc is a function that can print objects @@ -162,6 +165,10 @@ func (fn ResourcePrinterFunc) HandledResources() []string { return []string{} } +func (fn ResourcePrinterFunc) FinishPrint(io.Writer, string) error { + return nil +} + // VersionedPrinter takes runtime objects and ensures they are converted to a given API version // prior to being passed to a nested printer. type VersionedPrinter struct { @@ -179,6 +186,10 @@ func NewVersionedPrinter(printer ResourcePrinter, converter runtime.ObjectConver } } +func (p *VersionedPrinter) FinishPrint(w io.Writer, res string) error { + return nil +} + // PrintObj implements ResourcePrinter func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error { if len(p.versions) == 0 { @@ -211,6 +222,10 @@ type NamePrinter struct { Typer runtime.ObjectTyper } +func (p *NamePrinter) FinishPrint(w io.Writer, res string) error { + return nil +} + // PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object // and print "resource/name" pair. If the object is a List, print all items in it. func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error { @@ -259,6 +274,10 @@ func (p *NamePrinter) HandledResources() []string { type JSONPrinter struct { } +func (p *JSONPrinter) FinishPrint(w io.Writer, res string) error { + return nil +} + // PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer. func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error { switch obj := obj.(type) { @@ -291,6 +310,10 @@ type YAMLPrinter struct { converter runtime.ObjectConvertor } +func (p *YAMLPrinter) FinishPrint(w io.Writer, res string) error { + return nil +} + // PrintObj prints the data as YAML. func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error { switch obj := obj.(type) { @@ -319,6 +342,7 @@ func (p *YAMLPrinter) HandledResources() []string { type handlerEntry struct { columns []string printFunc reflect.Value + args []reflect.Value } type PrintOptions struct { @@ -338,9 +362,10 @@ type PrintOptions struct { // will only be printed if the object type changes. This makes it useful for printing items // received from watches. type HumanReadablePrinter struct { - handlerMap map[reflect.Type]*handlerEntry - options PrintOptions - lastType reflect.Type + handlerMap map[reflect.Type]*handlerEntry + options PrintOptions + lastType reflect.Type + hiddenObjNum int } // NewHumanReadablePrinter creates a HumanReadablePrinter. @@ -384,6 +409,7 @@ func (h *HumanReadablePrinter) Handler(columns []string, printFunc interface{}) glog.Errorf("Unable to add print handler: %v", err) return err } + objType := printFuncValue.Type().In(0) h.handlerMap[objType] = &handlerEntry{ columns: columns, @@ -431,6 +457,14 @@ func (h *HumanReadablePrinter) HandledResources() []string { return keys } +func (h *HumanReadablePrinter) FinishPrint(output io.Writer, res string) error { + if !h.options.NoHeaders && !h.options.ShowAll && h.hiddenObjNum > 0 { + _, err := fmt.Fprintf(output, " info: %d completed object(s) was(were) not shown in %s list. Pass --show-all to see all objects.\n\n", h.hiddenObjNum, res) + return err + } + return nil +} + // NOTE: When adding a new resource type here, please update the list // pkg/kubectl/cmd/get.go to reflect the new resource type. var podColumns = []string{"NAME", "READY", "STATUS", "RESTARTS", "AGE"} @@ -471,10 +505,40 @@ var clusterColumns = []string{"NAME", "STATUS", "VERSION", "AGE"} var networkPolicyColumns = []string{"NAME", "POD-SELECTOR", "AGE"} var certificateSigningRequestColumns = []string{"NAME", "AGE", "REQUESTOR", "CONDITION"} +func (h *HumanReadablePrinter) printPod(pod *api.Pod, w io.Writer, options PrintOptions) error { + reason := string(pod.Status.Phase) + // if not printing all pods, skip terminated pods (default) + if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) { + h.hiddenObjNum++ + return nil + } + if err := printPodBase(pod, w, options); err != nil { + return err + } + + return nil +} + +func (h *HumanReadablePrinter) printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error { + for _, pod := range podList.Items { + reason := string(pod.Status.Phase) + // if not printing all pods, skip terminated pods (default) + if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) { + h.hiddenObjNum++ + continue + } + + if err := printPodBase(&pod, w, options); err != nil { + return err + } + } + return nil +} + // addDefaultHandlers adds print handlers for default Kubernetes types. func (h *HumanReadablePrinter) addDefaultHandlers() { - h.Handler(podColumns, printPod) - h.Handler(podColumns, printPodList) + h.Handler(podColumns, h.printPodList) + h.Handler(podColumns, h.printPod) h.Handler(podTemplateColumns, printPodTemplate) h.Handler(podTemplateColumns, printPodTemplateList) h.Handler(replicationControllerColumns, printReplicationController) @@ -617,10 +681,6 @@ func translateTimestamp(timestamp unversioned.Time) string { return shortHumanDuration(time.Now().Sub(timestamp.Time)) } -func printPod(pod *api.Pod, w io.Writer, options PrintOptions) error { - return printPodBase(pod, w, options) -} - func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error { name := formatResourceName(options.Kind, pod.Name, options.WithKind) namespace := pod.Namespace @@ -630,10 +690,6 @@ func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error { readyContainers := 0 reason := string(pod.Status.Phase) - // if not printing all pods, skip terminated pods (default) - if !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) { - return nil - } if pod.Status.Reason != "" { reason = pod.Status.Reason } @@ -731,15 +787,6 @@ func printPodBase(pod *api.Pod, w io.Writer, options PrintOptions) error { return nil } -func printPodList(podList *api.PodList, w io.Writer, options PrintOptions) error { - for _, pod := range podList.Items { - if err := printPodBase(&pod, w, options); err != nil { - return err - } - } - return nil -} - func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) error { name := formatResourceName(options.Kind, pod.Name, options.WithKind) @@ -2183,6 +2230,10 @@ func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) { }, nil } +func (p *TemplatePrinter) FinishPrint(w io.Writer, res string) error { + return nil +} + // PrintObj formats the obj with the Go Template. func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error { data, err := json.Marshal(obj) @@ -2330,6 +2381,10 @@ func NewJSONPathPrinter(tmpl string) (*JSONPathPrinter, error) { return &JSONPathPrinter{tmpl, j}, nil } +func (j *JSONPathPrinter) FinishPrint(w io.Writer, res string) error { + return nil +} + // PrintObj formats the obj with the JSONPath Template. func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error { var queryObj interface{} = obj diff --git a/pkg/kubectl/resource_printer_test.go b/pkg/kubectl/resource_printer_test.go index 6fbe141adca..2f341acfaf9 100644 --- a/pkg/kubectl/resource_printer_test.go +++ b/pkg/kubectl/resource_printer_test.go @@ -1148,14 +1148,18 @@ func TestPrintPod(t *testing.T) { } buf := bytes.NewBuffer([]byte{}) + printer := HumanReadablePrinter{hiddenObjNum: 0} for _, test := range tests { - printPod(&test.pod, buf, PrintOptions{false, false, false, false, true, false, false, "", []string{}}) + printer.printPod(&test.pod, buf, PrintOptions{false, false, false, false, true, false, false, "", []string{}}) // We ignore time if !strings.HasPrefix(buf.String(), test.expect) { t.Fatalf("Expected: %s, got: %s", test.expect, buf.String()) } buf.Reset() } + if printer.hiddenObjNum > 0 { + t.Fatalf("Expected hidden pods: 0, got: %d", printer.hiddenObjNum) + } } func TestPrintNonTerminatedPod(t *testing.T) { @@ -1241,14 +1245,18 @@ func TestPrintNonTerminatedPod(t *testing.T) { } buf := bytes.NewBuffer([]byte{}) + printer := HumanReadablePrinter{hiddenObjNum: 0} for _, test := range tests { - printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, false, false, "", []string{}}) + printer.printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, false, false, "", []string{}}) // We ignore time if !strings.HasPrefix(buf.String(), test.expect) { t.Fatalf("Expected: %s, got: %s", test.expect, buf.String()) } buf.Reset() } + if printer.hiddenObjNum != 2 { + t.Fatalf("Expected hidden pods: 2, got: %d", printer.hiddenObjNum) + } } func TestPrintPodWithLabels(t *testing.T) { @@ -1301,14 +1309,18 @@ func TestPrintPodWithLabels(t *testing.T) { } buf := bytes.NewBuffer([]byte{}) + printer := HumanReadablePrinter{hiddenObjNum: 0} for _, test := range tests { - printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, false, false, "", test.labelColumns}) + printer.printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, false, false, "", test.labelColumns}) // We ignore time if !strings.HasPrefix(buf.String(), test.startsWith) || !strings.HasSuffix(buf.String(), test.endsWith) { t.Fatalf("Expected to start with: %s and end with: %s, but got: %s", test.startsWith, test.endsWith, buf.String()) } buf.Reset() } + if printer.hiddenObjNum > 0 { + t.Fatalf("Expected hidden pods: 0, got: %d", printer.hiddenObjNum) + } } type stringTestList []struct { @@ -1507,12 +1519,17 @@ func TestPrintPodShowLabels(t *testing.T) { } buf := bytes.NewBuffer([]byte{}) + printer := HumanReadablePrinter{hiddenObjNum: 0} + for _, test := range tests { - printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, test.showLabels, false, "", []string{}}) + printer.printPod(&test.pod, buf, PrintOptions{false, false, false, false, false, test.showLabels, false, "", []string{}}) // We ignore time if !strings.HasPrefix(buf.String(), test.startsWith) || !strings.HasSuffix(buf.String(), test.endsWith) { t.Fatalf("Expected to start with: %s and end with: %s, but got: %s", test.startsWith, test.endsWith, buf.String()) } buf.Reset() } + if printer.hiddenObjNum > 0 { + t.Fatalf("Expected hidden pods: 0, got: %d", printer.hiddenObjNum) + } } diff --git a/pkg/kubectl/sorting_printer.go b/pkg/kubectl/sorting_printer.go index c2c97f37d7c..3e797fa3c91 100644 --- a/pkg/kubectl/sorting_printer.go +++ b/pkg/kubectl/sorting_printer.go @@ -40,6 +40,10 @@ type SortingPrinter struct { Decoder runtime.Decoder } +func (s *SortingPrinter) FinishPrint(w io.Writer, res string) error { + return nil +} + func (s *SortingPrinter) PrintObj(obj runtime.Object, out io.Writer) error { if !meta.IsListType(obj) { return s.Delegate.PrintObj(obj, out)