Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7000e2c

Browse files
committed
add resource handling before printing
Resources are currently filtered (in order to prevent printing) at print time in their HumanReadablePrinter handlers. This design makes it not possible to filter objects when they are printed using any other printer, such as YAML, JSON, or the NamePrinter. This patch removes any filters previously added at the printer level for pods and adds a way to define resource-specific filters before they are sent to a printer handler. A woking filter handler for pods has also been implemented. Filters affect resources being printed through the HumanReadablePrinter, YAML, JSON, and `--template` printers.
1 parent 313ef63 commit 7000e2c

8 files changed

Lines changed: 244 additions & 83 deletions

File tree

pkg/kubectl/cmd/cmd_test.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -749,16 +749,25 @@ func Example_printPodHideTerminated() {
749749
}
750750
cmd := NewCmdRun(f, os.Stdin, os.Stdout, os.Stderr)
751751
podList := newAllPhasePodList()
752-
mapper, _ := f.Object()
753-
err := f.PrintObject(cmd, mapper, podList, os.Stdout)
754-
if err != nil {
755-
fmt.Printf("Unexpected error: %v", err)
752+
// filter pods
753+
filterFuncs := f.DefaultResourceFilterFunc()
754+
filterOpts := f.DefaultResourceFilterOptions(cmd, false)
755+
_, filteredPodList, errs := cmdutil.FilterResourceList(podList, filterFuncs, filterOpts)
756+
if errs != nil {
757+
fmt.Printf("Unexpected filter error: %v\n", errs)
758+
}
759+
for _, pod := range filteredPodList {
760+
mapper, _ := f.Object()
761+
err := f.PrintObject(cmd, mapper, pod, os.Stdout)
762+
if err != nil {
763+
fmt.Printf("Unexpected error: %v", err)
764+
}
756765
}
757766
// Output:
758767
// NAME READY STATUS RESTARTS AGE
759768
// test1 1/2 Pending 6 10y
760-
// test2 1/2 Running 6 10y
761-
// test5 1/2 Unknown 6 10y
769+
// test2 1/2 Running 6 10y
770+
// test5 1/2 Unknown 6 10y
762771
}
763772

764773
func Example_printPodShowAll() {

pkg/kubectl/cmd/get.go

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/renstrom/dedent"
2424
"github.com/spf13/cobra"
2525

26+
"github.com/golang/glog"
2627
"k8s.io/kubernetes/pkg/api/meta"
2728
"k8s.io/kubernetes/pkg/kubectl"
2829
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@@ -156,6 +157,8 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm
156157
showKind := cmdutil.GetFlagBool(cmd, "show-kind")
157158
mapper, typer := f.Object()
158159
printAll := false
160+
filterFuncs := f.DefaultResourceFilterFunc()
161+
filterOpts := f.DefaultResourceFilterOptions(cmd, allNamespaces)
159162

160163
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
161164
if err != nil {
@@ -239,11 +242,13 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm
239242
}
240243

241244
// print the current object
245+
filteredResourceCount := 0
242246
if !isWatchOnly {
243247
if err := printer.PrintObj(obj, out); err != nil {
244248
return fmt.Errorf("unable to output the provided object: %v", err)
245249
}
246-
printer.AfterPrint(errOut, mapping.Resource)
250+
filteredResourceCount++
251+
cmdutil.PrintFilterCount(filteredResourceCount, mapping.Resource, errOut, filterOpts)
247252
}
248253

249254
// print watched changes
@@ -253,6 +258,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm
253258
}
254259

255260
first := true
261+
filteredResourceCount = 0
256262
kubectl.WatchLoop(w, func(e watch.Event) error {
257263
if !isList && first {
258264
// drop the initial watch event in the single resource case
@@ -261,7 +267,8 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm
261267
}
262268
err := printer.PrintObj(e.Object, out)
263269
if err == nil {
264-
printer.AfterPrint(errOut, mapping.Resource)
270+
filteredResourceCount++
271+
cmdutil.PrintFilterCount(filteredResourceCount, mapping.Resource, errOut, filterOpts)
265272
}
266273
return err
267274
})
@@ -320,10 +327,36 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm
320327
return err
321328
}
322329

