Skip to content

Commit

Permalink
Merge pull request kubernetes#10816 from feihujiang/kubectlDescribeAc…
Browse files Browse the repository at this point in the history
…ceptFileNameParam

Kubectl describe command accepts a filename param
  • Loading branch information
satnam6502 committed Aug 7, 2015
2 parents 4ece39a + 2ca200f commit b071857
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 20 deletions.
6 changes: 6 additions & 0 deletions contrib/completions/bash/kubectl
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,12 @@ _kubectl_describe()
flags_with_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+=("-h")
flags+=("--selector=")
Expand Down
7 changes: 7 additions & 0 deletions docs/man/man1/kubectl-describe.1
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ namespaces (ns) or secrets.


.SH OPTIONS
.PP
\fB\-f\fP, \fB\-\-filename\fP=[]
Filename, directory, or URL to a file containing the resource to describe

.PP
\fB\-h\fP, \fB\-\-help\fP=false
help for describe
Expand Down Expand Up @@ -152,6 +156,9 @@ $ kubectl describe nodes kubernetes\-minion\-emt8.c.myproject.internal
// Describe a pod
$ kubectl describe pods/nginx

// Describe a pod using the data in pod.json.
$ kubectl describe \-f pod.json

// Describe pods by label name=myLabel
$ kubectl describe po \-l name=myLabel

Expand Down
2 changes: 1 addition & 1 deletion docs/user-guide/kubectl/kubectl_api-versions.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ kubectl api-versions

* [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 -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_api-versions.md?pixel)]()
Expand Down
8 changes: 6 additions & 2 deletions docs/user-guide/kubectl/kubectl_describe.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ persistentvolumes (pv), persistentvolumeclaims (pvc), resourcequotas (quota),
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
Expand All @@ -66,6 +66,9 @@ $ kubectl describe nodes kubernetes-minion-emt8.c.myproject.internal
// Describe a pod
$ kubectl describe pods/nginx
// Describe a pod using the data in pod.json.
$ kubectl describe -f pod.json
// Describe pods by label name=myLabel
$ kubectl describe po -l name=myLabel
Expand All @@ -77,6 +80,7 @@ $ kubectl describe pods frontend
### Options

```
-f, --filename=[]: Filename, directory, or URL to a file containing the resource to describe
-h, --help[=false]: help for describe
-l, --selector="": Selector (label query) to filter on
```
Expand Down Expand Up @@ -114,7 +118,7 @@ $ kubectl describe pods frontend

* [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 -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_describe.md?pixel)]()
Expand Down
49 changes: 32 additions & 17 deletions pkg/kubectl/cmd/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/errors"
)

const (
Expand All @@ -52,6 +53,9 @@ $ kubectl describe nodes kubernetes-minion-emt8.c.myproject.internal
// Describe a pod
$ kubectl describe pods/nginx
// Describe a pod using the data in pod.json.
$ kubectl describe -f pod.json
// Describe pods by label name=myLabel
$ kubectl describe po -l name=myLabel
Expand All @@ -62,7 +66,7 @@ $ kubectl describe pods frontend`

func NewCmdDescribe(f *cmdutil.Factory, out io.Writer) *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",
Long: describe_long,
Example: describe_example,
Expand All @@ -72,18 +76,20 @@ func NewCmdDescribe(f *cmdutil.Factory, out io.Writer) *cobra.Command {
},
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")
return cmd
}

func RunDescribe(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
selector := cmdutil.GetFlagString(cmd, "selector")
cmdNamespace, _, err := f.DefaultNamespace()
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
}

if len(args) == 0 {
filenames := cmdutil.GetFlagStringSlice(cmd, "filename")
if len(args) == 0 && len(filenames) == 0 {
fmt.Fprint(out, "You must specify the type of resource to describe. ", valid_resources)
return cmdutil.UsageError(cmd, "Required resource not specified.")
}
Expand All @@ -92,6 +98,7 @@ func RunDescribe(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, filenames...).
SelectorParam(selector).
ResourceTypeOrNameArgs(false, args...).
Flatten().
Expand All @@ -100,41 +107,49 @@ func RunDescribe(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
if err != nil {
return err
}
mapping, err := r.ResourceMapping()
if err != nil {
return err
}

describer, err := f.Describer(mapping)
if err != nil {
return err
}
allErrs := []error{}
infos, err := r.Infos()
if err != nil {
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 {
mapping := info.ResourceMapping()
describer, err := f.Describer(mapping)
if err != nil {
allErrs = append(allErrs, err)
continue
}
s, err := describer.Describe(info.Namespace, info.Name)
if err != nil {
return err
allErrs = append(allErrs, err)
continue
}
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()).
NamespaceParam(namespace).DefaultNamespace().
ResourceTypeOrNameArgs(true, rsrc).
SingleResourceType().
Flatten().
Do()
mapping, err := r.ResourceMapping()
if err != nil {
return err
}
describer, err := f.Describer(mapping)
if err != nil {
return err
}
infos, err := r.Infos()
if err != nil {
return err
Expand Down
33 changes: 33 additions & 0 deletions pkg/kubectl/cmd/describe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,36 @@ func TestDescribeUnknownSchemaObject(t *testing.T) {
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())
}
}

0 comments on commit b071857

Please sign in to comment.