1
16
17 package describe
18
19 import (
20 "fmt"
21 "strings"
22
23 "github.com/spf13/cobra"
24
25 apierrors "k8s.io/apimachinery/pkg/api/errors"
26 "k8s.io/apimachinery/pkg/api/meta"
27 utilerrors "k8s.io/apimachinery/pkg/util/errors"
28 "k8s.io/apimachinery/pkg/util/sets"
29 "k8s.io/cli-runtime/pkg/genericiooptions"
30 "k8s.io/cli-runtime/pkg/resource"
31 cmdutil "k8s.io/kubectl/pkg/cmd/util"
32 "k8s.io/kubectl/pkg/describe"
33 "k8s.io/kubectl/pkg/util/completion"
34 "k8s.io/kubectl/pkg/util/i18n"
35 "k8s.io/kubectl/pkg/util/templates"
36 )
37
38 var (
39 describeLong = templates.LongDesc(i18n.T(`
40 Show details of a specific resource or group of resources.
41
42 Print a detailed description of the selected resources, including related resources such
43 as events or controllers. You may select a single object by name, all objects of that
44 type, provide a name prefix, or label selector. For example:
45
46 $ kubectl describe TYPE NAME_PREFIX
47
48 will first check for an exact match on TYPE and NAME_PREFIX. If no such resource
49 exists, it will output details for every resource that has a name prefixed with NAME_PREFIX.`))
50
51 describeExample = templates.Examples(i18n.T(`
52 # Describe a node
53 kubectl describe nodes kubernetes-node-emt8.c.myproject.internal
54
55 # Describe a pod
56 kubectl describe pods/nginx
57
58 # Describe a pod identified by type and name in "pod.json"
59 kubectl describe -f pod.json
60
61 # Describe all pods
62 kubectl describe pods
63
64 # Describe pods by label name=myLabel
65 kubectl describe pods -l name=myLabel
66
67 # Describe all pods managed by the 'frontend' replication controller
68 # (rc-created pods get the name of the rc as a prefix in the pod name)
69 kubectl describe pods frontend`))
70 )
71
72
73
74 type DescribeFlags struct {
75 Factory cmdutil.Factory
76 Selector string
77 AllNamespaces bool
78 FilenameOptions *resource.FilenameOptions
79 DescriberSettings *describe.DescriberSettings
80 genericiooptions.IOStreams
81 }
82
83
84 func NewDescribeFlags(f cmdutil.Factory, streams genericiooptions.IOStreams) *DescribeFlags {
85 return &DescribeFlags{
86 Factory: f,
87 FilenameOptions: &resource.FilenameOptions{},
88 DescriberSettings: &describe.DescriberSettings{
89 ShowEvents: true,
90 ChunkSize: cmdutil.DefaultChunkSize,
91 },
92 IOStreams: streams,
93 }
94 }
95
96
97 func (flags *DescribeFlags) AddFlags(cmd *cobra.Command) {
98 cmdutil.AddFilenameOptionFlags(cmd, flags.FilenameOptions, "containing the resource to describe")
99 cmdutil.AddLabelSelectorFlagVar(cmd, &flags.Selector)
100 cmd.Flags().BoolVarP(&flags.AllNamespaces, "all-namespaces", "A", flags.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
101 cmd.Flags().BoolVar(&flags.DescriberSettings.ShowEvents, "show-events", flags.DescriberSettings.ShowEvents, "If true, display events related to the described object.")
102 cmdutil.AddChunkSizeFlag(cmd, &flags.DescriberSettings.ChunkSize)
103 }
104
105
106 func (flags *DescribeFlags) ToOptions(parent string, args []string) (*DescribeOptions, error) {
107
108 var err error
109 namespace, enforceNamespace, err := flags.Factory.ToRawKubeConfigLoader().Namespace()
110 if err != nil {
111 return nil, err
112 }
113
114 if flags.AllNamespaces {
115 enforceNamespace = false
116 }
117
118 if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(flags.FilenameOptions.Filenames, flags.FilenameOptions.Kustomize) {
119 return nil, fmt.Errorf("You must specify the type of resource to describe. %s\n", cmdutil.SuggestAPIResources(parent))
120 }
121
122 builderArgs := args
123
124 describer := func(mapping *meta.RESTMapping) (describe.ResourceDescriber, error) {
125 return describe.DescriberFn(flags.Factory, mapping)
126 }
127
128 o := &DescribeOptions{
129 Selector: flags.Selector,
130 Namespace: namespace,
131 Describer: describer,
132 NewBuilder: flags.Factory.NewBuilder,
133 BuilderArgs: builderArgs,
134 EnforceNamespace: enforceNamespace,
135 AllNamespaces: flags.AllNamespaces,
136 FilenameOptions: flags.FilenameOptions,
137 DescriberSettings: flags.DescriberSettings,
138 IOStreams: flags.IOStreams,
139 }
140
141 return o, nil
142 }
143
144 func NewCmdDescribe(parent string, f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
145 flags := NewDescribeFlags(f, streams)
146
147 cmd := &cobra.Command{
148 Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)",
149 DisableFlagsInUseLine: true,
150 Short: i18n.T("Show details of a specific resource or group of resources"),
151 Long: describeLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
152 Example: describeExample,
153 ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f),
154 Run: func(cmd *cobra.Command, args []string) {
155 o, err := flags.ToOptions(parent, args)
156 cmdutil.CheckErr(err)
157 cmdutil.CheckErr(o.Validate())
158 cmdutil.CheckErr(o.Run())
159 },
160 }
161
162 flags.AddFlags(cmd)
163
164 return cmd
165 }
166
167 func (o *DescribeOptions) Validate() error {
168 return nil
169 }
170
171 func (o *DescribeOptions) Run() error {
172 r := o.NewBuilder().
173 Unstructured().
174 ContinueOnError().
175 NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
176 FilenameParam(o.EnforceNamespace, o.FilenameOptions).
177 LabelSelectorParam(o.Selector).
178 ResourceTypeOrNameArgs(true, o.BuilderArgs...).
179 RequestChunksOf(o.DescriberSettings.ChunkSize).
180 Flatten().
181 Do()
182 err := r.Err()
183 if err != nil {
184 return err
185 }
186
187 allErrs := []error{}
188 infos, err := r.Infos()
189 if err != nil {
190 if apierrors.IsNotFound(err) && len(o.BuilderArgs) == 2 {
191 return o.DescribeMatchingResources(err, o.BuilderArgs[0], o.BuilderArgs[1])
192 }
193 allErrs = append(allErrs, err)
194 }
195
196 errs := sets.NewString()
197 first := true
198 for _, info := range infos {
199 mapping := info.ResourceMapping()
200 describer, err := o.Describer(mapping)
201 if err != nil {
202 if errs.Has(err.Error()) {
203 continue
204 }
205 allErrs = append(allErrs, err)
206 errs.Insert(err.Error())
207 continue
208 }
209 s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
210 if err != nil {
211 if errs.Has(err.Error()) {
212 continue
213 }
214 allErrs = append(allErrs, err)
215 errs.Insert(err.Error())
216 continue
217 }
218 if first {
219 first = false
220 fmt.Fprint(o.Out, s)
221 } else {
222 fmt.Fprintf(o.Out, "\n\n%s", s)
223 }
224 }
225
226 if len(infos) == 0 && len(allErrs) == 0 {
227
228 if o.AllNamespaces {
229 fmt.Fprintln(o.ErrOut, "No resources found")
230 } else {
231 fmt.Fprintf(o.ErrOut, "No resources found in %s namespace.\n", o.Namespace)
232 }
233 }
234
235 return utilerrors.NewAggregate(allErrs)
236 }
237
238 func (o *DescribeOptions) DescribeMatchingResources(originalError error, resource, prefix string) error {
239 r := o.NewBuilder().
240 Unstructured().
241 NamespaceParam(o.Namespace).DefaultNamespace().
242 ResourceTypeOrNameArgs(true, resource).
243 SingleResourceType().
244 RequestChunksOf(o.DescriberSettings.ChunkSize).
245 Flatten().
246 Do()
247 mapping, err := r.ResourceMapping()
248 if err != nil {
249 return err
250 }
251 describer, err := o.Describer(mapping)
252 if err != nil {
253 return err
254 }
255 infos, err := r.Infos()
256 if err != nil {
257 return err
258 }
259 isFound := false
260 for ix := range infos {
261 info := infos[ix]
262 if strings.HasPrefix(info.Name, prefix) {
263 isFound = true
264 s, err := describer.Describe(info.Namespace, info.Name, *o.DescriberSettings)
265 if err != nil {
266 return err
267 }
268 fmt.Fprintf(o.Out, "%s\n", s)
269 }
270 }
271 if !isFound {
272 return originalError
273 }
274 return nil
275 }
276
277 type DescribeOptions struct {
278 CmdParent string
279 Selector string
280 Namespace string
281
282 Describer func(*meta.RESTMapping) (describe.ResourceDescriber, error)
283 NewBuilder func() *resource.Builder
284
285 BuilderArgs []string
286
287 EnforceNamespace bool
288 AllNamespaces bool
289
290 DescriberSettings *describe.DescriberSettings
291 FilenameOptions *resource.FilenameOptions
292
293 genericiooptions.IOStreams
294 }
295
View as plain text