Kubectl describe command accepts a filename param

pull/6/head
feihjiang 2015-07-07 15:31:08 +08:00 committed by feihujiang
parent d04fce045e
commit 2ca200f087
6 changed files with 85 additions and 20 deletions

View File

@ -275,6 +275,12 @@ _kubectl_describe()
flags_with_completion=() flags_with_completion=()
flags_completion=() flags_completion=()
flags+=("--filename=")
flags_with_completion+=("--filename")
flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
two_word_flags+=("-f")
flags_with_completion+=("-f")
flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
flags+=("--help") flags+=("--help")
flags+=("-h") flags+=("-h")
flags+=("--selector=") flags+=("--selector=")

View File

@ -34,6 +34,10 @@ namespaces (ns) or secrets.
.SH OPTIONS .SH OPTIONS
.PP
\fB\-f\fP, \fB\-\-filename\fP=[]
Filename, directory, or URL to a file containing the resource to describe
.PP .PP
\fB\-h\fP, \fB\-\-help\fP=false \fB\-h\fP, \fB\-\-help\fP=false
help for describe help for describe
@ -152,6 +156,9 @@ $ kubectl describe nodes kubernetes\-minion\-emt8.c.myproject.internal
// Describe a pod // Describe a pod
$ kubectl describe pods/nginx $ kubectl describe pods/nginx
// Describe a pod using the data in pod.json.
$ kubectl describe \-f pod.json
// Describe pods by label name=myLabel // Describe pods by label name=myLabel
$ kubectl describe po \-l name=myLabel $ kubectl describe po \-l name=myLabel

View File

@ -83,7 +83,7 @@ kubectl api-versions
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-05 23:27:50.890645232 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-07 07:32:08.138043968 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_api-versions.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_api-versions.md?pixel)]()

View File

@ -54,7 +54,7 @@ persistentvolumes (pv), persistentvolumeclaims (pvc), resourcequotas (quota),
namespaces (ns) or secrets. namespaces (ns) or secrets.
``` ```
kubectl describe (TYPE [(NAME_PREFIX | -l label] | TYPE/NAME) kubectl describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)
``` ```
### Examples ### Examples
@ -66,6 +66,9 @@ $ kubectl describe nodes kubernetes-minion-emt8.c.myproject.internal
// Describe a pod // Describe a pod
$ kubectl describe pods/nginx $ kubectl describe pods/nginx
// Describe a pod using the data in pod.json.
$ kubectl describe -f pod.json
// Describe pods by label name=myLabel // Describe pods by label name=myLabel
$ kubectl describe po -l name=myLabel $ kubectl describe po -l name=myLabel
@ -77,6 +80,7 @@ $ kubectl describe pods frontend
### Options ### Options
``` ```
-f, --filename=[]: Filename, directory, or URL to a file containing the resource to describe
-h, --help[=false]: help for describe -h, --help[=false]: help for describe
-l, --selector="": Selector (label query) to filter on -l, --selector="": Selector (label query) to filter on
``` ```
@ -114,7 +118,7 @@ $ kubectl describe pods frontend
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-05 23:27:50.885301316 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-07 07:32:08.128980687 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_describe.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_describe.md?pixel)]()

View File

