@@ -33,6 +33,7 @@ import (
33
33
"k8s.io/apimachinery/pkg/runtime/schema"
34
34
utilerrors "k8s.io/apimachinery/pkg/util/errors"
35
35
"k8s.io/cli-runtime/pkg/genericclioptions"
36
+ discovery "k8s.io/client-go/discovery"
36
37
authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
37
38
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
38
39
describeutil "k8s.io/kubernetes/pkg/kubectl/describe/versioned"
@@ -44,11 +45,12 @@ import (
44
45
// CanIOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
45
46
// referencing the cmd.Flags()
46
47
type CanIOptions struct {
47
- AllNamespaces bool
48
- Quiet bool
49
- NoHeaders bool
50
- Namespace string
51
- AuthClient authorizationv1client.AuthorizationV1Interface
48
+ AllNamespaces bool
49
+ Quiet bool
50
+ NoHeaders bool
51
+ Namespace string
52
+ AuthClient authorizationv1client.AuthorizationV1Interface
53
+ DiscoveryClient discovery.DiscoveryInterface
52
54
53
55
Verb string
54
56
Resource schema.GroupVersionResource
@@ -169,6 +171,7 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
169
171
return err
170
172
}
171
173
o .AuthClient = client .AuthorizationV1 ()
174
+ o .DiscoveryClient = client .Discovery ()
172
175
o .Namespace = ""
173
176
if ! o .AllNamespaces {
174
177
o .Namespace , _ , err = f .ToRawKubeConfigLoader ().Namespace ()
@@ -196,6 +199,14 @@ func (o *CanIOptions) Validate() error {
196
199
if o .Resource != (schema.GroupVersionResource {}) || o .ResourceName != "" {
197
200
return fmt .Errorf ("NonResourceURL and ResourceName can not specified together" )
198
201
}
202
+ } else if ! o .Resource .Empty () && ! o .AllNamespaces && o .DiscoveryClient != nil {
203
+ if namespaced , err := isNamespaced (o .Resource , o .DiscoveryClient ); err == nil && ! namespaced {
204
+ if len (o .Resource .Group ) == 0 {
205
+ fmt .Fprintf (o .ErrOut , "Warning: resource '%s' is not namespace scoped\n " , o .Resource .Resource )
206
+ } else {
207
+ fmt .Fprintf (o .ErrOut , "Warning: resource '%s' is not namespace scoped in group '%s'\n " , o .Resource .Resource , o .Resource .Group )
208
+ }
209
+ }
199
210
}
200
211
201
212
if o .NoHeaders {
@@ -360,3 +371,23 @@ func printAccess(out io.Writer, rules []rbacv1.PolicyRule) error {
360
371
}
361
372
return nil
362
373
}
374
+
375
+ func isNamespaced (gvr schema.GroupVersionResource , discoveryClient discovery.DiscoveryInterface ) (bool , error ) {
376
+ if gvr .Resource == "*" {
377
+ return true , nil
378
+ }
379
+ apiResourceList , err := discoveryClient .ServerResourcesForGroupVersion (schema.GroupVersion {
380
+ Group : gvr .Group , Version : gvr .Version ,
381
+ }.String ())
382
+ if err != nil {
383
+ return true , err
384
+ }
385
+
386
+ for _ , resource := range apiResourceList .APIResources {
387
+ if resource .Name == gvr .Resource {
388
+ return resource .Namespaced , nil
389
+ }
390
+ }
391
+
392
+ return false , fmt .Errorf ("the server doesn't have a resource type '%s' in group '%s'" , gvr .Resource , gvr .Group )
393
+ }
0 commit comments