diff --git a/pkg/kubectl/cmd/cmd_test.go b/pkg/kubectl/cmd/cmd_test.go index fa00458a78c0b..cea653ef958bd 100644 --- a/pkg/kubectl/cmd/cmd_test.go +++ b/pkg/kubectl/cmd/cmd_test.go @@ -389,7 +389,7 @@ func ExamplePrintReplicationControllerWithNamespace() { // beep foo 1 1 10y } -func ExamplePrintReplicationControllerWithWide() { +func ExamplePrintMultiContainersReplicationControllerWithWide() { f, tf, codec := NewAPIFactory() tf.Printer = kubectl.NewHumanReadablePrinter(false, false, true, false, false, false, []string{}) tf.Client = &fake.RESTClient{ @@ -416,6 +416,58 @@ func ExamplePrintReplicationControllerWithWide() { Name: "foo", Image: "someimage", }, + { + Name: "foo2", + Image: "someimage2", + }, + }, + }, + }, + }, + Status: api.ReplicationControllerStatus{ + Replicas: 1, + }, + } + err := f.PrintObject(cmd, ctrl, os.Stdout) + if err != nil { + fmt.Printf("Unexpected error: %v", err) + } + // Output: + // NAME DESIRED CURRENT AGE CONTAINER(S) IMAGE(S) SELECTOR + // foo 1 1 10y foo,foo2 someimage,someimage2 foo=bar +} + +func ExamplePrintReplicationController() { + f, tf, codec := NewAPIFactory() + tf.Printer = kubectl.NewHumanReadablePrinter(false, false, false, false, false, false, []string{}) + tf.Client = &fake.RESTClient{ + Codec: codec, + Client: nil, + } + cmd := NewCmdRun(f, os.Stdin, os.Stdout, os.Stderr) + ctrl := &api.ReplicationController{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{"foo": "bar"}, + CreationTimestamp: unversioned.Time{Time: time.Now().AddDate(-10, 0, 0)}, + }, + Spec: api.ReplicationControllerSpec{ + Replicas: 1, + Selector: map[string]string{"foo": "bar"}, + Template: &api.PodTemplateSpec{ + ObjectMeta: api.ObjectMeta{ + Labels: map[string]string{"foo": "bar"}, + }, + Spec: api.PodSpec{ + Containers: []api.Container{ + { + Name: "foo", + Image: "someimage", + }, + { + Name: "foo2", + Image: "someimage", + }, }, }, }, @@ -429,8 +481,8 @@ func ExamplePrintReplicationControllerWithWide() { fmt.Printf("Unexpected error: %v", err) } // Output: - // NAME DESIRED CURRENT AGE CONTAINER(S) IMAGE(S) SELECTOR - // foo 1 1 10y foo someimage foo=bar + // NAME DESIRED CURRENT AGE + // foo 1 1 10y } func ExamplePrintPodWithWideFormat() { diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index bd3c8f2053cc7..7f9d4ab0ef731 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -638,22 +638,19 @@ func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) e namespace := pod.Namespace containers := pod.Template.Spec.Containers - var firstContainer api.Container - if len(containers) > 0 { - firstContainer, containers = containers[0], containers[1:] - } if options.WithNamespace { if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { return err } } - if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s", - name, - firstContainer.Name, - firstContainer.Image, - labels.FormatLabels(pod.Template.Labels), - ); err != nil { + if _, err := fmt.Fprintf(w, "%s", name); err != nil { + return err + } + if err := layoutContainers(containers, w); err != nil { + return err + } + if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(pod.Template.Labels)); err != nil { return err } if _, err := fmt.Fprint(w, appendLabels(pod.Labels, options.ColumnLabels)); err != nil { @@ -663,20 +660,6 @@ func printPodTemplate(pod *api.PodTemplate, w io.Writer, options PrintOptions) e return err } - // Lay out all the other containers on separate lines. - extraLinePrefix := "\t" - if options.WithNamespace { - extraLinePrefix = "\t\t" - } - for _, container := range containers { - _, err := fmt.Fprintf(w, "%s%s\t%s\t%s", extraLinePrefix, container.Name, container.Image, "") - if err != nil { - return err - } - if _, err := fmt.Fprint(w, appendLabelTabs(options.ColumnLabels)); err != nil { - return err - } - } return nil } @@ -689,14 +672,11 @@ func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, options Pri return nil } +// TODO(AdoHe): try to put wide output in a single method func printReplicationController(controller *api.ReplicationController, w io.Writer, options PrintOptions) error { name := controller.Name namespace := controller.Namespace containers := controller.Spec.Template.Spec.Containers - var firstContainer api.Container - if len(containers) > 0 { - firstContainer, containers = containers[0], containers[1:] - } if options.WithNamespace { if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { @@ -714,12 +694,12 @@ func printReplicationController(controller *api.ReplicationController, w io.Writ ); err != nil { return err } + if options.Wide { - if _, err := fmt.Fprintf(w, "\t%s\t%s\t%s", - firstContainer.Name, - firstContainer.Image, - labels.FormatLabels(controller.Spec.Selector), - ); err != nil { + if err := layoutContainers(containers, w); err != nil { + return err + } + if _, err := fmt.Fprintf(w, "\t%s", labels.FormatLabels(controller.Spec.Selector)); err != nil { return err } } @@ -730,20 +710,6 @@ func printReplicationController(controller *api.ReplicationController, w io.Writ return err } - // Lay out all the other containers on separate lines. - extraLinePrefix := "\t" - if options.WithNamespace { - extraLinePrefix = "\t\t" - } - for _, container := range containers { - _, err := fmt.Fprintf(w, "%s%s\t%s\t%s\t%s", extraLinePrefix, container.Name, container.Image, "", "") - if err != nil { - return err - } - if _, err := fmt.Fprint(w, appendLabelTabs(options.ColumnLabels)); err != nil { - return err - } - } return nil } @@ -760,10 +726,6 @@ func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options PrintOption name := rs.Name namespace := rs.Namespace containers := rs.Spec.Template.Spec.Containers - var firstContainer api.Container - if len(containers) > 0 { - firstContainer, containers = containers[0], containers[1:] - } if options.WithNamespace { if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { @@ -782,11 +744,10 @@ func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options PrintOption return err } if options.Wide { - if _, err := fmt.Fprintf(w, "\t%s\t%s\t%s", - firstContainer.Name, - firstContainer.Image, - unversioned.FormatLabelSelector(rs.Spec.Selector), - ); err != nil { + if err := layoutContainers(containers, w); err != nil { + return err + } + if _, err := fmt.Fprintf(w, "\t%s", unversioned.FormatLabelSelector(rs.Spec.Selector)); err != nil { return err } } @@ -797,20 +758,6 @@ func printReplicaSet(rs *extensions.ReplicaSet, w io.Writer, options PrintOption return err } - // Lay out all the other containers on separate lines. - extraLinePrefix := "\t" - if options.WithNamespace { - extraLinePrefix = "\t\t" - } - for _, container := range containers { - _, err := fmt.Fprintf(w, "%s%s\t%s\t%s\t%s", extraLinePrefix, container.Name, container.Image, "", "") - if err != nil { - return err - } - if _, err := fmt.Fprint(w, appendLabelTabs(options.ColumnLabels)); err != nil { - return err - } - } return nil } @@ -827,17 +774,18 @@ func printJob(job *extensions.Job, w io.Writer, options PrintOptions) error { name := job.Name namespace := job.Namespace containers := job.Spec.Template.Spec.Containers - var firstContainer api.Container - if len(containers) > 0 { - firstContainer, containers = containers[0], containers[1:] - } + if options.WithNamespace { if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { return err } } - selector, _ := unversioned.LabelSelectorAsSelector(job.Spec.Selector) + selector, err := unversioned.LabelSelectorAsSelector(job.Spec.Selector) + if err != nil { + // this shouldn't happen if LabelSelector passed validation + return err + } if job.Spec.Completions != nil { if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s", name, @@ -858,11 +806,10 @@ func printJob(job *extensions.Job, w io.Writer, options PrintOptions) error { } } if options.Wide { - if _, err := fmt.Fprintf(w, "\t%s\t%s\t%s", - firstContainer.Name, - firstContainer.Image, - selector.String(), - ); err != nil { + if err := layoutContainers(containers, w); err != nil { + return err + } + if _, err := fmt.Fprintf(w, "\t%s", selector.String()); err != nil { return err } } @@ -873,20 +820,6 @@ func printJob(job *extensions.Job, w io.Writer, options PrintOptions) error { return err } - // Lay out all the other containers on separate lines. - extraLinePrefix := "\t" - if options.WithNamespace { - extraLinePrefix = "\t\t" - } - for _, container := range containers { - _, err := fmt.Fprintf(w, "%s%s\t%s\t%s\t%s", extraLinePrefix, container.Name, container.Image, "", "") - if err != nil { - return err - } - if _, err := fmt.Fprint(w, appendLabelTabs(options.ColumnLabels)); err != nil { - return err - } - } return nil } @@ -1021,7 +954,8 @@ func printIngress(ingress *extensions.Ingress, w io.Writer, options PrintOptions return err } - // Lay out all the rules on separate lines. + // Lay out all the rules on separate lines if use wide output. + // TODO(AdoHe): improve ingress output extraLinePrefix := "" if options.WithNamespace { extraLinePrefix = "\t" @@ -1047,6 +981,7 @@ func printIngress(ingress *extensions.Ingress, w io.Writer, options PrintOptions } } } + return nil } @@ -1064,10 +999,6 @@ func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions) namespace := ds.Namespace containers := ds.Spec.Template.Spec.Containers - var firstContainer api.Container - if len(containers) > 0 { - firstContainer, containers = containers[0], containers[1:] - } if options.WithNamespace { if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { @@ -1092,11 +1023,10 @@ func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions) return err } if options.Wide { - if _, err := fmt.Fprintf(w, "\t%s\t%s\t%s", - firstContainer.Name, - firstContainer.Image, - selector, - ); err != nil { + if err := layoutContainers(containers, w); err != nil { + return err + } + if _, err := fmt.Fprintf(w, "\t%s", selector.String()); err != nil { return err } } @@ -1107,20 +1037,6 @@ func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions) return err } - // Lay out all the other containers on separate lines. - extraLinePrefix := "\t" - if options.WithNamespace { - extraLinePrefix = "\t\t" - } - for _, container := range containers { - _, err := fmt.Fprintf(w, "%s%s\t%s\t%s\t%s", extraLinePrefix, container.Name, container.Image, "", "") - if err != nil { - return err - } - if _, err := fmt.Fprint(w, appendLabelTabs(options.ColumnLabels)); err != nil { - return err - } - } return nil } @@ -1729,6 +1645,26 @@ func appendLabelTabs(columnLabels []string) string { return buffer.String() } +// Lay out all the containers on one line if use wide output. +func layoutContainers(containers []api.Container, w io.Writer) error { + var namesBuffer bytes.Buffer + var imagesBuffer bytes.Buffer + + for i, container := range containers { + namesBuffer.WriteString(container.Name) + imagesBuffer.WriteString(container.Image) + if i != len(containers)-1 { + namesBuffer.WriteString(",") + imagesBuffer.WriteString(",") + } + } + _, err := fmt.Fprintf(w, "\t%s\t%s", namesBuffer.String(), imagesBuffer.String()) + if err != nil { + return err + } + return nil +} + func formatLabelHeaders(columnLabels []string) []string { formHead := make([]string, len(columnLabels)) for i, l := range columnLabels {