323-
if err := printer.PrintObj(obj, out); err != nil {
324-
allErrs = append(allErrs, err)
330+
isList := meta.IsListType(obj)
331+
if isList {
332+
filteredResourceCount, items, errs := cmdutil.FilterResourceList(obj, filterFuncs, filterOpts)
333+
if errs != nil {
334+
return errs
335+
}
336+
filteredObj, err := cmdutil.ObjectListToVersionedObject(items, version)
337+
if err != nil {
338+
return err
339+
}
340+
if err := printer.PrintObj(filteredObj, out); err != nil {
341+
allErrs = append(allErrs, err)
342+
}
343+
344+
cmdutil.PrintFilterCount(filteredResourceCount, res, errOut, filterOpts)
345+
return utilerrors.NewAggregate(allErrs)
325346
}
326-
printer.AfterPrint(errOut, res)
347+
348+
filteredResourceCount := 0
349+
if isFiltered, err := filterFuncs.Filter(obj, filterOpts); !isFiltered {
350+
if err != nil {
351+
glog.V(2).Infof("Unable to filter resource: %v", err)
352+
} else if err := printer.PrintObj(obj, out); err != nil {
353+
allErrs = append(allErrs, err)
354+
}
355+
} else if isFiltered {
356+
filteredResourceCount++
357+
}
358+
359+
cmdutil.PrintFilterCount(filteredResourceCount, res, errOut, filterOpts)
327360
return utilerrors.NewAggregate(allErrs)
328361
}
329362

@@ -372,8 +405,9 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm
372405
printer = nil
373406
var lastMapping *meta.RESTMapping
374407
w := kubectl.GetNewTabWriter(out)
408+
filteredResourceCount := 0
375409

376-
if mustPrintWithKinds(objs, infos, sorter, printAll) {
410+
if cmdutil.MustPrintWithKinds(objs, infos, sorter, printAll) {
377411
showKind = true
378412
}
379413

@@ -390,7 +424,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm
390424
if printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource {
391425
if printer != nil {
392426
w.Flush()
393-
printer.AfterPrint(errOut, lastMapping.Resource)
427+
cmdutil.PrintFilterCount(filteredResourceCount, lastMapping.Resource, errOut, filterOpts)
394428
}
395429
printer, err = f.PrinterForMapping(cmd, mapping, allNamespaces)
396430
if err != nil {
@@ -399,6 +433,16 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm
399433
}
400434
lastMapping = mapping
401435
}
436+
437+
// filter objects if filter has been defined for current object
438+
if isFiltered, err := filterFuncs.Filter(original, filterOpts); isFiltered {
439+
if err == nil {
440+
filteredResourceCount++
441+
continue
442+
}
443+
allErrs = append(allErrs, err)
444+
}
445+
402446
if resourcePrinter, found := printer.(*kubectl.HumanReadablePrinter); found {
403447
resourceName := resourcePrinter.GetResourceKind()
404448
if mapping != nil {
@@ -429,37 +473,8 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm
429473
}
430474
}
431475
w.Flush()
432-
if printer != nil {
433-
printer.AfterPrint(errOut, lastMapping.Resource)
476+
if printer != nil && lastMapping != nil {
477+
cmdutil.PrintFilterCount(filteredResourceCount, lastMapping.Resource, errOut, filterOpts)
434478
}
435479
return utilerrors.NewAggregate(allErrs)
436480
}
437-
438-
// mustPrintWithKinds determines if printer is dealing
439-
// with multiple resource kinds, in which case it will
440-
// return true, indicating resource kind will be
441-
// included as part of printer output
442-
func mustPrintWithKinds(objs []runtime.Object, infos []*resource.Info, sorter *kubectl.RuntimeSort, printAll bool) bool {
443-
var lastMap *meta.RESTMapping
444-
445-
if len(infos) == 1 && printAll {
446-
return true
447-
}
448-
449-
for ix := range objs {
450-
var mapping *meta.RESTMapping
451-
if sorter != nil {
452-
mapping = infos[sorter.OriginalPosition(ix)].Mapping
453-
} else {
454-
mapping = infos[ix].Mapping
455-
}
456-
457-
// display "kind" only if we have mixed resources
458-
if lastMap != nil && mapping.Resource != lastMap.Resource {
459-
return true
460-
}
461-
lastMap = mapping
462-
}
463-
464-
return false
465-
}

pkg/kubectl/cmd/util/factory.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,29 @@ func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
11791179
return clientConfig
11801180
}
11811181

