@@ -11,14 +11,14 @@ import (
11
11
"github.com/ktr0731/go-fuzzyfinder"
12
12
"github.com/spf13/cobra"
13
13
"k8s.io/apimachinery/pkg/api/meta"
14
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14
15
"k8s.io/apimachinery/pkg/runtime/schema"
15
16
"k8s.io/cli-runtime/pkg/genericclioptions"
16
17
"k8s.io/client-go/discovery"
17
18
openapiclient "k8s.io/client-go/openapi"
18
19
_ "k8s.io/client-go/plugin/pkg/client/auth"
19
20
"k8s.io/kube-openapi/pkg/util/proto"
20
21
cmdutil "k8s.io/kubectl/pkg/cmd/util"
21
- "k8s.io/kubectl/pkg/explain"
22
22
"k8s.io/kubectl/pkg/util/openapi"
23
23
)
24
24
@@ -135,44 +135,54 @@ func (o *Options) Complete(f cmdutil.Factory, args []string) error {
135
135
return nil
136
136
}
137
137
138
- var gotGVR schema.GroupVersionResource
139
- var idx int
140
- // Find the first valid resource name in the inputFieldPath.
141
- for i := 1 ; i <= len (o .inputFieldPath ); i ++ {
142
- gotGVR , err = GetGVR (o , o .inputFieldPath [:i ])
143
- if err != nil {
144
- continue
138
+ gvarMap , gvrs , err := o .discover ()
139
+ if err != nil {
140
+ return err
141
+ }
142
+
143
+ var gvar * groupVersionAPIResource
144
+ var resourceIdx int
145
+ for i := len (o .inputFieldPath ); i > 0 ; i -- {
146
+ var ok bool
147
+ gvar , ok = gvarMap [o .inputFieldPath [:i ]]
148
+ if ok {
149
+ resourceIdx = i
150
+ break
145
151
}
146
- idx = i
147
- break
148
152
}
149
153
// If the inputFieldPath does not contain a valid resource name,
150
- // inputFiledPath is treated as a regex directly.
151
- if gotGVR .Empty () {
152
- o .gvrs , err = o .listGVRs ()
153
- if err != nil {
154
- return err
155
- }
154
+ // inputFiledPath is treated as a regex.
155
+ if gvar == nil {
156
+ o .gvrs = gvrs
156
157
return nil
157
158
}
158
159
// Overwrite the regex if the inputFieldPath contains a valid resource name.
160
+ _ , ok := gvarMap [o .inputFieldPath [:resourceIdx ]]
161
+ if ! ok {
162
+ return fmt .Errorf ("no resource found for %s" , o .inputFieldPath )
163
+ }
159
164
var re string
160
- if strings .HasPrefix (o .inputFieldPath , gotGVR .Resource ) {
161
- // E.g., "nodes.*spec" -> ".*spec"
162
- re = strings .TrimPrefix (o .inputFieldPath , gotGVR . Resource )
163
- } else if strings .HasPrefix (o .inputFieldPath , singularResource ( gotGVR . Resource )) {
164
- // E.g., "node.*spec" -> ".*spec"
165
- re = strings .TrimPrefix (o .inputFieldPath , singularResource ( gotGVR . Resource ) )
165
+ if strings .HasPrefix (o .inputFieldPath , gvar .Resource ) {
166
+ re = strings . TrimPrefix ( o . inputFieldPath , gvar . Resource )
167
+ } else if strings .HasPrefix (o .inputFieldPath , gvar . Kind ) {
168
+ re = strings .TrimPrefix (o .inputFieldPath , gvar . Kind )
169
+ } else if strings . HasPrefix ( o . inputFieldPath , gvar . SingularName ) {
170
+ re = strings .TrimPrefix (o .inputFieldPath , gvar . SingularName )
166
171
} else {
167
- // E.g., "no.*spec" -> ".*spec"
168
- prefix := o .inputFieldPath [:idx ]
169
- re = strings .TrimPrefix (o .inputFieldPath , prefix )
172
+ for _ , shortName := range gvar .ShortNames {
173
+ if strings .HasPrefix (o .inputFieldPath , shortName ) {
174
+ re = strings .TrimPrefix (o .inputFieldPath , shortName )
175
+ }
176
+ }
177
+ }
178
+ if re == "" {
179
+ return fmt .Errorf ("cannot find resource name in %s" , o .inputFieldPath )
170
180
}
171
181
o .inputFieldPathRegex , err = regexp .Compile (re )
172
182
if err != nil {
173
183
return err
174
184
}
175
- o .gvrs = []schema.GroupVersionResource {gotGVR }
185
+ o .gvrs = []schema.GroupVersionResource {gvar . GroupVersionResource }
176
186
177
187
return nil
178
188
}
@@ -237,13 +247,6 @@ func (o *Options) Run() error {
237
247
return pathExplainers [paths [idx ]].explain (o .Out , paths [idx ])
238
248
}
239
249
240
- func singularResource (resource string ) string {
241
- if strings .HasSuffix (resource , "s" ) {
242
- return resource [:len (resource )- 1 ]
243
- }
244
- return resource
245
- }
246
-
247
250
func (o * Options ) listGVRs () ([]schema.GroupVersionResource , error ) {
248
251
lists , err := o .discovery .ServerPreferredResources ()
249
252
if err != nil {
@@ -287,21 +290,43 @@ func (o *Options) findGVR() (schema.GroupVersionResource, error) {
287
290
return gvrs [idx ], nil
288
291
}
289
292
290
- // TODO: Find a way to mock meta.RESTMapper to avoid defining it as a variable.
291
- var GetGVR = func ( o * Options , name string ) ( schema.GroupVersionResource , error ) {
292
- return o . getGVR ( name )
293
+ type groupVersionAPIResource struct {
294
+ schema.GroupVersionResource
295
+ metav1. APIResource
293
296
}
294
297
295
- func (o * Options ) getGVR (name string ) (schema.GroupVersionResource , error ) {
296
- var ret schema.GroupVersionResource
297
- var err error
298
- if len (o .apiVersion ) == 0 {
299
- ret , _ , err = explain .SplitAndParseResourceRequestWithMatchingPrefix (name , o .mapper )
300
- } else {
301
- ret , _ , err = explain .SplitAndParseResourceRequest (name , o .mapper )
302
- }
298
+ func (o * Options ) discover () (map [string ]* groupVersionAPIResource , []schema.GroupVersionResource , error ) {
299
+ lists , err := o .discovery .ServerPreferredResources ()
303
300
if err != nil {
304
- return schema.GroupVersionResource {}, fmt .Errorf ("get the group version resource by %s %s: %w" , o .apiVersion , name , err )
301
+ return nil , nil , err
302
+ }
303
+ var gvrs []schema.GroupVersionResource
304
+ m := make (map [string ]* groupVersionAPIResource )
305
+ for _ , list := range lists {
306
+ if len (list .APIResources ) == 0 {
307
+ continue
308
+ }
309
+ gv , err := schema .ParseGroupVersion (list .GroupVersion )
310
+ if err != nil {
311
+ continue
312
+ }
313
+ for _ , resource := range list .APIResources {
314
+ gvr := gv .WithResource (resource .Name )
315
+ gvrs = append (gvrs , gvr )
316
+ r := groupVersionAPIResource {
317
+ GroupVersionResource : gvr ,
318
+ APIResource : resource ,
319
+ }
320
+ m [resource .Name ] = & r
321
+ m [resource .Kind ] = & r
322
+ m [resource .SingularName ] = & r
323
+ for _ , shortName := range resource .ShortNames {
324
+ m [shortName ] = & r
325
+ }
326
+ }
305
327
}
306
- return ret , nil
328
+ sort .SliceStable (gvrs , func (i , j int ) bool {
329
+ return gvrs [i ].String () < gvrs [j ].String ()
330
+ })
331
+ return m , gvrs , nil
307
332
}
0 commit comments