describe.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package describe
  14. import (
  15. "fmt"
  16. "strings"
  17. "github.com/spf13/cobra"
  18. apierrors "k8s.io/apimachinery/pkg/api/errors"
  19. "k8s.io/apimachinery/pkg/api/meta"
  20. utilerrors "k8s.io/apimachinery/pkg/util/errors"
  21. "k8s.io/apimachinery/pkg/util/sets"
  22. "k8s.io/cli-runtime/pkg/genericclioptions"
  23. "k8s.io/cli-runtime/pkg/resource"
  24. cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
  25. "k8s.io/kubernetes/pkg/kubectl/describe"
  26. describeversioned "k8s.io/kubernetes/pkg/kubectl/describe/versioned"
  27. "k8s.io/kubernetes/pkg/kubectl/util/i18n"
  28. "k8s.io/kubernetes/pkg/kubectl/util/templates"
  29. )
  30. var (
  31. describeLong = templates.LongDesc(`
  32. Show details of a specific resource or group of resources
  33. Print a detailed description of the selected resources, including related resources such
  34. as events or controllers. You may select a single object by name, all objects of that
  35. type, provide a name prefix, or label selector. For example:
  36. $ kubectl describe TYPE NAME_PREFIX
  37. will first check for an exact match on TYPE and NAME_PREFIX. If no such resource
  38. exists, it will output details for every resource that has a name prefixed with NAME_PREFIX.`)
  39. describeExample = templates.Examples(i18n.T(`
  40. # Describe a node
  41. kubectl describe nodes kubernetes-node-emt8.c.myproject.internal
  42. # Describe a pod
  43. kubectl describe pods/nginx
  44. # Describe a pod identified by type and name in "pod.json"
  45. kubectl describe -f pod.json
  46. # Describe all pods
  47. kubectl describe pods
  48. # Describe pods by label name=myLabel
  49. kubectl describe po -l name=myLabel
  50. # Describe all pods managed by the 'frontend' replication controller (rc-created pods
  51. # get the name of the rc as a prefix in the pod the name).
  52. kubectl describe pods frontend`))
  53. )
  54. type DescribeOptions struct {
  55. CmdParent string
  56. Selector string
  57. Namespace string
  58. Describer func(*meta.RESTMapping) (describe.Describer, error)
  59. NewBuilder func() *resource.Builder
  60. BuilderArgs []string
  61. EnforceNamespace bool
  62. AllNamespaces bool
  63. DescriberSettings *describe.DescriberSettings
  64. FilenameOptions *resource.FilenameOptions
  65. genericclioptions.IOStreams
  66. }
  67. func NewCmdDescribe(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
  68. o := &DescribeOptions{
  69. FilenameOptions: &resource.FilenameOptions{},
  70. DescriberSettings: &describe.DescriberSettings{
  71. ShowEvents: true,
  72. },
  73. CmdParent: parent,
  74. IOStreams: streams,
  75. }
  76. cmd := &cobra.Command{
  77. Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)",
  78. DisableFlagsInUseLine: true,
  79. Short: i18n.T("Show details of a specific resource or group of resources"),
  80. Long: describeLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
  81. Example: describeExample,
  82. Run: func(cmd *cobra.Command, args []string) {
  83. cmdutil.CheckErr(o.Complete(f, cmd, args))
  84. cmdutil.CheckErr(o.Run())
  85. },
  86. }
  87. usage := "containing the resource to describe"
  88. cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, usage)
  89. cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
  90. cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
  91. cmd.Flags().BoolVar(&o.DescriberSettings.ShowEvents, "show-events", o.DescriberSettings.ShowEvents, "If true, display events related to the described object.")
  92. cmdutil.AddIncludeUninitializedFlag(cmd)
  93. return cmd
  94. }
  95. func (o *DescribeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
  96. var err error
  97. o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
  98. if err != nil {
  99. return err
  100. }
  101. if o.AllNamespaces {
  102. o.EnforceNamespace = false
  103. }
  104. if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
  105. return fmt.Errorf("You must specify the type of resource to describe. %s\n", cmdutil.SuggestAPIResources(o.CmdParent))
  106. }
  107. o.BuilderArgs = args
  108. o.Describer = func(mapping *meta.RESTMapping) (describe.Describer, error) {
  109. return describeversioned.DescriberFn(f, mapping)
  110. }
  111. o.NewBuilder = f.NewBuilder
  112. return nil
  113. }
  114. func (o *DescribeOptions) Validate(args []string) error {
  115. return nil
  116. }
  117. func (o *DescribeOptions) Run() error {
  118. r := o.NewBuilder().
  119. Unstructured().
  120. ContinueOnError().
  121. NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
  122. FilenameParam(o.EnforceNamespace, o.FilenameOptions).
  123. LabelSelectorParam(o.Selector).
  124. ResourceTypeOrNameArgs(true, o.BuilderArgs...).
  125. Flatten().
  126. Do()
  127. err := r.Err()
  128. if err != nil {
  129. return err
  130. }
  131. allErrs := []error{}
  132. infos, err := r.Infos()
  133. if err != nil {
  134. if apierrors.IsNotFound(err) && len(o.BuilderArgs) == 2 {
  135. return o.DescribeMatchingResources(err, o.BuilderArgs[0], o.BuilderArgs[1])
  136. }
  137. allErrs = append(allErrs, err)
  138. }
  139. errs := sets.NewString()
  140. first := true
  141. for _, info := range infos {
  142. mapping := info.ResourceMapping()
  143. describer, err := o.Describer(mapping)
  144. if err != nil {
  145. if errs.Has(err.Error()) {
  146. continue
  147. }
  148. allErrs = append(allErrs, err)
  149. errs.Insert(err.Error())
  150. continue
  151. }
  152. s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
  153. if err != nil {
  154. if errs.Has(err.Error()) {
  155. continue
  156. }
  157. allErrs = append(allErrs, err)
  158. errs.Insert(err.Error())
  159. continue
  160. }
  161. if first {
  162. first = false
  163. fmt.Fprint(o.Out, s)
  164. } else {
  165. fmt.Fprintf(o.Out, "\n\n%s", s)
  166. }
  167. }
  168. return utilerrors.NewAggregate(allErrs)
  169. }
  170. func (o *DescribeOptions) DescribeMatchingResources(originalError error, resource, prefix string) error {
  171. r := o.NewBuilder().
  172. Unstructured().
  173. NamespaceParam(o.Namespace).DefaultNamespace().
  174. ResourceTypeOrNameArgs(true, resource).
  175. SingleResourceType().
  176. Flatten().
  177. Do()
  178. mapping, err := r.ResourceMapping()
  179. if err != nil {
  180. return err
  181. }
  182. describer, err := o.Describer(mapping)
  183. if err != nil {
  184. return err
  185. }
  186. infos, err := r.Infos()
  187. if err != nil {
  188. return err
  189. }
  190. isFound := false
  191. for ix := range infos {
  192. info := infos[ix]
  193. if strings.HasPrefix(info.Name, prefix) {
  194. isFound = true
  195. s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
  196. if err != nil {
  197. return err
  198. }
  199. fmt.Fprintf(o.Out, "%s\n", s)
  200. }
  201. }
  202. if !isFound {
  203. return originalError
  204. }
  205. return nil
  206. }