1182+
func (f *Factory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions {
1183+
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
1184+
if err != nil {
1185+
columnLabel = []string{}
1186+
}
1187+
opts := &kubectl.PrintOptions{
1188+
NoHeaders: GetFlagBool(cmd, "no-headers"),
1189+
WithNamespace: withNamespace,
1190+
Wide: GetWideFlag(cmd),
1191+
ShowAll: GetFlagBool(cmd, "show-all"),
1192+
ShowLabels: GetFlagBool(cmd, "show-labels"),
1193+
AbsoluteTimestamps: isWatch(cmd),
1194+
ColumnLabels: columnLabel,
1195+
}
1196+
1197+
return opts
1198+
}
1199+
1200+
// DefaultResourceFilterFunc returns a collection of FilterFuncs suitable for filtering specific resource types.
1201+
func (f *Factory) DefaultResourceFilterFunc() kubectl.Filters {
1202+
return kubectl.NewResourceFilter()
1203+
}
1204+
11821205
// PrintObject prints an api object given command line flags to modify the output format
11831206
func (f *Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error {
11841207
gvks, _, err := api.Scheme.ObjectKinds(obj)

pkg/kubectl/cmd/util/helpers.go

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"strings"
2929
"time"
3030

31+
"k8s.io/kubernetes/pkg/api"
3132
kerrors "k8s.io/kubernetes/pkg/api/errors"
3233
"k8s.io/kubernetes/pkg/api/meta"
3334
"k8s.io/kubernetes/pkg/api/unversioned"
@@ -43,7 +44,7 @@ import (
4344
"k8s.io/kubernetes/pkg/util/sets"
4445
"k8s.io/kubernetes/pkg/util/strategicpatch"
4546

46-
"github.com/evanphx/json-patch"
47+
jsonpatch "github.com/evanphx/json-patch"
4748
"github.com/golang/glog"
4849
"github.com/spf13/cobra"
4950
)
@@ -59,7 +60,7 @@ type debugError interface {
5960

6061
// AddSourceToErr adds handleResourcePrefix and source string to error message.
6162
// verb is the string like "creating", "deleting" etc.
62-
// souce is the filename or URL to the template file(*.json or *.yaml), or stdin to use to handle the resource.
63+
// source is the filename or URL to the template file(*.json or *.yaml), or stdin to use to handle the resource.
6364
func AddSourceToErr(verb string, source string, err error) error {
6465
if source != "" {
6566
if statusError, ok := err.(kerrors.APIStatus); ok {
@@ -626,3 +627,78 @@ func MaybeConvertObject(obj runtime.Object, gv unversioned.GroupVersion, convert
626627
return converter.ConvertToVersion(obj, gv)
627628
}
628629
}
630+
631+
// MustPrintWithKinds determines if printer is dealing
632+
// with multiple resource kinds, in which case it will
633+
// return true, indicating resource kind will be
634+
// included as part of printer output
635+
func MustPrintWithKinds(objs []runtime.Object, infos []*resource.Info, sorter *kubectl.RuntimeSort, printAll bool) bool {
636+
var lastMap *meta.RESTMapping
637+
638+
if len(infos) == 1 && printAll {
639+
return true
640+
}
641+
642+
for ix := range objs {
643+
var mapping *meta.RESTMapping
644+
if sorter != nil {
645+
mapping = infos[sorter.OriginalPosition(ix)].Mapping
646+
} else {
647+
mapping = infos[ix].Mapping
648+
}
649+
650+
// display "kind" only if we have mixed resources
651+
if lastMap != nil && mapping.Resource != lastMap.Resource {
652+
return true
653+
}
654+
lastMap = mapping
655+
}
656+
657+
return false
658+
}
659+
660+
// FilterResourceList receives a list of runtime objects.
661+
// If any objects are filtered, that number is returned along with a modified list.
662+
func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterOpts *kubectl.PrintOptions) (int, []runtime.Object, error) {
663+
items, err := meta.ExtractList(obj)
664+
if err != nil {
665+
return 0, []runtime.Object{obj}, utilerrors.NewAggregate([]error{err})
666+
}
667+
if errs := runtime.DecodeList(items, api.Codecs.UniversalDecoder(), runtime.UnstructuredJSONScheme); len(errs) > 0 {
668+
return 0, []runtime.Object{obj}, utilerrors.NewAggregate(errs)
669+
}
670+
671+
filterCount := 0
672+
list := make([]runtime.Object, 0, len(items))
673+
for _, obj := range items {
674+
if isFiltered, err := filterFuncs.Filter(obj, filterOpts); !isFiltered {
675+
if err != nil {
676+
glog.V(2).Infof("Unable to filter resource: %v", err)
677+
continue
678+
}
679+
list = append(list, obj)
680+
} else if isFiltered {
681+
filterCount++
682+
}
683+
}
684+
return filterCount, list, nil
685+
}
686+
687+
func PrintFilterCount(hiddenObjNum int, resource string, out io.Writer, options *kubectl.PrintOptions) error {
688+
if !options.NoHeaders && !options.ShowAll && hiddenObjNum > 0 {
689+
_, err := fmt.Fprintf(out, " info: %d completed object(s) was(were) not shown in %s list. Pass --show-all to see all objects.\n\n", hiddenObjNum, resource)
690+
return err
691+
}
692+
return nil
693+
}
694+
695+
// ObjectListToVersionedObject receives a list of api objects and a group version
696+
// and squashes the list's items into a single versioned runtime.Object.
697+
func ObjectListToVersionedObject(objects []runtime.Object, version unversioned.GroupVersion) (runtime.Object, error) {
698+
objectList := &api.List{Items: objects}
699+
converted, err := resource.TryConvert(api.Scheme, objectList, version, registered.GroupOrDie(api.GroupName).GroupVersion)
700+
if err != nil {
701+
return nil, err
702+
}
703+
return converted, nil
704+
}

pkg/kubectl/resource/result.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ func AsVersionedObject(infos []*Info, forceList bool, version unversioned.GroupV
222222
object = objects[0]
223223
} else {
224224
object = &api.List{Items: objects}
225-
converted, err := tryConvert(api.Scheme, object, version, registered.GroupOrDie(api.GroupName).GroupVersion)
225+
converted, err := TryConvert(api.Scheme, object, version, registered.GroupOrDie(api.GroupName).GroupVersion)
226226
if err != nil {
227227
return nil, err
228228
}
@@ -263,7 +263,7 @@ func AsVersionedObjects(infos []*Info, version unversioned.GroupVersion, encoder
263263
}
264264
}
265265

266-
converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, version, info.Mapping.GroupVersionKind.GroupVersion())
266+
converted, err := TryConvert(info.Mapping.ObjectConvertor, info.Object, version, info.Mapping.GroupVersionKind.GroupVersion())
267267
if err != nil {
268268
return nil, err
269269
}
@@ -272,9 +272,9 @@ func AsVersionedObjects(infos []*Info, version unversioned.GroupVersion, encoder
272272
return objects, nil
273273
}
274274

275-
// tryConvert attempts to convert the given object to the provided versions in order. This function assumes
275+
// TryConvert attempts to convert the given object to the provided versions in order. This function assumes
276276
// the object is in internal version.
277-
func tryConvert(converter runtime.ObjectConvertor, object runtime.Object, versions ...unversioned.GroupVersion) (runtime.Object, error) {
277+
func TryConvert(converter runtime.ObjectConvertor, object runtime.Object, versions ...unversioned.GroupVersion) (runtime.Object, error) {
278278
var last error
279279
for _, version := range versions {
280280
if version.Empty() {

0 commit comments

Comments
 (0)