@@ -223,20 +223,17 @@ func (o *ResourceOptions) Complete(f kcmdutil.Factory, c *cobra.Command) error {
223223 return err
224224 }
225225
226+ // if o.Include has * we need to update it via discovery and o.DefaultExcludes and o.OverlappingResources
226227 resourceNames := sets .NewString ()
227228 for i , s := range o .Include {
228229 if resourceNames .Has (s ) {
229230 continue
230231 }
231232 if s != "*" {
232233 resourceNames .Insert (s )
233- break
234+ continue
234235 }
235236
236- all , err := FindAllCanonicalResources (discoveryClient , mapper )
237- if err != nil {
238- return fmt .Errorf ("could not calculate the list of available resources: %v" , err )
239- }
240237 exclude := sets .NewString ()
241238 for _ , gr := range o .DefaultExcludes {
242239 if len (o .OverlappingResources ) > 0 {
@@ -250,7 +247,16 @@ func (o *ResourceOptions) Complete(f kcmdutil.Factory, c *cobra.Command) error {
250247 }
251248 exclude .Insert (gr .String ())
252249 }
250+
253251 candidate := sets .NewString ()
252+
253+ // keep this logic as close to the point of use as possible so that we limit our dependency on discovery
254+ // since discovery is cached this does not repeatedly call out to the API
255+ all , err := FindAllCanonicalResources (discoveryClient , mapper )
256+ if err != nil {
257+ return fmt .Errorf ("could not calculate the list of available resources: %v" , err )
258+ }
259+
254260 for _ , gr := range all {
255261 // if the user specifies a resource that matches resource or resource+group, skip it
256262 if resourceNames .Has (gr .Resource ) || resourceNames .Has (gr .String ()) || exclude .Has (gr .String ()) {
@@ -719,18 +725,21 @@ func DefaultRetriable(info *resource.Info, err error) error {
719725 }
720726}
721727
722- // FindAllCanonicalResources returns all resource names that map directly to their kind (Kind -> Resource -> Kind)
723- // and are not subresources. This is the closest mapping possible from the client side to resources that can be
724- // listed and updated. Note that this may return some virtual resources (like imagestreamtags) that can be otherwise
725- // represented.
728+ // FindAllCanonicalResources returns all resources that:
729+ // 1. map directly to their kind (Kind -> Resource -> Kind)
730+ // 2. are not subresources
731+ // 3. can be listed and updated
732+ // Note that this may return some virtual resources (like imagestreamtags) that can be otherwise represented.
726733// TODO: add a field to APIResources for "virtual" (or that points to the canonical resource).
727- // TODO: fallback to the scheme when discovery is not possible.
728734func FindAllCanonicalResources (d discovery.ServerResourcesInterface , m meta.RESTMapper ) ([]schema.GroupResource , error ) {
729735 set := make (map [schema.GroupResource ]struct {})
736+
737+ // this call doesn't fail on aggregated apiserver failures
730738 all , err := d .ServerResources ()
731739 if err != nil {
732740 return nil , err
733741 }
742+
734743 for _ , serverResource := range all {
735744 gv , err := schema .ParseGroupVersion (serverResource .GroupVersion )
736745 if err != nil {
@@ -741,6 +750,10 @@ func FindAllCanonicalResources(d discovery.ServerResourcesInterface, m meta.REST
741750 if strings .Contains (r .Name , "/" ) {
742751 continue
743752 }
753+ // ignore resources that cannot be listed and updated
754+ if ! sets .NewString (r .Verbs ... ).HasAll ("list" , "update" ) {
755+ continue
756+ }
744757 // because discovery info doesn't tell us whether the object is virtual or not, perform a lookup
745758 // by the kind for resource (which should be the canonical resource) and then verify that the reverse
746759 // lookup (KindsFor) does not error.
@@ -751,6 +764,7 @@ func FindAllCanonicalResources(d discovery.ServerResourcesInterface, m meta.REST
751764 }
752765 }
753766 }
767+
754768 var groupResources []schema.GroupResource
755769 for k := range set {
756770 groupResources = append (groupResources , k )
0 commit comments