@ -29,6 +29,7 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/errors"
) )
const ( const (
@ -52,6 +53,9 @@ $ kubectl describe nodes kubernetes-minion-emt8.c.myproject.internal
// Describe a pod // Describe a pod
$ kubectl describe pods/nginx $ kubectl describe pods/nginx
// Describe a pod using the data in pod.json.
$ kubectl describe -f pod.json
// Describe pods by label name=myLabel // Describe pods by label name=myLabel
$ kubectl describe po -l name=myLabel $ kubectl describe po -l name=myLabel
@ -62,7 +66,7 @@ $ kubectl describe pods frontend`
func NewCmdDescribe(f *cmdutil.Factory, out io.Writer) *cobra.Command { func NewCmdDescribe(f *cmdutil.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "describe (TYPE [(NAME_PREFIX | -l label] | TYPE/NAME)", Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)",
Short: "Show details of a specific resource or group of resources", Short: "Show details of a specific resource or group of resources",
Long: describe_long, Long: describe_long,
Example: describe_example, Example: describe_example,
@ -72,18 +76,20 @@ func NewCmdDescribe(f *cmdutil.Factory, out io.Writer) *cobra.Command {
}, },
ValidArgs: kubectl.DescribableResources(), ValidArgs: kubectl.DescribableResources(),
} }
usage := "Filename, directory, or URL to a file containing the resource to describe"
kubectl.AddJsonFilenameFlag(cmd, usage)
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on") cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on")
return cmd return cmd
} }
func RunDescribe(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { func RunDescribe(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
selector := cmdutil.GetFlagString(cmd, "selector") selector := cmdutil.GetFlagString(cmd, "selector")
cmdNamespace, _, err := f.DefaultNamespace() cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil { if err != nil {
return err return err
} }
filenames := cmdutil.GetFlagStringSlice(cmd, "filename")
if len(args) == 0 { if len(args) == 0 && len(filenames) == 0 {
fmt.Fprint(out, "You must specify the type of resource to describe. ", valid_resources) fmt.Fprint(out, "You must specify the type of resource to describe. ", valid_resources)
return cmdutil.UsageError(cmd, "Required resource not specified.") return cmdutil.UsageError(cmd, "Required resource not specified.")
} }
@ -92,6 +98,7 @@ func RunDescribe(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
ContinueOnError(). ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, filenames...).
SelectorParam(selector). SelectorParam(selector).
ResourceTypeOrNameArgs(false, args...). ResourceTypeOrNameArgs(false, args...).
Flatten(). Flatten().
@ -100,41 +107,49 @@ func RunDescribe(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
if err != nil { if err != nil {
return err return err
} }
mapping, err := r.ResourceMapping()
if err != nil {
return err
}
describer, err := f.Describer(mapping) allErrs := []error{}
if err != nil {
return err
}
infos, err := r.Infos() infos, err := r.Infos()
if err != nil { if err != nil {
if apierrors.IsNotFound(err) && len(args) == 2 { if apierrors.IsNotFound(err) && len(args) == 2 {
return DescribeMatchingResources(mapper, typer, describer, f, cmdNamespace, args[0], args[1], out, err) return DescribeMatchingResources(mapper, typer, f, cmdNamespace, args[0], args[1], out, err)
} }
return err allErrs = append(allErrs, err)
} }
for _, info := range infos { for _, info := range infos {
mapping := info.ResourceMapping()
describer, err := f.Describer(mapping)
if err != nil {
allErrs = append(allErrs, err)
continue
}
s, err := describer.Describe(info.Namespace, info.Name) s, err := describer.Describe(info.Namespace, info.Name)
if err != nil { if err != nil {
return err allErrs = append(allErrs, err)
continue
} }
fmt.Fprintf(out, "%s\n\n", s) fmt.Fprintf(out, "%s\n\n", s)
} }
return nil return errors.NewAggregate(allErrs)
} }
func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, describer kubectl.Describer, f *cmdutil.Factory, namespace, rsrc, prefix string, out io.Writer, originalError error) error { func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f *cmdutil.Factory, namespace, rsrc, prefix string, out io.Writer, originalError error) error {
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
NamespaceParam(namespace).DefaultNamespace(). NamespaceParam(namespace).DefaultNamespace().
ResourceTypeOrNameArgs(true, rsrc). ResourceTypeOrNameArgs(true, rsrc).
SingleResourceType(). SingleResourceType().
Flatten(). Flatten().
Do() Do()
mapping, err := r.ResourceMapping()
if err != nil {
return err
}
describer, err := f.Describer(mapping)
if err != nil {
return err
}
infos, err := r.Infos() infos, err := r.Infos()
if err != nil { if err != nil {
return err return err

View File

@ -48,3 +48,36 @@ func TestDescribeUnknownSchemaObject(t *testing.T) {
t.Errorf("unexpected output: %s", buf.String()) t.Errorf("unexpected output: %s", buf.String())
} }
} }
func TestDescribeObject(t *testing.T) {
_, _, rc := testData()
f, tf, codec := NewAPIFactory()
d := &testDescriber{Output: "test output"}
tf.Describer = d
tf.Client = &client.FakeRESTClient{
Codec: codec,
Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/replicationcontrollers/redis-master" && m == "GET":
return &http.Response{StatusCode: 200, Body: objBody(codec, &rc.Items[0])}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{})
cmd := NewCmdDescribe(f, buf)
cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.yaml")
cmd.Run(cmd, []string{})
if d.Name != "redis-master" || d.Namespace != "test" {
t.Errorf("unexpected describer: %#v", d)
}
if buf.String() != fmt.Sprintf("%s\n\n", d.Output) {
t.Errorf("unexpected output: %s", buf.String())
}
}