Add -o name for commands which use printer to output results

Added a new printer which prints 'resource/name' pair of a given
object.
This commit is contained in:
hurf 2015-08-18 15:35:35 +08:00
parent 00e34429e0
commit d2d96ff6e1
20 changed files with 138 additions and 26 deletions

View File

@ -47,7 +47,7 @@ resourcequotas (quota) or secrets.
.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
.PP
\fB\-\-output\-version\fP=""

View File

@ -42,7 +42,7 @@ You can use \-\-output=template \-\-template=TEMPLATE to extract specific values
.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
.PP
\fB\-\-output\-version\fP=""

View File

@ -64,7 +64,7 @@ re\-use the labels from the resource it exposes.
.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
.PP
\fB\-\-output\-version\fP=""

View File

@ -49,7 +49,7 @@ of the \-\-template flag, you can filter the attributes of the fetched resource(
.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
.PP
\fB\-\-output\-version\fP=""
@ -187,6 +187,9 @@ $ kubectl get pods
# List all pods in ps output format with more information (such as node name).
$ kubectl get pods \-o wide
# List all pods in resource/name format (such as pod/nginx).
$ kubectl get pods \-o name
# List a single replication controller with specified NAME in ps output format.
$ kubectl get replicationcontroller web

View File

@ -40,7 +40,7 @@ If \-\-resource\-version is specified, then updates will use this resource versi
.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
.PP
\fB\-\-output\-version\fP=""

View File

@ -48,7 +48,7 @@ existing replication controller and overwrite at least one (common) label in its
.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
.PP
\fB\-\-output\-version\fP=""

View File

@ -56,7 +56,7 @@ Creates a replication controller to manage the created container(s).
.PP
\fB\-o\fP, \fB\-\-output\fP=""
Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
.PP
\fB\-\-output\-version\fP=""

View File

@ -85,7 +85,7 @@ $ kubectl annotate pods foo description-
-f, --filename=[]: Filename, directory, or URL to a file identifying the resource to update the annotation
-h, --help[=false]: help for annotate
--no-headers[=false]: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
--output-version="": Output the formatted object with the given version (default api-version).
--overwrite[=false]: If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.
--resource-version="": If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.
@ -126,7 +126,7 @@ $ kubectl annotate pods foo description-
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-21 07:07:55.977091863 +0000 UTC
###### Auto generated by spf13/cobra at 2015-08-25 11:50:09.184436452 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_annotate.md?pixel)]()

View File

@ -64,7 +64,7 @@ $ kubectl config view -o template --template='{{range .users}}{{ if eq .name "e2
--merge=true: merge together the full hierarchy of kubeconfig files
--minify[=false]: remove all information not used by current-context from the output
--no-headers[=false]: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
--output-version="": Output the formatted object with the given version (default api-version).
--raw[=false]: display raw byte data
-a, --show-all[=false]: When printing, show all resources (default hide terminated pods.)
@ -104,7 +104,7 @@ $ kubectl config view -o template --template='{{range .users}}{{ if eq .name "e2
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files
###### Auto generated by spf13/cobra at 2015-08-25 10:17:24.594231276 +0000 UTC
###### Auto generated by spf13/cobra at 2015-08-26 09:03:39.977436672 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_config_view.md?pixel)]()

View File

@ -77,7 +77,7 @@ $ kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream
-l, --labels="": Labels to apply to the service created by this call.
--name="": The name for the newly created object.
--no-headers[=false]: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
--output-version="": Output the formatted object with the given version (default api-version).
--overrides="": An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.
--port=-1: The port that the service should serve on. Copied from the resource being exposed, if unspecified
@ -123,7 +123,7 @@ $ kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-25 10:17:24.593785768 +0000 UTC
###### Auto generated by spf13/cobra at 2015-08-26 09:03:39.976795003 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_expose.md?pixel)]()

View File

@ -61,6 +61,9 @@ $ kubectl get pods
# List all pods in ps output format with more information (such as node name).
$ kubectl get pods -o wide
# List all pods in resource/name format (such as pod/nginx).
$ kubectl get pods -o name
# List a single replication controller with specified NAME in ps output format.
$ kubectl get replicationcontroller web
@ -88,7 +91,7 @@ $ kubectl get rc/web service/frontend pods/web-pod-13je7
-h, --help[=false]: help for get
-L, --label-columns=[]: Accepts a comma separated list of labels that are going to be presented as columns. Names are case-sensitive. You can also use multiple flag statements like -L label1 -L label2...
--no-headers[=false]: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
--output-version="": Output the formatted object with the given version (default api-version).
-l, --selector="": Selector (label query) to filter on
-a, --show-all[=false]: When printing, show all resources (default hide terminated pods.)
@ -130,7 +133,7 @@ $ kubectl get rc/web service/frontend pods/web-pod-13je7
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-25 10:17:24.591177912 +0000 UTC
###### Auto generated by spf13/cobra at 2015-08-26 09:03:39.972870101 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_get.md?pixel)]()

View File

@ -78,7 +78,7 @@ $ kubectl label pods foo bar-
-f, --filename=[]: Filename, directory, or URL to a file identifying the resource to update the labels
-h, --help[=false]: help for label
--no-headers[=false]: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
--output-version="": Output the formatted object with the given version (default api-version).
--overwrite[=false]: If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels.
--resource-version="": If non-empty, the labels update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.
@ -120,7 +120,7 @@ $ kubectl label pods foo bar-
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-25 10:17:24.593929691 +0000 UTC
###### Auto generated by spf13/cobra at 2015-08-26 09:03:39.977006328 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_label.md?pixel)]()

View File

@ -75,7 +75,7 @@ $ kubectl rolling-update frontend --image=image:v2
-h, --help[=false]: help for rolling-update
--image="": Image to use for upgrading the replication controller. Can not be used with --filename/-f
--no-headers[=false]: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
--output-version="": Output the formatted object with the given version (default api-version).
--poll-interval=3s: Time delay between polling for replication controller status after the update. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
--rollback[=false]: If true, this is a request to abort an existing rollout that is partially rolled out. It effectively reverses current and next and runs a rollout
@ -119,7 +119,7 @@ $ kubectl rolling-update frontend --image=image:v2
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-25 10:17:24.592687096 +0000 UTC
###### Auto generated by spf13/cobra at 2015-08-26 09:03:39.974410445 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_rolling-update.md?pixel)]()

View File

@ -82,7 +82,7 @@ $ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
--image="": The image for the container to run.
-l, --labels="": Labels to apply to the pod(s).
--no-headers[=false]: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath.
-o, --output="": Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.
--output-version="": Output the formatted object with the given version (default api-version).
--overrides="": An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.
--port=-1: The port that this container exposes.
@ -127,7 +127,7 @@ $ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-25 10:17:24.593489492 +0000 UTC
###### Auto generated by spf13/cobra at 2015-08-26 09:03:39.976311407 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_run.md?pixel)]()

View File

@ -113,7 +113,7 @@ func NewDefaultRESTMapper(group string, versions []string, f VersionInterfacesFu
}
func (m *DefaultRESTMapper) Add(scope RESTScope, kind string, version string, mixedCase bool) {
plural, singular := kindToResource(kind, mixedCase)
plural, singular := KindToResource(kind, mixedCase)
m.plurals[singular] = plural
m.singulars[plural] = singular
meta := typeMeta{APIVersion: version, Kind: kind}
@ -131,8 +131,8 @@ func (m *DefaultRESTMapper) Add(scope RESTScope, kind string, version string, mi
m.scopes[meta] = scope
}
// kindToResource converts Kind to a resource name.
func kindToResource(kind string, mixedCase bool) (plural, singular string) {
// KindToResource converts Kind to a resource name.
func KindToResource(kind string, mixedCase bool) (plural, singular string) {
if len(kind) == 0 {
return
}

View File

@ -155,7 +155,7 @@ func TestKindToResource(t *testing.T) {
{Kind: "lowercases", MixedCase: false, Plural: "lowercases", Singular: "lowercases"},
}
for i, testCase := range testCases {
plural, singular := kindToResource(testCase.Kind, testCase.MixedCase)
plural, singular := KindToResource(testCase.Kind, testCase.MixedCase)
if singular != testCase.Singular || plural != testCase.Plural {
t.Errorf("%d: unexpected plural and singular: %s %s", i, plural, singular)
}

View File

@ -43,6 +43,9 @@ $ kubectl get pods
# List all pods in ps output format with more information (such as node name).
$ kubectl get pods -o wide
# List all pods in resource/name format (such as pod/nginx).
$ kubectl get pods -o name
# List a single replication controller with specified NAME in ps output format.
$ kubectl get replicationcontroller web

View File

@ -28,7 +28,7 @@ import (
// AddPrinterFlags adds printing related flags to a command (e.g. output format, no headers, template path)
func AddPrinterFlags(cmd *cobra.Command) {
cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|template|templatefile|wide|jsonpath.")
cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|template|templatefile|wide|jsonpath|name.")
cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version).")
cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers.")
// template shorthand -t is deprecated to support -t for --tty

View File

@ -19,6 +19,7 @@ package kubectl
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@ -32,6 +33,7 @@ import (
"github.com/ghodss/yaml"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/expapi"
"k8s.io/kubernetes/pkg/labels"
@ -53,6 +55,8 @@ func GetPrinter(format, formatArgument string) (ResourcePrinter, bool, error) {
printer = &JSONPrinter{}
case "yaml":
printer = &YAMLPrinter{}
case "name":
printer = &NamePrinter{}
case "template":
if len(formatArgument) == 0 {
return nil, false, fmt.Errorf("template format specified but no template given")
@ -145,6 +149,56 @@ func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
return fmt.Errorf("the object cannot be converted to any of the versions: %v", p.version)
}
// NamePrinter is an implementation of ResourcePrinter which outputs "resource/name" pair of an object.
type NamePrinter struct {
}
// 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 {
objvalue := reflect.ValueOf(obj).Elem()
kind := objvalue.FieldByName("Kind")
if !kind.IsValid() {
kind = reflect.ValueOf("<unknown>")
}
if kind.String() == "List" {
items := objvalue.FieldByName("Items")
if items.Type().String() == "[]runtime.RawExtension" {
for i := 0; i < items.Len(); i++ {
rawObj := items.Index(i).FieldByName("RawJSON").Interface().([]byte)
scheme := api.Scheme
version, kind, err := scheme.DataVersionAndKind(rawObj)
if err != nil {
return err
}
decodedObj, err := scheme.DecodeToVersion(rawObj, "")
if err != nil {
return err
}
tpmeta := api.TypeMeta{
APIVersion: version,
Kind: kind,
}
s := reflect.ValueOf(decodedObj).Elem()
s.FieldByName("TypeMeta").Set(reflect.ValueOf(tpmeta))
p.PrintObj(decodedObj, w)
}
} else {
return errors.New("the list object contains unrecognized items.")
}
} else {
name := objvalue.FieldByName("Name")
if !name.IsValid() {
name = reflect.ValueOf("<unknown>")
}
_, resource := meta.KindToResource(kind.String(), false)
fmt.Fprintf(w, "%s/%s\n", resource, name)
}
return nil
}
// JSONPrinter is an implementation of ResourcePrinter which outputs an object as JSON.
type JSONPrinter struct {
}

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
@ -118,6 +119,7 @@ func TestPrinter(t *testing.T) {
{"test template", "template", "{{if .id}}{{.id}}{{end}}{{if .metadata.name}}{{.metadata.name}}{{end}}",
podTest, "foo"},
{"test jsonpath", "jsonpath", "{.metadata.name}", podTest, "foo"},
{"test name", "name", "", podTest, "/foo\n"},
{"emits versioned objects", "template", "{{.kind}}", testapi, "Pod"},
}
for _, test := range printerTests {
@ -272,6 +274,52 @@ func TestTemplatePanic(t *testing.T) {
}
}
func TestNamePrinter(t *testing.T) {
tests := map[string]struct {
obj runtime.Object
expect string
}{
"singleObject": {
&api.Pod{
TypeMeta: api.TypeMeta{
Kind: "Pod",
},
ObjectMeta: api.ObjectMeta{
Name: "foo",
},
},
"pod/foo\n"},
"List": {
&v1.List{
TypeMeta: v1.TypeMeta{
Kind: "List",
},
Items: []runtime.RawExtension{
{
RawJSON: []byte(`{"kind": "Pod", "apiVersion": "v1", "metadata": { "name": "foo"}}`),
},
{
RawJSON: []byte(`{"kind": "Pod", "apiVersion": "v1", "metadata": { "name": "bar"}}`),
},
},
},
"pod/foo\npod/bar\n"},
}
printer, _, _ := GetPrinter("name", "")
for name, item := range tests {
buff := &bytes.Buffer{}
err := printer.PrintObj(item.obj, buff)
if err != nil {
t.Errorf("%v: unexpected err: %v", name, err)
continue
}
got := buff.String()
if item.expect != got {
t.Errorf("%v: expected %v, got %v", name, item.expect, got)
}
}
}
func TestTemplateStrings(t *testing.T) {
// This unit tests the "exists" function as well as the template from update.sh
table := map[string]struct {
@ -413,6 +461,7 @@ func TestPrinters(t *testing.T) {
"template": templatePrinter,
"template2": templatePrinter2,
"jsonpath": jsonpathPrinter,
"name": &NamePrinter{},
}
objects := map[string]runtime.Object{
"pod": &api.Pod{ObjectMeta: om("pod")},