@@ -17,124 +17,157 @@ import (
17
17
18
18
// cache is our cache of schema information.
19
19
type cache struct {
20
- mutex sync.Mutex
21
- groups map [string ]metav1.APIGroup
22
- groupVersions map [schema.GroupVersion ]* cachedGroupVersion
20
+ mutex sync.Mutex
21
+ cachedAllGroups map [string ]metav1.APIGroup
22
+ cachedGroupVersions map [schema.GroupVersion ]* cachedGroupVersion
23
23
}
24
24
25
25
// newCache is the constructor for a cache.
26
26
func newCache () * cache {
27
27
return & cache {
28
- groupVersions : make (map [schema.GroupVersion ]* cachedGroupVersion ),
28
+ cachedGroupVersions : make (map [schema.GroupVersion ]* cachedGroupVersion ),
29
29
}
30
30
}
31
31
32
- // findGroupInfo returns the APIGroup for the specified group, querying discovery if not cached.
32
+ // fetchAllGroups returns the APIGroup for the specified group, querying discovery if not cached.
33
33
// If not found, returns APIGroup{}, false, nil
34
- func (c * cache ) findGroupInfo (ctx context.Context , discovery discovery.DiscoveryInterface , groupName string ) (metav1.APIGroup , bool , error ) {
34
+ func (c * cache ) fetchAllGroups (ctx context.Context , discovery discovery.DiscoveryInterface ) (map [ string ] metav1.APIGroup , error ) {
35
35
log := log .FromContext (ctx )
36
36
37
37
c .mutex .Lock ()
38
38
defer c .mutex .Unlock ()
39
39
40
- if c .groups == nil {
40
+ if c .cachedAllGroups == nil {
41
41
log .Info ("discovering server groups" )
42
42
serverGroups , err := discovery .ServerGroups ()
43
43
if err != nil {
44
44
klog .Infof ("unexpected error from ServerGroups: %v" , err )
45
- return metav1. APIGroup {}, false , fmt .Errorf ("error from ServerGroups: %w" , err )
45
+ return nil , fmt .Errorf ("error from ServerGroups: %w" , err )
46
46
}
47
47
48
48
groups := make (map [string ]metav1.APIGroup )
49
49
for i := range serverGroups .Groups {
50
50
group := & serverGroups .Groups [i ]
51
51
groups [group .Name ] = * group
52
52
}
53
- c .groups = groups
53
+ c .cachedAllGroups = groups
54
54
}
55
55
56
- group , found := c .groups [groupName ]
57
- return group , found , nil
56
+ return c .cachedAllGroups , nil
58
57
}
59
58
60
59
// cachedGroupVersion caches (all) the resource information for a particular groupversion.
61
60
type cachedGroupVersion struct {
62
- gv schema.GroupVersion
63
- mutex sync.Mutex
64
- kinds map [string ]cachedGVR
65
- // resource to kind
66
- toKind map [string ]string
61
+ gv schema.GroupVersion
62
+ mutex sync.Mutex
63
+ cachedServerResources map [string ]cachedResource
67
64
}
68
65
69
- // cachedGVR caches the information for a particular resource.
70
- type cachedGVR struct {
71
- Resource string
72
- Scope meta.RESTScope
66
+ // cachedResource caches the information for a particular resource.
67
+ type cachedResource struct {
68
+ resource string
69
+ scope meta.RESTScope
70
+ gvk schema.GroupVersionKind
73
71
}
74
72
75
- // KindFor finds out the Kind from the GVR in the cache. If the GVR version is not given, we will iterate all the matching
73
+ func (r * cachedResource ) GVR () schema.GroupVersionResource {
74
+ return r .gvk .GroupVersion ().WithResource (r .resource )
75
+ }
76
+
77
+ func (r * cachedResource ) GVK () schema.GroupVersionKind {
78
+ return r .gvk
79
+ }
80
+
81
+ func (r * cachedResource ) RESTMapping () * meta.RESTMapping {
82
+ return & meta.RESTMapping {
83
+ Resource : r .GVR (),
84
+ GroupVersionKind : r .GVK (),
85
+ Scope : r .scope ,
86
+ }
87
+ }
88
+
89
+ // KindsFor finds out the Kind from the GVR in the cache. If the GVR version is not given, we will iterate all the matching
76
90
// GR in the cache and return the first matching one.
77
- func (c * cache ) KindsFor (gvr schema.GroupVersionResource ) []string {
91
+ func (c * cache ) KindsFor (ctx context.Context , gvr schema.GroupVersionResource , discovery discovery.DiscoveryInterface ) ([]schema.GroupVersionKind , error ) {
92
+ var matches []schema.GroupVersionKind
78
93
if gvr .Version != "" {
79
- cachedgvr , ok := c .groupVersions [gvr .GroupVersion ()]
80
- if ! ok {
81
- return nil
94
+ gv := gvr .GroupVersion ()
95
+ cachedGV := c .cacheForGroupVersion (gv )
96
+
97
+ all , err := cachedGV .KindsFor (ctx , gvr , discovery )
98
+ if err != nil {
99
+ return nil , err
82
100
}
83
- return []string {cachedgvr .toKind [gvr .Resource ]}
101
+
102
+ matches = append (matches , all ... )
103
+
104
+ return matches , nil
84
105
}
85
- var kinds []string
86
106
87
- for keyGVR , cachedgvr := range c .groupVersions {
88
- if keyGVR .Group != gvr .Group {
107
+ allGroups , err := c .fetchAllGroups (ctx , discovery )
108
+ if err != nil {
109
+ return nil , err
110
+ }
111
+ for groupName , group := range allGroups {
112
+ if groupName != gvr .Group {
89
113
continue
90
114
}
91
- kind , ok := cachedgvr .toKind [gvr .Resource ]
92
- if ok && kind != "" {
93
- kinds = append (kinds , kind )
115
+ for _ , version := range group .Versions {
116
+ gv := schema.GroupVersion {Group : groupName , Version : version .Version }
117
+ cachedGV := c .cacheForGroupVersion (gv )
118
+
119
+ all , err := cachedGV .KindsFor (ctx , gvr , discovery )
120
+ if err != nil {
121
+ return nil , err
122
+ }
123
+
124
+ matches = append (matches , all ... )
94
125
}
95
126
}
96
- return kinds
127
+ return matches , nil
97
128
}
98
129
99
- // findRESTMapping returns the RESTMapping for the specified GVK, querying discovery if not cached.
100
- func (c * cache ) findRESTMapping (ctx context.Context , discovery discovery.DiscoveryInterface , gv schema.GroupVersion , kind string ) (* meta.RESTMapping , error ) {
130
+ func (c * cache ) cacheForGroupVersion (gv schema.GroupVersion ) * cachedGroupVersion {
101
131
c .mutex .Lock ()
102
- cached := c .groupVersions [gv ]
132
+ cached := c .cachedGroupVersions [gv ]
103
133
if cached == nil {
104
- cached = & cachedGroupVersion {gv : gv , toKind : make ( map [ string ] string ) }
105
- c .groupVersions [gv ] = cached
134
+ cached = & cachedGroupVersion {gv : gv }
135
+ c .cachedGroupVersions [gv ] = cached
106
136
}
107
137
c .mutex .Unlock ()
108
- return cached .findRESTMapping (ctx , discovery , kind )
138
+ return cached
139
+ }
140
+
141
+ // findRESTMapping returns the RESTMapping for the specified GVK, querying discovery if not cached.
142
+ func (c * cache ) findRESTMapping (ctx context.Context , discovery discovery.DiscoveryInterface , gv schema.GroupVersion , kind string ) (* meta.RESTMapping , error ) {
143
+ cachedGV := c .cacheForGroupVersion (gv )
144
+ return cachedGV .findRESTMapping (ctx , discovery , kind )
109
145
}
110
146
111
147
// findRESTMapping returns the RESTMapping for the specified GVK, querying discovery if not cached.
112
148
func (c * cachedGroupVersion ) findRESTMapping (ctx context.Context , discovery discovery.DiscoveryInterface , kind string ) (* meta.RESTMapping , error ) {
113
- kinds , err := c .fetch (ctx , discovery )
149
+ resources , err := c .fetchServerResources (ctx , discovery )
114
150
if err != nil {
115
151
return nil , err
116
152
}
117
153
118
- cached , found := kinds [kind ]
119
- if ! found {
120
- return nil , nil
154
+ for _ , resource := range resources {
155
+ if resource .GVK ().Kind == kind {
156
+ return resource .RESTMapping (), nil
157
+ }
121
158
}
122
- return & meta.RESTMapping {
123
- Resource : c .gv .WithResource (cached .Resource ),
124
- GroupVersionKind : c .gv .WithKind (kind ),
125
- Scope : cached .Scope ,
126
- }, nil
159
+ return nil , nil
127
160
}
128
161
129
162
// fetch returns the metadata, fetching it if not cached.
130
- func (c * cachedGroupVersion ) fetch (ctx context.Context , discovery discovery.DiscoveryInterface ) (map [string ]cachedGVR , error ) {
163
+ func (c * cachedGroupVersion ) fetchServerResources (ctx context.Context , discovery discovery.DiscoveryInterface ) (map [string ]cachedResource , error ) {
131
164
log := log .FromContext (ctx )
132
165
133
166
c .mutex .Lock ()
134
167
defer c .mutex .Unlock ()
135
168
136
- if c .kinds != nil {
137
- return c .kinds , nil
169
+ if c .cachedServerResources != nil {
170
+ return c .cachedServerResources , nil
138
171
}
139
172
140
173
log .Info ("discovering server resources for group/version" , "gv" , c .gv .String ())
@@ -149,7 +182,7 @@ func (c *cachedGroupVersion) fetch(ctx context.Context, discovery discovery.Disc
149
182
}
150
183
}
151
184
152
- kinds := make (map [string ]cachedGVR )
185
+ result := make (map [string ]cachedResource )
153
186
for i := range resourceList .APIResources {
154
187
resource := resourceList .APIResources [i ]
155
188
@@ -162,12 +195,36 @@ func (c *cachedGroupVersion) fetch(ctx context.Context, discovery discovery.Disc
162
195
if resource .Namespaced {
163
196
scope = meta .RESTScopeNamespace
164
197
}
165
- kinds [resource .Kind ] = cachedGVR {
166
- Resource : resource .Name ,
167
- Scope : scope ,
198
+ result [resource .Name ] = cachedResource {
199
+ resource : resource .Name ,
200
+ scope : scope ,
201
+ gvk : c .gv .WithKind (resource .Kind ),
168
202
}
169
- c .toKind [resource .Name ] = resource .Kind
170
203
}
171
- c .kinds = kinds
172
- return kinds , nil
204
+ c .cachedServerResources = result
205
+ return result , nil
206
+ }
207
+
208
+ func (c * cachedGroupVersion ) KindsFor (ctx context.Context , filterGVR schema.GroupVersionResource , discovery discovery.DiscoveryInterface ) ([]schema.GroupVersionKind , error ) {
209
+ serverResources , err := c .fetchServerResources (ctx , discovery )
210
+ if err != nil {
211
+ return nil , err
212
+ }
213
+ var matches []schema.GroupVersionKind
214
+ for _ , resource := range serverResources {
215
+ resourceGVR := resource .GVR ()
216
+
217
+ if resourceGVR .Group != filterGVR .Group {
218
+ continue
219
+ }
220
+ if filterGVR .Version != "" && resourceGVR .Version != filterGVR .Version {
221
+ continue
222
+ }
223
+ if filterGVR .Resource != "" && resourceGVR .Resource != filterGVR .Resource {
224
+ continue
225
+ }
226
+ matches = append (matches , resource .GVK ())
227
+ }
228
+
229
+ return matches , nil
173
230
}
0 commit comments