1
16
17 package get
18
19 import (
20 "context"
21 "encoding/json"
22 "fmt"
23 "io"
24 "net/url"
25 "strings"
26
27 "github.com/spf13/cobra"
28
29 corev1 "k8s.io/api/core/v1"
30 apierrors "k8s.io/apimachinery/pkg/api/errors"
31 "k8s.io/apimachinery/pkg/api/meta"
32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
34 metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
35 "k8s.io/apimachinery/pkg/runtime"
36 utilerrors "k8s.io/apimachinery/pkg/util/errors"
37 "k8s.io/apimachinery/pkg/util/sets"
38 "k8s.io/apimachinery/pkg/watch"
39 "k8s.io/cli-runtime/pkg/genericiooptions"
40 "k8s.io/cli-runtime/pkg/printers"
41 "k8s.io/cli-runtime/pkg/resource"
42 kubernetesscheme "k8s.io/client-go/kubernetes/scheme"
43 "k8s.io/client-go/rest"
44 watchtools "k8s.io/client-go/tools/watch"
45 cmdutil "k8s.io/kubectl/pkg/cmd/util"
46 "k8s.io/kubectl/pkg/rawhttp"
47 "k8s.io/kubectl/pkg/scheme"
48 "k8s.io/kubectl/pkg/util/i18n"
49 "k8s.io/kubectl/pkg/util/interrupt"
50 "k8s.io/kubectl/pkg/util/slice"
51 "k8s.io/kubectl/pkg/util/templates"
52 utilpointer "k8s.io/utils/pointer"
53 )
54
55
56 type GetOptions struct {
57 PrintFlags *PrintFlags
58 ToPrinter func(*meta.RESTMapping, *bool, bool, bool) (printers.ResourcePrinterFunc, error)
59 IsHumanReadablePrinter bool
60
61 CmdParent string
62
63 resource.FilenameOptions
64
65 Raw string
66 Watch bool
67 WatchOnly bool
68 ChunkSize int64
69
70 OutputWatchEvents bool
71
72 LabelSelector string
73 FieldSelector string
74 AllNamespaces bool
75 Namespace string
76 ExplicitNamespace bool
77 Subresource string
78 SortBy string
79
80 ServerPrint bool
81
82 NoHeaders bool
83 IgnoreNotFound bool
84
85 genericiooptions.IOStreams
86 }
87
88 var (
89 getLong = templates.LongDesc(i18n.T(`
90 Display one or many resources.
91
92 Prints a table of the most important information about the specified resources.
93 You can filter the list using a label selector and the --selector flag. If the
94 desired resource type is namespaced you will only see results in your current
95 namespace unless you pass --all-namespaces.
96
97 By specifying the output as 'template' and providing a Go template as the value
98 of the --template flag, you can filter the attributes of the fetched resources.`))
99
100 getExample = templates.Examples(i18n.T(`
101 # List all pods in ps output format
102 kubectl get pods
103
104 # List all pods in ps output format with more information (such as node name)
105 kubectl get pods -o wide
106
107 # List a single replication controller with specified NAME in ps output format
108 kubectl get replicationcontroller web
109
110 # List deployments in JSON output format, in the "v1" version of the "apps" API group
111 kubectl get deployments.v1.apps -o json
112
113 # List a single pod in JSON output format
114 kubectl get -o json pod web-pod-13je7
115
116 # List a pod identified by type and name specified in "pod.yaml" in JSON output format
117 kubectl get -f pod.yaml -o json
118
119 # List resources from a directory with kustomization.yaml - e.g. dir/kustomization.yaml
120 kubectl get -k dir/
121
122 # Return only the phase value of the specified pod
123 kubectl get -o template pod/web-pod-13je7 --template={{.status.phase}}
124
125 # List resource information in custom columns
126 kubectl get pod test-pod -o custom-columns=CONTAINER:.spec.containers[0].name,IMAGE:.spec.containers[0].image
127
128 # List all replication controllers and services together in ps output format
129 kubectl get rc,services
130
131 # List one or more resources by their type and names
132 kubectl get rc/web service/frontend pods/web-pod-13je7
133
134 # List the 'status' subresource for a single pod
135 kubectl get pod web-pod-13je7 --subresource status`))
136 )
137
138 const (
139 useServerPrintColumns = "server-print"
140 )
141
142 var supportedSubresources = []string{"status", "scale"}
143
144
145 func NewGetOptions(parent string, streams genericiooptions.IOStreams) *GetOptions {
146 return &GetOptions{
147 PrintFlags: NewGetPrintFlags(),
148 CmdParent: parent,
149
150 IOStreams: streams,
151 ChunkSize: cmdutil.DefaultChunkSize,
152 ServerPrint: true,
153 }
154 }
155
156
157
158 func NewCmdGet(parent string, f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
159 o := NewGetOptions(parent, streams)
160
161 cmd := &cobra.Command{
162 Use: fmt.Sprintf("get [(-o|--output=)%s] (TYPE[.VERSION][.GROUP] [NAME | -l label] | TYPE[.VERSION][.GROUP]/NAME ...) [flags]", strings.Join(o.PrintFlags.AllowedFormats(), "|")),
163 DisableFlagsInUseLine: true,
164 Short: i18n.T("Display one or many resources"),
165 Long: getLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
166 Example: getExample,
167
168 Run: func(cmd *cobra.Command, args []string) {
169 cmdutil.CheckErr(o.Complete(f, cmd, args))
170 cmdutil.CheckErr(o.Validate())
171 cmdutil.CheckErr(o.Run(f, args))
172 },
173 SuggestFor: []string{"list", "ps"},
174 }
175
176 o.PrintFlags.AddFlags(cmd)
177
178 cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to request from the server. Uses the transport specified by the kubeconfig file.")
179 cmd.Flags().BoolVarP(&o.Watch, "watch", "w", o.Watch, "After listing/getting the requested object, watch for changes.")
180 cmd.Flags().BoolVar(&o.WatchOnly, "watch-only", o.WatchOnly, "Watch for changes to the requested object(s), without listing/getting first.")
181 cmd.Flags().BoolVar(&o.OutputWatchEvents, "output-watch-events", o.OutputWatchEvents, "Output watch event objects when --watch or --watch-only is used. Existing objects are output as initial ADDED events.")
182 cmd.Flags().BoolVar(&o.IgnoreNotFound, "ignore-not-found", o.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.")
183 cmd.Flags().StringVar(&o.FieldSelector, "field-selector", o.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
184 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.")
185 addServerPrintColumnFlags(cmd, o)
186 cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, "identifying the resource to get from a server.")
187 cmdutil.AddChunkSizeFlag(cmd, &o.ChunkSize)
188 cmdutil.AddLabelSelectorFlagVar(cmd, &o.LabelSelector)
189 cmdutil.AddSubresourceFlags(cmd, &o.Subresource, "If specified, gets the subresource of the requested object.", supportedSubresources...)
190 return cmd
191 }
192
193
194 func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
195 if len(o.Raw) > 0 {
196 if len(args) > 0 {
197 return fmt.Errorf("arguments may not be passed when --raw is specified")
198 }
199 return nil
200 }
201
202 var err error
203 o.Namespace, o.ExplicitNamespace, err = f.ToRawKubeConfigLoader().Namespace()
204 if err != nil {
205 return err
206 }
207 if o.AllNamespaces {
208 o.ExplicitNamespace = false
209 }
210
211 if o.PrintFlags.HumanReadableFlags.SortBy != nil {
212 o.SortBy = *o.PrintFlags.HumanReadableFlags.SortBy
213 }
214
215 o.NoHeaders = cmdutil.GetFlagBool(cmd, "no-headers")
216
217
218
219 outputOption := cmd.Flags().Lookup("output").Value.String()
220 if strings.Contains(outputOption, "custom-columns") || outputOption == "yaml" || strings.Contains(outputOption, "json") {
221 o.ServerPrint = false
222 }
223
224 templateArg := ""
225 if o.PrintFlags.TemplateFlags != nil && o.PrintFlags.TemplateFlags.TemplateArgument != nil {
226 templateArg = *o.PrintFlags.TemplateFlags.TemplateArgument
227 }
228
229
230 if (len(*o.PrintFlags.OutputFormat) == 0 && len(templateArg) == 0) || *o.PrintFlags.OutputFormat == "wide" {
231 o.IsHumanReadablePrinter = true
232 }
233
234 o.ToPrinter = func(mapping *meta.RESTMapping, outputObjects *bool, withNamespace bool, withKind bool) (printers.ResourcePrinterFunc, error) {
235
236 printFlags := o.PrintFlags.Copy()
237
238 if mapping != nil {
239 printFlags.SetKind(mapping.GroupVersionKind.GroupKind())
240 }
241 if withNamespace {
242 printFlags.EnsureWithNamespace()
243 }
244 if withKind {
245 printFlags.EnsureWithKind()
246 }
247
248 printer, err := printFlags.ToPrinter()
249 if err != nil {
250 return nil, err
251 }
252 printer, err = printers.NewTypeSetter(scheme.Scheme).WrapToPrinter(printer, nil)
253 if err != nil {
254 return nil, err
255 }
256
257 if len(o.SortBy) > 0 {
258 printer = &SortingPrinter{Delegate: printer, SortField: o.SortBy}
259 }
260 if outputObjects != nil {
261 printer = &skipPrinter{delegate: printer, output: outputObjects}
262 }
263 if o.ServerPrint {
264 printer = &TablePrinter{Delegate: printer}
265 }
266 return printer.PrintObj, nil
267 }
268
269 switch {
270 case o.Watch || o.WatchOnly:
271 if len(o.SortBy) > 0 {
272 fmt.Fprintf(o.IOStreams.ErrOut, "warning: --watch or --watch-only requested, --sort-by will be ignored\n")
273 }
274 default:
275 if len(args) == 0 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
276 fmt.Fprintf(o.ErrOut, "You must specify the type of resource to get. %s\n\n", cmdutil.SuggestAPIResources(o.CmdParent))
277 fullCmdName := cmd.Parent().CommandPath()
278 usageString := "Required resource not specified."
279 if len(fullCmdName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "explain") {
280 usageString = fmt.Sprintf("%s\nUse \"%s explain <resource>\" for a detailed description of that resource (e.g. %[2]s explain pods).", usageString, fullCmdName)
281 }
282
283 return cmdutil.UsageErrorf(cmd, usageString)
284 }
285 }
286
287 return nil
288 }
289
290
291 func (o *GetOptions) Validate() error {
292 if len(o.Raw) > 0 {
293 if o.Watch || o.WatchOnly || len(o.LabelSelector) > 0 {
294 return fmt.Errorf("--raw may not be specified with other flags that filter the server request or alter the output")
295 }
296 if o.PrintFlags.OutputFormat != nil && len(*o.PrintFlags.OutputFormat) > 0 {
297 return fmt.Errorf("--raw and --output are mutually exclusive")
298 }
299 if _, err := url.ParseRequestURI(o.Raw); err != nil {
300 return fmt.Errorf("--raw must be a valid URL path: %v", err)
301 }
302 }
303 if o.PrintFlags.HumanReadableFlags.ShowLabels != nil && *o.PrintFlags.HumanReadableFlags.ShowLabels && o.PrintFlags.OutputFormat != nil {
304 outputOption := *o.PrintFlags.OutputFormat
305 if outputOption != "" && outputOption != "wide" {
306 return fmt.Errorf("--show-labels option cannot be used with %s printer", outputOption)
307 }
308 }
309 if o.OutputWatchEvents && !(o.Watch || o.WatchOnly) {
310 return fmt.Errorf("--output-watch-events option can only be used with --watch or --watch-only")
311 }
312 if len(o.Subresource) > 0 && !slice.ContainsString(supportedSubresources, o.Subresource, nil) {
313 return fmt.Errorf("invalid subresource value: %q. Must be one of %v", o.Subresource, supportedSubresources)
314 }
315 return nil
316 }
317
318
319 type OriginalPositioner interface {
320 OriginalPosition(int) int
321 }
322
323
324 type NopPositioner struct{}
325
326
327 func (t *NopPositioner) OriginalPosition(ix int) int {
328 return ix
329 }
330
331
332 type RuntimeSorter struct {
333 field string
334 decoder runtime.Decoder
335 objects []runtime.Object
336 positioner OriginalPositioner
337 }
338
339
340 func (r *RuntimeSorter) Sort() error {
341
342
343 if len(r.objects) == 0 {
344 return nil
345 }
346 if len(r.objects) == 1 {
347 _, isTable := r.objects[0].(*metav1.Table)
348 if !isTable {
349 return nil
350 }
351 }
352
353 includesTable := false
354 includesRuntimeObjs := false
355
356 for _, obj := range r.objects {
357 switch t := obj.(type) {
358 case *metav1.Table:
359 includesTable = true
360
361 if sorter, err := NewTableSorter(t, r.field); err != nil {
362 return err
363 } else if err := sorter.Sort(); err != nil {
364 return err
365 }
366 default:
367 includesRuntimeObjs = true
368 }
369 }
370
371
372
373
374 r.positioner = &NopPositioner{}
375
376 if includesRuntimeObjs && includesTable {
377 return fmt.Errorf("sorting is not supported on mixed Table and non-Table object lists")
378 }
379 if includesTable {
380 return nil
381 }
382
383
384
385 var err error
386 if r.positioner, err = SortObjects(r.decoder, r.objects, r.field); err != nil {
387 return err
388 }
389 return nil
390 }
391
392
393 func (r *RuntimeSorter) OriginalPosition(ix int) int {
394 if r.positioner == nil {
395 return 0
396 }
397 return r.positioner.OriginalPosition(ix)
398 }
399
400
401 func (r *RuntimeSorter) WithDecoder(decoder runtime.Decoder) *RuntimeSorter {
402 r.decoder = decoder
403 return r
404 }
405
406
407 func NewRuntimeSorter(objects []runtime.Object, sortBy string) *RuntimeSorter {
408 parsedField, err := RelaxedJSONPathExpression(sortBy)
409 if err != nil {
410 parsedField = sortBy
411 }
412
413 return &RuntimeSorter{
414 field: parsedField,
415 decoder: kubernetesscheme.Codecs.UniversalDecoder(),
416 objects: objects,
417 }
418 }
419
420 func (o *GetOptions) transformRequests(req *rest.Request) {
421 if !o.ServerPrint || !o.IsHumanReadablePrinter {
422 return
423 }
424
425 req.SetHeader("Accept", strings.Join([]string{
426 fmt.Sprintf("application/json;as=Table;v=%s;g=%s", metav1.SchemeGroupVersion.Version, metav1.GroupName),
427 fmt.Sprintf("application/json;as=Table;v=%s;g=%s", metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName),
428 "application/json",
429 }, ","))
430
431
432 if len(o.SortBy) > 0 {
433 req.Param("includeObject", "Object")
434 }
435 }
436
437
438
439 func (o *GetOptions) Run(f cmdutil.Factory, args []string) error {
440 if len(o.Raw) > 0 {
441 restClient, err := f.RESTClient()
442 if err != nil {
443 return err
444 }
445 return rawhttp.RawGet(restClient, o.IOStreams, o.Raw)
446 }
447 if o.Watch || o.WatchOnly {
448 return o.watch(f, args)
449 }
450
451 chunkSize := o.ChunkSize
452 if len(o.SortBy) > 0 {
453
454
455 chunkSize = 0
456 }
457
458 r := f.NewBuilder().
459 Unstructured().
460 NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
461 FilenameParam(o.ExplicitNamespace, &o.FilenameOptions).
462 LabelSelectorParam(o.LabelSelector).
463 FieldSelectorParam(o.FieldSelector).
464 Subresource(o.Subresource).
465 RequestChunksOf(chunkSize).
466 ResourceTypeOrNameArgs(true, args...).
467 ContinueOnError().
468 Latest().
469 Flatten().
470 TransformRequests(o.transformRequests).
471 Do()
472
473 if o.IgnoreNotFound {
474 r.IgnoreErrors(apierrors.IsNotFound)
475 }
476 if err := r.Err(); err != nil {
477 return err
478 }
479
480 if !o.IsHumanReadablePrinter {
481 return o.printGeneric(r)
482 }
483
484 allErrs := []error{}
485 errs := sets.NewString()
486 infos, err := r.Infos()
487 if err != nil {
488 allErrs = append(allErrs, err)
489 }
490 printWithKind := multipleGVKsRequested(infos)
491
492 objs := make([]runtime.Object, len(infos))
493 for ix := range infos {
494 objs[ix] = infos[ix].Object
495 }
496
497 var positioner OriginalPositioner
498 if len(o.SortBy) > 0 {
499 sorter := NewRuntimeSorter(objs, o.SortBy)
500 if err := sorter.Sort(); err != nil {
501 return err
502 }
503 positioner = sorter
504 }
505
506 var printer printers.ResourcePrinter
507 var lastMapping *meta.RESTMapping
508
509
510 trackingWriter := &trackingWriterWrapper{Delegate: o.Out}
511
512 separatorWriter := &separatorWriterWrapper{Delegate: trackingWriter}
513
514 w := printers.GetNewTabWriter(separatorWriter)
515 allResourcesNamespaced := !o.AllNamespaces
516 for ix := range objs {
517 var mapping *meta.RESTMapping
518 var info *resource.Info
519 if positioner != nil {
520 info = infos[positioner.OriginalPosition(ix)]
521 mapping = info.Mapping
522 } else {
523 info = infos[ix]
524 mapping = info.Mapping
525 }
526
527 allResourcesNamespaced = allResourcesNamespaced && info.Namespaced()
528 printWithNamespace := o.AllNamespaces
529
530 if mapping != nil && mapping.Scope.Name() == meta.RESTScopeNameRoot {
531 printWithNamespace = false
532 }
533
534 if shouldGetNewPrinterForMapping(printer, lastMapping, mapping) {
535 w.Flush()
536 w.SetRememberedWidths(nil)
537
538
539
540
541
542
543 if lastMapping != nil && !o.NoHeaders && trackingWriter.Written > 0 {
544 separatorWriter.SetReady(true)
545 }
546
547 printer, err = o.ToPrinter(mapping, nil, printWithNamespace, printWithKind)
548 if err != nil {
549 if !errs.Has(err.Error()) {
550 errs.Insert(err.Error())
551 allErrs = append(allErrs, err)
552 }
553 continue
554 }
555
556 lastMapping = mapping
557 }
558
559 printer.PrintObj(info.Object, w)
560 }
561 w.Flush()
562 if trackingWriter.Written == 0 && !o.IgnoreNotFound && len(allErrs) == 0 {
563
564 if allResourcesNamespaced {
565 fmt.Fprintf(o.ErrOut, "No resources found in %s namespace.\n", o.Namespace)
566 } else {
567 fmt.Fprintln(o.ErrOut, "No resources found")
568 }
569 }
570 return utilerrors.NewAggregate(allErrs)
571 }
572
573 type trackingWriterWrapper struct {
574 Delegate io.Writer
575 Written int
576 }
577
578 func (t *trackingWriterWrapper) Write(p []byte) (n int, err error) {
579 t.Written += len(p)
580 return t.Delegate.Write(p)
581 }
582
583 type separatorWriterWrapper struct {
584 Delegate io.Writer
585 Ready bool
586 }
587
588 func (s *separatorWriterWrapper) Write(p []byte) (n int, err error) {
589
590
591 if len(p) != 0 && s.Ready {
592 fmt.Fprintln(s.Delegate)
593 s.Ready = false
594 }
595 return s.Delegate.Write(p)
596 }
597
598 func (s *separatorWriterWrapper) SetReady(state bool) {
599 s.Ready = state
600 }
601
602
603
604 func (o *GetOptions) watch(f cmdutil.Factory, args []string) error {
605 r := f.NewBuilder().
606 Unstructured().
607 NamespaceParam(o.Namespace).DefaultNamespace().AllNamespaces(o.AllNamespaces).
608 FilenameParam(o.ExplicitNamespace, &o.FilenameOptions).
609 LabelSelectorParam(o.LabelSelector).
610 FieldSelectorParam(o.FieldSelector).
611 RequestChunksOf(o.ChunkSize).
612 ResourceTypeOrNameArgs(true, args...).
613 SingleResourceType().
614 Latest().
615 TransformRequests(o.transformRequests).
616 Do()
617 if err := r.Err(); err != nil {
618 return err
619 }
620 infos, err := r.Infos()
621 if err != nil {
622 return err
623 }
624 if multipleGVKsRequested(infos) {
625 return i18n.Errorf("watch is only supported on individual resources and resource collections - more than 1 resource was found")
626 }
627
628 info := infos[0]
629 mapping := info.ResourceMapping()
630 outputObjects := utilpointer.BoolPtr(!o.WatchOnly)
631 printer, err := o.ToPrinter(mapping, outputObjects, o.AllNamespaces, false)
632 if err != nil {
633 return err
634 }
635 obj, err := r.Object()
636 if err != nil {
637 return err
638 }
639
640
641
642
643
644 rv := "0"
645 isList := meta.IsListType(obj)
646 if isList {
647
648
649 rv, err = meta.NewAccessor().ResourceVersion(obj)
650 if err != nil {
651 return err
652 }
653 }
654
655 writer := printers.GetNewTabWriter(o.Out)
656
657
658 var objsToPrint []runtime.Object
659 if isList {
660 objsToPrint, _ = meta.ExtractList(obj)
661 } else {
662 objsToPrint = append(objsToPrint, obj)
663 }
664 for _, objToPrint := range objsToPrint {
665 if o.OutputWatchEvents {
666 objToPrint = &metav1.WatchEvent{Type: string(watch.Added), Object: runtime.RawExtension{Object: objToPrint}}
667 }
668 if err := printer.PrintObj(objToPrint, writer); err != nil {
669 return fmt.Errorf("unable to output the provided object: %v", err)
670 }
671 }
672 writer.Flush()
673 if isList {
674
675 *outputObjects = true
676 } else {
677
678 *outputObjects = false
679 }
680
681
682 w, err := r.Watch(rv)
683 if err != nil {
684 return err
685 }
686
687 ctx, cancel := context.WithCancel(context.Background())
688 defer cancel()
689 intr := interrupt.New(nil, cancel)
690 intr.Run(func() error {
691 _, err := watchtools.UntilWithoutRetry(ctx, w, func(e watch.Event) (bool, error) {
692 objToPrint := e.Object
693 if o.OutputWatchEvents {
694 objToPrint = &metav1.WatchEvent{Type: string(e.Type), Object: runtime.RawExtension{Object: objToPrint}}
695 }
696 if err := printer.PrintObj(objToPrint, writer); err != nil {
697 return false, err
698 }
699 writer.Flush()
700
701 *outputObjects = true
702 return false, nil
703 })
704 return err
705 })
706 return nil
707 }
708
709 func (o *GetOptions) printGeneric(r *resource.Result) error {
710
711
712
713
714 var errs []error
715 singleItemImplied := false
716 infos, err := r.IntoSingleItemImplied(&singleItemImplied).Infos()
717 if err != nil {
718 if singleItemImplied {
719 return err
720 }
721 errs = append(errs, err)
722 }
723
724 if len(infos) == 0 && o.IgnoreNotFound {
725 return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs)))
726 }
727
728 printer, err := o.ToPrinter(nil, nil, false, false)
729 if err != nil {
730 return err
731 }
732
733 var obj runtime.Object
734 if !singleItemImplied || len(infos) != 1 {
735
736
737
738
739 list := corev1.List{
740 TypeMeta: metav1.TypeMeta{
741 Kind: "List",
742 APIVersion: "v1",
743 },
744 ListMeta: metav1.ListMeta{},
745 }
746 for _, info := range infos {
747 list.Items = append(list.Items, runtime.RawExtension{Object: info.Object})
748 }
749
750 listData, err := json.Marshal(list)
751 if err != nil {
752 return err
753 }
754
755 converted, err := runtime.Decode(unstructured.UnstructuredJSONScheme, listData)
756 if err != nil {
757 return err
758 }
759
760 obj = converted
761 } else {
762 obj = infos[0].Object
763 }
764
765 isList := meta.IsListType(obj)
766 if isList {
767 items, err := meta.ExtractList(obj)
768 if err != nil {
769 return err
770 }
771
772
773 list := &unstructured.UnstructuredList{
774 Object: map[string]interface{}{
775 "kind": "List",
776 "apiVersion": "v1",
777 "metadata": map[string]interface{}{},
778 },
779 }
780 if listMeta, err := meta.ListAccessor(obj); err == nil {
781 list.Object["metadata"] = map[string]interface{}{
782 "resourceVersion": listMeta.GetResourceVersion(),
783 }
784 }
785
786 for _, item := range items {
787 list.Items = append(list.Items, *item.(*unstructured.Unstructured))
788 }
789 if err := printer.PrintObj(list, o.Out); err != nil {
790 errs = append(errs, err)
791 }
792 return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs)))
793 }
794
795 if printErr := printer.PrintObj(obj, o.Out); printErr != nil {
796 errs = append(errs, printErr)
797 }
798
799 return utilerrors.Reduce(utilerrors.Flatten(utilerrors.NewAggregate(errs)))
800 }
801
802 func addServerPrintColumnFlags(cmd *cobra.Command, opt *GetOptions) {
803 cmd.Flags().BoolVar(&opt.ServerPrint, useServerPrintColumns, opt.ServerPrint, "If true, have the server return the appropriate table output. Supports extension APIs and CRDs.")
804 }
805
806 func shouldGetNewPrinterForMapping(printer printers.ResourcePrinter, lastMapping, mapping *meta.RESTMapping) bool {
807 return printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource
808 }
809
810 func multipleGVKsRequested(infos []*resource.Info) bool {
811 if len(infos) < 2 {
812 return false
813 }
814 gvk := infos[0].Mapping.GroupVersionKind
815 for _, info := range infos {
816 if info.Mapping.GroupVersionKind != gvk {
817 return true
818 }
819 }
820 return false
821 }
822
View as plain text