@@ -29,6 +29,7 @@ import (
29
29
corev1 "k8s.io/api/core/v1"
30
30
kapierrors "k8s.io/apimachinery/pkg/api/errors"
31
31
"k8s.io/apimachinery/pkg/api/meta"
32
+ metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion"
32
33
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33
34
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
34
35
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
@@ -204,11 +205,11 @@ func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
204
205
o .ExplicitNamespace = false
205
206
}
206
207
207
- isSorting , err := cmd .Flags ().GetString ("sort-by" )
208
+ sortBy , err := cmd .Flags ().GetString ("sort-by" )
208
209
if err != nil {
209
210
return err
210
211
}
211
- o .Sort = len (isSorting ) > 0
212
+ o .Sort = len (sortBy ) > 0
212
213
213
214
o .NoHeaders = cmdutil .GetFlagBool (cmd , "no-headers" )
214
215
@@ -253,12 +254,20 @@ func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
253
254
return nil , err
254
255
}
255
256
256
- printer = maybeWrapSortingPrinter (printer , isSorting )
257
+ if o .Sort {
258
+ printer = & SortingPrinter {Delegate : printer , SortField : sortBy }
259
+ }
260
+ if o .ServerPrint {
261
+ printer = & TablePrinter {Delegate : printer }
262
+ }
257
263
return printer .PrintObj , nil
258
264
}
259
265
260
266
switch {
261
267
case o .Watch || o .WatchOnly :
268
+ if o .Sort {
269
+ fmt .Fprintf (o .IOStreams .ErrOut , "warning: --watch or --watch-only requested, --sort-by will be ignored\n " )
270
+ }
262
271
default :
263
272
if len (args ) == 0 && cmdutil .IsFilenameSliceEmpty (o .Filenames , o .Kustomize ) {
264
273
fmt .Fprintf (o .ErrOut , "You must specify the type of resource to get. %s\n \n " , cmdutil .SuggestAPIResources (o .CmdParent ))
@@ -271,6 +280,12 @@ func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
271
280
return cmdutil .UsageErrorf (cmd , usageString )
272
281
}
273
282
}
283
+
284
+ // openapi printing is mutually exclusive with server side printing
285
+ if o .PrintWithOpenAPICols && o .ServerPrint {
286
+ fmt .Fprintf (o .IOStreams .ErrOut , "warning: --%s requested, --%s will be ignored\n " , useOpenAPIPrintColumnFlagLabel , useServerPrintColumns )
287
+ }
288
+
274
289
return nil
275
290
}
276
291
@@ -398,6 +413,27 @@ func NewRuntimeSorter(objects []runtime.Object, sortBy string) *RuntimeSorter {
398
413
}
399
414
}
400
415
416
+ func (o * GetOptions ) transformRequests (req * rest.Request ) {
417
+ // We need full objects if printing with openapi columns
418
+ if o .PrintWithOpenAPICols {
419
+ return
420
+ }
421
+ if ! o .ServerPrint || ! o .IsHumanReadablePrinter {
422
+ return
423
+ }
424
+
425
+ group := metav1beta1 .GroupName
426
+ version := metav1beta1 .SchemeGroupVersion .Version
427
+
428
+ tableParam := fmt .Sprintf ("application/json;as=Table;v=%s;g=%s, application/json" , version , group )
429
+ req .SetHeader ("Accept" , tableParam )
430
+
431
+ // if sorting, ensure we receive the full object in order to introspect its fields via jsonpath
432
+ if o .Sort {
433
+ req .Param ("includeObject" , "Object" )
434
+ }
435
+ }
436
+
401
437
// Run performs the get operation.
402
438
// TODO: remove the need to pass these arguments, like other commands.
403
439
func (o * GetOptions ) Run (f cmdutil.Factory , cmd * cobra.Command , args []string ) error {
@@ -408,11 +444,6 @@ func (o *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) e
408
444
return o .watch (f , cmd , args )
409
445
}
410
446
411
- // openapi printing is mutually exclusive with server side printing
412
- if o .PrintWithOpenAPICols && o .ServerPrint {
413
- fmt .Fprintf (o .IOStreams .ErrOut , "warning: --%s requested, --%s will be ignored\n " , useOpenAPIPrintColumnFlagLabel , useServerPrintColumns )
414
- }
415
-
416
447
chunkSize := o .ChunkSize
417
448
if o .Sort {
418
449
// TODO(juanvallejo): in the future, we could have the client use chunking
@@ -432,26 +463,7 @@ func (o *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) e
432
463
ContinueOnError ().
433
464
Latest ().
434
465
Flatten ().
435
- TransformRequests (func (req * rest.Request ) {
436
- // We need full objects if printing with openapi columns
437
- if o .PrintWithOpenAPICols {
438
- return
439
- }
440
- if ! o .ServerPrint || ! o .IsHumanReadablePrinter {
441
- return
442
- }
443
-
444
- group := metav1beta1 .GroupName
445
- version := metav1beta1 .SchemeGroupVersion .Version
446
-
447
- tableParam := fmt .Sprintf ("application/json;as=Table;v=%s;g=%s, application/json" , version , group )
448
- req .SetHeader ("Accept" , tableParam )
449
-
450
- // if sorting, ensure we receive the full object in order to introspect its fields via jsonpath
451
- if o .Sort {
452
- req .Param ("includeObject" , "Object" )
453
- }
454
- }).
466
+ TransformRequests (o .transformRequests ).
455
467
Do ()
456
468
457
469
if o .IgnoreNotFound {
@@ -475,17 +487,6 @@ func (o *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) e
475
487
476
488
objs := make ([]runtime.Object , len (infos ))
477
489
for ix := range infos {
478
- if o .ServerPrint {
479
- table , err := o .decodeIntoTable (infos [ix ].Object )
480
- if err == nil {
481
- infos [ix ].Object = table
482
- } else {
483
- // if we are unable to decode server response into a v1beta1.Table,
484
- // fallback to client-side printing with whatever info the server returned.
485
- klog .V (2 ).Infof ("Unable to decode server response into a Table. Falling back to hardcoded types: %v" , err )
486
- }
487
- }
488
-
489
490
objs [ix ] = infos [ix ].Object
490
491
}
491
492
@@ -505,8 +506,11 @@ func (o *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) e
505
506
506
507
var printer printers.ResourcePrinter
507
508
var lastMapping * meta.RESTMapping
508
- nonEmptyObjCount := 0
509
- w := utilprinters .GetNewTabWriter (o .Out )
509
+
510
+ // track if we write any output
511
+ trackingWriter := & trackingWriterWrapper {Delegate : o .Out }
512
+
513
+ w := utilprinters .GetNewTabWriter (trackingWriter )
510
514
for ix := range objs {
511
515
var mapping * meta.RESTMapping
512
516
var info * resource.Info
@@ -518,16 +522,6 @@ func (o *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) e
518
522
mapping = info .Mapping
519
523
}
520
524
521
- // if dealing with a table that has no rows, skip remaining steps
522
- // and avoid printing an unnecessary newline
523
- if table , isTable := info .Object .(* metav1beta1.Table ); isTable {
524
- if len (table .Rows ) == 0 {
525
- continue
526
- }
527
- }
528
-
529
- nonEmptyObjCount ++
530
-
531
525
printWithNamespace := o .AllNamespaces
532
526
533
527
if mapping != nil && mapping .Scope .Name () == meta .RESTScopeNameRoot {
@@ -574,12 +568,23 @@ func (o *GetOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) e
574
568
}
575
569
}
576
570
w .Flush ()
577
- if nonEmptyObjCount == 0 && ! o .IgnoreNotFound && len (allErrs ) == 0 {
571
+ if trackingWriter .Written == 0 && ! o .IgnoreNotFound && len (allErrs ) == 0 {
572
+ // if we wrote no output, and had no errors, and are not ignoring NotFound, be sure we output something
578
573
fmt .Fprintln (o .ErrOut , "No resources found." )
579
574
}
580
575
return utilerrors .NewAggregate (allErrs )
581
576
}
582
577
578
+ type trackingWriterWrapper struct {
579
+ Delegate io.Writer
580
+ Written int
581
+ }
582
+
583
+ func (t * trackingWriterWrapper ) Write (p []byte ) (n int , err error ) {
584
+ t .Written += len (p )
585
+ return t .Delegate .Write (p )
586
+ }
587
+
583
588
// raw makes a simple HTTP request to the provided path on the server using the default
584
589
// credentials.
585
590
func (o * GetOptions ) raw (f cmdutil.Factory ) error {
@@ -615,6 +620,7 @@ func (o *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []string)
615
620
ResourceTypeOrNameArgs (true , args ... ).
616
621
SingleResourceType ().
617
622
Latest ().
623
+ TransformRequests (o .transformRequests ).
618
624
Do ()
619
625
if err := r .Err (); err != nil {
620
626
return err
@@ -655,6 +661,8 @@ func (o *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []string)
655
661
656
662
writer := utilprinters .GetNewTabWriter (o .Out )
657
663
664
+ tableGK := metainternal .SchemeGroupVersion .WithKind ("Table" ).GroupKind ()
665
+
658
666
// print the current object
659
667
if ! o .WatchOnly {
660
668
var objsToPrint []runtime.Object
@@ -665,8 +673,8 @@ func (o *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []string)
665
673
objsToPrint = append (objsToPrint , obj )
666
674
}
667
675
for _ , objToPrint := range objsToPrint {
668
- if o .IsHumanReadablePrinter {
669
- // printing always takes the internal version, but the watch event uses externals
676
+ if o .IsHumanReadablePrinter && objToPrint . GetObjectKind (). GroupVersionKind (). GroupKind () != tableGK {
677
+ // printing anything other than tables always takes the internal version, but the watch event uses externals
670
678
internalGV := mapping .GroupVersionKind .GroupKind ().WithVersion (runtime .APIVersionInternal ).GroupVersion ()
671
679
objToPrint = attemptToConvertToInternal (objToPrint , legacyscheme .Scheme , internalGV )
672
680
}
@@ -698,7 +706,7 @@ func (o *GetOptions) watch(f cmdutil.Factory, cmd *cobra.Command, args []string)
698
706
// printing always takes the internal version, but the watch event uses externals
699
707
// TODO fix printing to use server-side or be version agnostic
700
708
objToPrint := e .Object
701
- if o .IsHumanReadablePrinter {
709
+ if o .IsHumanReadablePrinter && objToPrint . GetObjectKind (). GroupVersionKind (). GroupKind () != tableGK {
702
710
internalGV := mapping .GroupVersionKind .GroupKind ().WithVersion (runtime .APIVersionInternal ).GroupVersion ()
703
711
objToPrint = attemptToConvertToInternal (e .Object , legacyscheme .Scheme , internalGV )
704
712
}
@@ -723,35 +731,6 @@ func attemptToConvertToInternal(obj runtime.Object, converter runtime.ObjectConv
723
731
return internalObject
724
732
}
725
733
726
- func (o * GetOptions ) decodeIntoTable (obj runtime.Object ) (runtime.Object , error ) {
727
- if obj .GetObjectKind ().GroupVersionKind ().Kind != "Table" {
728
- return nil , fmt .Errorf ("attempt to decode non-Table object into a v1beta1.Table" )
729
- }
730
-
731
- unstr , ok := obj .(* unstructured.Unstructured )
732
- if ! ok {
733
- return nil , fmt .Errorf ("attempt to decode non-Unstructured object" )
734
- }
735
- table := & metav1beta1.Table {}
736
- if err := runtime .DefaultUnstructuredConverter .FromUnstructured (unstr .Object , table ); err != nil {
737
- return nil , err
738
- }
739
-
740
- for i := range table .Rows {
741
- row := & table .Rows [i ]
742
- if row .Object .Raw == nil || row .Object .Object != nil {
743
- continue
744
- }
745
- converted , err := runtime .Decode (unstructured .UnstructuredJSONScheme , row .Object .Raw )
746
- if err != nil {
747
- return nil , err
748
- }
749
- row .Object .Object = converted
750
- }
751
-
752
- return table , nil
753
- }
754
-
755
734
func (o * GetOptions ) printGeneric (r * resource.Result ) error {
756
735
// we flattened the data from the builder, so we have individual items, but now we'd like to either:
757
736
// 1. if there is more than one item, combine them all into a single list
@@ -863,16 +842,6 @@ func cmdSpecifiesOutputFmt(cmd *cobra.Command) bool {
863
842
return cmdutil .GetFlagString (cmd , "output" ) != ""
864
843
}
865
844
866
- func maybeWrapSortingPrinter (printer printers.ResourcePrinter , sortBy string ) printers.ResourcePrinter {
867
- if len (sortBy ) != 0 {
868
- return & SortingPrinter {
869
- Delegate : printer ,
870
- SortField : fmt .Sprintf ("%s" , sortBy ),
871
- }
872
- }
873
- return printer
874
- }
875
-
876
845
func multipleGVKsRequested (infos []* resource.Info ) bool {
877
846
if len (infos ) < 2 {
878
847
return false
0 commit comments