diff --git a/pkg/kubectl/cmd/cmd_test.go b/pkg/kubectl/cmd/cmd_test.go index 7c9a8e463a1..97c68045087 100644 --- a/pkg/kubectl/cmd/cmd_test.go +++ b/pkg/kubectl/cmd/cmd_test.go @@ -241,9 +241,9 @@ func stringBody(body string) io.ReadCloser { // } //} -func ExamplePrintReplicationController() { +func ExamplePrintReplicationControllerWithNamespace() { f, tf, codec := NewAPIFactory() - tf.Printer = kubectl.NewHumanReadablePrinter(false, false, false, []string{}) + tf.Printer = kubectl.NewHumanReadablePrinter(false, true, false, []string{}) tf.Client = &client.FakeRESTClient{ Codec: codec, Client: nil, @@ -251,8 +251,9 @@ func ExamplePrintReplicationController() { cmd := NewCmdRun(f, os.Stdout) ctrl := &api.ReplicationController{ ObjectMeta: api.ObjectMeta{ - Name: "foo", - Labels: map[string]string{"foo": "bar"}, + Name: "foo", + Namespace: "beep", + Labels: map[string]string{"foo": "bar"}, }, Spec: api.ReplicationControllerSpec{ Replicas: 1, @@ -277,8 +278,8 @@ func ExamplePrintReplicationController() { fmt.Printf("Unexpected error: %v", err) } // Output: - // CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS - // foo foo someimage foo=bar 1 + // NAMESPACE CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS + // beep foo foo someimage foo=bar 1 } func ExamplePrintPodWithWideFormat() { diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index 52856b08fab..a72a43046cb 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -32,7 +32,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/conversion" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" - "github.com/GoogleCloudPlatform/kubernetes/pkg/types" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/volume" "github.com/ghodss/yaml" @@ -270,6 +269,7 @@ var serviceAccountColumns = []string{"NAME", "SECRETS"} var persistentVolumeColumns = []string{"NAME", "LABELS", "CAPACITY", "ACCESSMODES", "STATUS", "CLAIM", "REASON"} var persistentVolumeClaimColumns = []string{"NAME", "LABELS", "STATUS", "VOLUME"} var componentStatusColumns = []string{"NAME", "STATUS", "MESSAGE", "ERROR"} +var withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print cluster name too. // addDefaultHandlers adds print handlers for default Kubernetes types. func (h *HumanReadablePrinter) addDefaultHandlers() { @@ -379,9 +379,7 @@ func translateTimestamp(timestamp util.Time) string { func printPod(pod *api.Pod, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { name := pod.Name - if withNamespace { - name = types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}.String() - } + namespace := pod.Namespace restarts := 0 totalContainers := len(pod.Spec.Containers) @@ -411,6 +409,11 @@ func printPod(pod *api.Pod, w io.Writer, withNamespace bool, wide bool, columnLa } } + if withNamespace { + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } + } if _, err := fmt.Fprintf(w, "%s\t%d/%d\t%s\t%d\t%s", name, readyContainers, @@ -445,12 +448,8 @@ func printPodList(podList *api.PodList, w io.Writer, withNamespace bool, wide bo } func printPodTemplate(pod *api.PodTemplate, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string - if withNamespace { - name = types.NamespacedName{pod.Namespace, pod.Name}.String() - } else { - name = pod.Name - } + name := pod.Name + namespace := pod.Namespace containers := pod.Template.Spec.Containers var firstContainer api.Container @@ -458,6 +457,11 @@ func printPodTemplate(pod *api.PodTemplate, w io.Writer, withNamespace bool, wid firstContainer, containers = containers[0], containers[1:] } + if 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, @@ -490,12 +494,8 @@ func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, withNamespa } func printReplicationController(controller *api.ReplicationController, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string - if withNamespace { - name = types.NamespacedName{controller.Namespace, controller.Name}.String() - } else { - name = controller.Name - } + name := controller.Name + namespace := controller.Namespace containers := controller.Spec.Template.Spec.Containers var firstContainer api.Container @@ -503,6 +503,11 @@ func printReplicationController(controller *api.ReplicationController, w io.Writ firstContainer, containers = containers[0], containers[1:] } + if 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\t%d", name, firstContainer.Name, @@ -536,12 +541,8 @@ func printReplicationControllerList(list *api.ReplicationControllerList, w io.Wr } func printService(svc *api.Service, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string - if withNamespace { - name = types.NamespacedName{svc.Namespace, svc.Name}.String() - } else { - name = svc.Name - } + name := svc.Name + namespace := svc.Namespace ips := []string{svc.Spec.ClusterIP} @@ -552,6 +553,11 @@ func printService(svc *api.Service, w io.Writer, withNamespace bool, wide bool, } } + if 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\t%d/%s", name, formatLabels(svc.Labels), formatLabels(svc.Spec.Selector), ips[0], svc.Spec.Ports[0].Port, svc.Spec.Ports[0].Protocol); err != nil { return err @@ -592,13 +598,14 @@ func printServiceList(list *api.ServiceList, w io.Writer, withNamespace bool, wi } func printEndpoints(endpoints *api.Endpoints, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string - if withNamespace { - name = types.NamespacedName{endpoints.Namespace, endpoints.Name}.String() - } else { - name = endpoints.Name - } + name := endpoints.Name + namespace := endpoints.Namespace + if withNamespace { + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } + } if _, err := fmt.Fprintf(w, "%s\t%s", name, formatEndpoints(endpoints, nil)); err != nil { return err } @@ -616,6 +623,9 @@ func printEndpointsList(list *api.EndpointsList, w io.Writer, withNamespace bool } func printNamespace(item *api.Namespace, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { + if withNamespace { + return fmt.Errorf("namespace is not namespaced") + } if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", item.Name, formatLabels(item.Labels), item.Status.Phase); err != nil { return err } @@ -633,13 +643,14 @@ func printNamespaceList(list *api.NamespaceList, w io.Writer, withNamespace bool } func printSecret(item *api.Secret, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string - if withNamespace { - name = types.NamespacedName{item.Namespace, item.Name}.String() - } else { - name = item.Name - } + name := item.Name + namespace := item.Namespace + if withNamespace { + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } + } if _, err := fmt.Fprintf(w, "%s\t%s\t%v", name, item.Type, len(item.Data)); err != nil { return err } @@ -658,13 +669,14 @@ func printSecretList(list *api.SecretList, w io.Writer, withNamespace bool, wide } func printServiceAccount(item *api.ServiceAccount, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string - if withNamespace { - name = types.NamespacedName{item.Namespace, item.Name}.String() - } else { - name = item.Name - } + name := item.Name + namespace := item.Namespace + if withNamespace { + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } + } if _, err := fmt.Fprintf(w, "%s\t%d", name, len(item.Secrets)); err != nil { return err } @@ -683,6 +695,9 @@ func printServiceAccountList(list *api.ServiceAccountList, w io.Writer, withName } func printNode(node *api.Node, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { + if withNamespace { + return fmt.Errorf("node is not namespaced") + } conditionMap := make(map[api.NodeConditionType]*api.NodeCondition) NodeAllConditions := []api.NodeConditionType{api.NodeReady} for i := range node.Status.Conditions { @@ -723,12 +738,10 @@ func printNodeList(list *api.NodeList, w io.Writer, withNamespace bool, wide boo } func printPersistentVolume(pv *api.PersistentVolume, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string if withNamespace { - name = types.NamespacedName{pv.Namespace, pv.Name}.String() - } else { - name = pv.Name + return fmt.Errorf("persistentVolume is not namespaced") } + name := pv.Name claimRefUID := "" if pv.Spec.ClaimRef != nil { @@ -759,13 +772,20 @@ func printPersistentVolumeList(list *api.PersistentVolumeList, w io.Writer, with } func printPersistentVolumeClaim(pvc *api.PersistentVolumeClaim, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string + name := pvc.Name + namespace := pvc.Namespace + if withNamespace { - name = types.NamespacedName{pvc.Namespace, pvc.Name}.String() - } else { - name = pvc.Name + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } } + if 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, pvc.Labels, pvc.Status.Phase, pvc.Spec.VolumeName); err != nil { return err } @@ -783,6 +803,12 @@ func printPersistentVolumeClaimList(list *api.PersistentVolumeClaimList, w io.Wr } func printEvent(event *api.Event, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { + namespace := event.Namespace + if withNamespace { + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } + } if _, err := fmt.Fprintf( w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s", event.FirstTimestamp.Time.Format(time.RFC1123Z), @@ -813,11 +839,13 @@ func printEventList(list *api.EventList, w io.Writer, withNamespace bool, wide b } func printLimitRange(limitRange *api.LimitRange, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string + name := limitRange.Name + namespace := limitRange.Namespace + if withNamespace { - name = types.NamespacedName{limitRange.Namespace, limitRange.Name}.String() - } else { - name = limitRange.Name + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } } if _, err := fmt.Fprintf(w, "%s", name); err != nil { @@ -838,11 +866,13 @@ func printLimitRangeList(list *api.LimitRangeList, w io.Writer, withNamespace bo } func printResourceQuota(resourceQuota *api.ResourceQuota, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { - var name string + name := resourceQuota.Name + namespace := resourceQuota.Namespace + if withNamespace { - name = types.NamespacedName{resourceQuota.Namespace, resourceQuota.Name}.String() - } else { - name = resourceQuota.Name + if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil { + return err + } } if _, err := fmt.Fprintf(w, "%s", name); err != nil { @@ -863,6 +893,9 @@ func printResourceQuotaList(list *api.ResourceQuotaList, w io.Writer, withNamesp } func printComponentStatus(item *api.ComponentStatus, w io.Writer, withNamespace bool, wide bool, columnLabels []string) error { + if withNamespace { + return fmt.Errorf("componentStatus is not namespaced") + } status := "Unknown" message := "" error := "" @@ -940,6 +973,9 @@ func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) er if !h.noHeaders && t != h.lastType { headers := append(handler.columns, formatWideHeaders(h.wide, t)...) headers = append(headers, formatLabelHeaders(h.columnLabels)...) + if h.withNamespace { + headers = append(withNamespacePrefixColumns, headers...) + } h.printHeader(headers, w) h.lastType = t } diff --git a/pkg/kubectl/resource_printer_test.go b/pkg/kubectl/resource_printer_test.go index 931ac560601..a1b44020f00 100644 --- a/pkg/kubectl/resource_printer_test.go +++ b/pkg/kubectl/resource_printer_test.go @@ -774,14 +774,14 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) { namespaceName := "testnamespace" name := "test" table := []struct { - obj runtime.Object - printNamespace bool + obj runtime.Object + isNamespaced bool }{ { obj: &api.Pod{ ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespaceName}, }, - printNamespace: true, + isNamespaced: true, }, { obj: &api.ReplicationController{ @@ -812,7 +812,7 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) { }, }, }, - printNamespace: true, + isNamespaced: true, }, { obj: &api.Service{ @@ -836,7 +836,7 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) { }, }, }, - printNamespace: true, + isNamespaced: true, }, { obj: &api.Endpoints{ @@ -846,47 +846,47 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) { Ports: []api.EndpointPort{{Port: 8080}}, }, }}, - printNamespace: true, + isNamespaced: true, }, { obj: &api.Namespace{ ObjectMeta: api.ObjectMeta{Name: name}, }, - printNamespace: false, + isNamespaced: false, }, { obj: &api.Secret{ ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespaceName}, }, - printNamespace: true, + isNamespaced: true, }, { obj: &api.ServiceAccount{ ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespaceName}, Secrets: []api.ObjectReference{}, }, - printNamespace: true, + isNamespaced: true, }, { obj: &api.Node{ ObjectMeta: api.ObjectMeta{Name: name}, Status: api.NodeStatus{}, }, - printNamespace: false, + isNamespaced: false, }, { obj: &api.PersistentVolume{ ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespaceName}, Spec: api.PersistentVolumeSpec{}, }, - printNamespace: true, + isNamespaced: false, }, { obj: &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespaceName}, Spec: api.PersistentVolumeClaimSpec{}, }, - printNamespace: true, + isNamespaced: true, }, { obj: &api.Event{ @@ -897,19 +897,19 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) { LastTimestamp: util.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)), Count: 1, }, - printNamespace: false, + isNamespaced: true, }, { obj: &api.LimitRange{ ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespaceName}, }, - printNamespace: true, + isNamespaced: true, }, { obj: &api.ResourceQuota{ ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespaceName}, }, - printNamespace: true, + isNamespaced: true, }, { obj: &api.ComponentStatus{ @@ -917,35 +917,31 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) { {Type: api.ComponentHealthy, Status: api.ConditionTrue, Message: "ok", Error: ""}, }, }, - printNamespace: false, + isNamespaced: false, }, } - printer := NewHumanReadablePrinter(false, false, false, []string{}) for _, test := range table { - buffer := &bytes.Buffer{} - err := printer.PrintObj(test.obj, buffer) - if err != nil { - t.Fatalf("An error occurred printing object: %#v", err) - } - matched := contains(strings.Fields(buffer.String()), fmt.Sprintf("%s/%s", namespaceName, name)) - if matched { - t.Errorf("Expect printing object not to contain namespace: %v", test.obj) - } - } - - printer = NewHumanReadablePrinter(false, true, false, []string{}) - for _, test := range table { - buffer := &bytes.Buffer{} - err := printer.PrintObj(test.obj, buffer) - if err != nil { - t.Fatalf("An error occurred printing object: %#v", err) - } - matched := contains(strings.Fields(buffer.String()), fmt.Sprintf("%s/%s", namespaceName, name)) - if test.printNamespace && !matched { - t.Errorf("Expect printing object to contain namespace: %v", test.obj) - } else if !test.printNamespace && matched { - t.Errorf("Expect printing object not to contain namespace: %v", test.obj) + if test.isNamespaced { + // Expect output to include namespace when requested. + printer := NewHumanReadablePrinter(false, true, false, []string{}) + buffer := &bytes.Buffer{} + err := printer.PrintObj(test.obj, buffer) + if err != nil { + t.Fatalf("An error occurred printing object: %#v", err) + } + matched := contains(strings.Fields(buffer.String()), fmt.Sprintf("%s", namespaceName)) + if !matched { + t.Errorf("Expect printing object to contain namespace: %#v", test.obj) + } + } else { + // Expect error when trying to get all namespaces for un-namespaced object. + printer := NewHumanReadablePrinter(false, true, false, []string{}) + buffer := &bytes.Buffer{} + err := printer.PrintObj(test.obj, buffer) + if err == nil { + t.Errorf("Expected error when printing un-namespaced type") + } } } }