@@ -19,14 +19,18 @@ package cache
19
19
import (
20
20
"context"
21
21
"fmt"
22
+ "reflect"
22
23
"time"
23
24
24
25
"k8s.io/apimachinery/pkg/api/meta"
26
+ "k8s.io/apimachinery/pkg/fields"
27
+ "k8s.io/apimachinery/pkg/labels"
25
28
"k8s.io/apimachinery/pkg/runtime"
26
29
"k8s.io/apimachinery/pkg/runtime/schema"
27
30
"k8s.io/client-go/kubernetes/scheme"
28
31
"k8s.io/client-go/rest"
29
32
toolscache "k8s.io/client-go/tools/cache"
33
+
30
34
"sigs.k8s.io/controller-runtime/pkg/cache/internal"
31
35
"sigs.k8s.io/controller-runtime/pkg/client"
32
36
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
@@ -150,49 +154,242 @@ func New(config *rest.Config, opts Options) (Cache, error) {
150
154
if err != nil {
151
155
return nil , err
152
156
}
153
- selectorsByGVK , err := convertToSelectorsByGVK (opts .SelectorsByObject , opts .DefaultSelector , opts .Scheme )
157
+ selectorsByGVK , err := convertToByGVK (opts .SelectorsByObject , opts .DefaultSelector , opts .Scheme )
154
158
if err != nil {
155
159
return nil , err
156
160
}
157
161
disableDeepCopyByGVK , err := convertToDisableDeepCopyByGVK (opts .UnsafeDisableDeepCopyByObject , opts .Scheme )
158
162
if err != nil {
159
163
return nil , err
160
164
}
161
- transformByGVK , err := convertToTransformByKindAndGVK (opts .TransformByObject , opts .DefaultTransform , opts .Scheme )
165
+ transformByGVK , err := convertToByGVK (opts .TransformByObject , opts .DefaultTransform , opts .Scheme )
162
166
if err != nil {
163
167
return nil , err
164
168
}
169
+ transformByObj := internal .TransformFuncByObjectFromMap (transformByGVK )
170
+
171
+ internalSelectorsByGVK := internal.SelectorsByGVK {}
172
+ for gvk , selector := range selectorsByGVK {
173
+ internalSelectorsByGVK [gvk ] = internal .Selector (selector )
174
+ }
165
175
166
- im := internal .NewInformersMap (config , opts .Scheme , opts .Mapper , * opts .Resync , opts .Namespace , selectorsByGVK , disableDeepCopyByGVK , transformByGVK )
176
+ im := internal .NewInformersMap (config , opts .Scheme , opts .Mapper , * opts .Resync , opts .Namespace , internalSelectorsByGVK , disableDeepCopyByGVK , transformByObj )
167
177
return & informerCache {InformersMap : im }, nil
168
178
}
169
179
170
- // BuilderWithOptions returns a Cache constructor that will build the a cache
180
+ // BuilderWithOptions returns a Cache constructor that will build a cache
171
181
// honoring the options argument, this is useful to specify options like
172
182
// SelectorsByObject
173
183
// WARNING: if SelectorsByObject is specified. filtered out resources are not
174
184
// returned.
175
185
// WARNING: if UnsafeDisableDeepCopy is enabled, you must DeepCopy any object
176
186
// returned from cache get/list before mutating it.
177
187
func BuilderWithOptions (options Options ) NewCacheFunc {
178
- return func (config * rest.Config , opts Options ) (Cache , error ) {
179
- if options .Scheme == nil {
180
- options .Scheme = opts .Scheme
188
+ return func (config * rest.Config , inherited Options ) (Cache , error ) {
189
+ var err error
190
+ inherited , err = defaultOpts (config , inherited )
191
+ if err != nil {
192
+ return nil , err
181
193
}
182
- if options .Mapper == nil {
183
- options .Mapper = opts .Mapper
194
+ options , err = defaultOpts (config , options )
195
+ if err != nil {
196
+ return nil , err
184
197
}
185
- if options .Resync == nil {
186
- options .Resync = opts .Resync
198
+ combined , err := options .inheritFrom (inherited )
199
+ if err != nil {
200
+ return nil , err
187
201
}
188
- if options .Namespace == "" {
189
- options .Namespace = opts .Namespace
202
+ return New (config , * combined )
203
+ }
204
+ }
205
+
206
+ func (options Options ) inheritFrom (inherited Options ) (* Options , error ) {
207
+ var (
208
+ combined Options
209
+ err error
210
+ )
211
+ combined .Scheme = combineScheme (inherited .Scheme , options .Scheme )
212
+ combined .Mapper = selectMapper (inherited .Mapper , options .Mapper )
213
+ combined .Resync = selectResync (inherited .Resync , options .Resync )
214
+ combined .Namespace = selectNamespace (inherited .Namespace , options .Namespace )
215
+ combined .SelectorsByObject , combined .DefaultSelector , err = combineSelectors (inherited , options , combined .Scheme )
216
+ if err != nil {
217
+ return nil , err
218
+ }
219
+ combined .UnsafeDisableDeepCopyByObject , err = combineUnsafeDeepCopy (inherited , options , combined .Scheme )
220
+ if err != nil {
221
+ return nil , err
222
+ }
223
+ combined .TransformByObject , combined .DefaultTransform , err = combineTransforms (inherited , options , combined .Scheme )
224
+ if err != nil {
225
+ return nil , err
226
+ }
227
+ return & combined , nil
228
+ }
229
+
230
+ func combineScheme (schemes ... * runtime.Scheme ) * runtime.Scheme {
231
+ var out * runtime.Scheme
232
+ for _ , sch := range schemes {
233
+ if sch == nil {
234
+ continue
190
235
}
191
- if opts .Resync == nil {
192
- opts .Resync = options .Resync
236
+ for gvk , t := range sch .AllKnownTypes () {
237
+ if out == nil {
238
+ out = runtime .NewScheme ()
239
+ }
240
+ out .AddKnownTypeWithName (gvk , reflect .New (t ).Interface ().(runtime.Object ))
193
241
}
242
+ }
243
+ return out
244
+ }
194
245
195
- return New (config , options )
246
+ func selectMapper (def , override meta.RESTMapper ) meta.RESTMapper {
247
+ if override != nil {
248
+ return override
249
+ }
250
+ return def
251
+ }
252
+
253
+ func selectResync (def , override * time.Duration ) * time.Duration {
254
+ if override != nil {
255
+ return override
256
+ }
257
+ return def
258
+ }
259
+
260
+ func selectNamespace (def , override string ) string {
261
+ if override != "" {
262
+ return override
263
+ }
264
+ return def
265
+ }
266
+
267
+ func combineSelectors (inherited , options Options , scheme * runtime.Scheme ) (SelectorsByObject , ObjectSelector , error ) {
268
+ // Selectors are combined via logical AND.
269
+ // - Combined label selector is a union of the selectors requirements from both sets of options.
270
+ // - Combined field selector uses fields.AndSelectors with the combined list of non-nil field selectors
271
+ // defined in both sets of options.
272
+ //
273
+ // There is a bunch of complexity here because we need to convert to SelectorsByGVK
274
+ // to be able to match keys between options and inherited and then convert back to SelectorsByObject
275
+ optionsSelectorsByGVK , err := convertToByGVK (options .SelectorsByObject , options .DefaultSelector , options .Scheme )
276
+ if err != nil {
277
+ return nil , ObjectSelector {}, err
278
+ }
279
+ inheritedSelectorsByGVK , err := convertToByGVK (inherited .SelectorsByObject , inherited .DefaultSelector , inherited .Scheme )
280
+ if err != nil {
281
+ return nil , ObjectSelector {}, err
282
+ }
283
+
284
+ for gvk , selector := range inheritedSelectorsByGVK {
285
+ optionsSelectorsByGVK [gvk ] = combineSelector (optionsSelectorsByGVK [gvk ], selector )
286
+ }
287
+ return convertToByObject (optionsSelectorsByGVK , scheme )
288
+ }
289
+
290
+ func combineSelector (selectors ... ObjectSelector ) ObjectSelector {
291
+ ls := make ([]labels.Selector , 0 , len (selectors ))
292
+ fs := make ([]fields.Selector , 0 , len (selectors ))
293
+ for _ , s := range selectors {
294
+ ls = append (ls , s .Label )
295
+ fs = append (fs , s .Field )
296
+ }
297
+ return ObjectSelector {
298
+ Label : combineLabelSelectors (ls ... ),
299
+ Field : combineFieldSelectors (fs ... ),
300
+ }
301
+ }
302
+
303
+ func combineLabelSelectors (ls ... labels.Selector ) labels.Selector {
304
+ var combined labels.Selector
305
+ for _ , l := range ls {
306
+ if l == nil {
307
+ continue
308
+ }
309
+ if combined == nil {
310
+ combined = labels .NewSelector ()
311
+ }
312
+ reqs , _ := l .Requirements ()
313
+ combined = combined .Add (reqs ... )
314
+ }
315
+ return combined
316
+ }
317
+
318
+ func combineFieldSelectors (fs ... fields.Selector ) fields.Selector {
319
+ nonNil := fs [:0 ]
320
+ for _ , f := range fs {
321
+ if f == nil {
322
+ continue
323
+ }
324
+ nonNil = append (nonNil , f )
325
+ }
326
+ if len (nonNil ) == 0 {
327
+ return nil
328
+ }
329
+ if len (nonNil ) == 1 {
330
+ return nonNil [0 ]
331
+ }
332
+ return fields .AndSelectors (nonNil ... )
333
+ }
334
+
335
+ func combineUnsafeDeepCopy (inherited , options Options , scheme * runtime.Scheme ) (DisableDeepCopyByObject , error ) {
336
+ // UnsafeDisableDeepCopyByObject is combined via precedence. Only if a value for a particular GVK is unset
337
+ // in options will a value from inherited be used.
338
+ optionsDisableDeepCopyByGVK , err := convertToDisableDeepCopyByGVK (options .UnsafeDisableDeepCopyByObject , options .Scheme )
339
+ if err != nil {
340
+ return nil , err
341
+ }
342
+ inheritedDisableDeepCopyByGVK , err := convertToDisableDeepCopyByGVK (inherited .UnsafeDisableDeepCopyByObject , inherited .Scheme )
343
+ if err != nil {
344
+ return nil , err
345
+ }
346
+
347
+ for gvk , inheritedDeepCopy := range inheritedDisableDeepCopyByGVK {
348
+ if _ , ok := optionsDisableDeepCopyByGVK [gvk ]; ! ok {
349
+ if optionsDisableDeepCopyByGVK == nil {
350
+ optionsDisableDeepCopyByGVK = map [schema.GroupVersionKind ]bool {}
351
+ }
352
+ optionsDisableDeepCopyByGVK [gvk ] = inheritedDeepCopy
353
+ }
354
+ }
355
+ return convertToDisableDeepCopyByObject (optionsDisableDeepCopyByGVK , scheme )
356
+ }
357
+
358
+ func combineTransforms (inherited , options Options , scheme * runtime.Scheme ) (TransformByObject , toolscache.TransformFunc , error ) {
359
+ // Transform functions are combined via chaining. If both inherited and options define a transform
360
+ // function, the transform function from inherited will be called first, and the transform function from
361
+ // options will be called second.
362
+ optionsTransformByGVK , err := convertToByGVK (options .TransformByObject , options .DefaultTransform , options .Scheme )
363
+ if err != nil {
364
+ return nil , nil , err
365
+ }
366
+ inheritedTransformByGVK , err := convertToByGVK (inherited .TransformByObject , inherited .DefaultTransform , inherited .Scheme )
367
+ if err != nil {
368
+ return nil , nil , err
369
+ }
370
+
371
+ for gvk , inheritedTransform := range inheritedTransformByGVK {
372
+ if optionsTransformByGVK == nil {
373
+ optionsTransformByGVK = map [schema.GroupVersionKind ]toolscache.TransformFunc {}
374
+ }
375
+ optionsTransformByGVK [gvk ] = combineTransform (inheritedTransform , optionsTransformByGVK [gvk ])
376
+ }
377
+ return convertToByObject (optionsTransformByGVK , scheme )
378
+ }
379
+
380
+ func combineTransform (inherited , current toolscache.TransformFunc ) toolscache.TransformFunc {
381
+ if inherited == nil {
382
+ return current
383
+ }
384
+ if current == nil {
385
+ return inherited
386
+ }
387
+ return func (in interface {}) (interface {}, error ) {
388
+ mid , err := inherited (in )
389
+ if err != nil {
390
+ return nil , err
391
+ }
392
+ return current (mid )
196
393
}
197
394
}
198
395
@@ -219,17 +416,40 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
219
416
return opts , nil
220
417
}
221
418
222
- func convertToSelectorsByGVK ( selectorsByObject SelectorsByObject , defaultSelector ObjectSelector , scheme * runtime.Scheme ) (internal. SelectorsByGVK , error ) {
223
- selectorsByGVK := internal. SelectorsByGVK {}
224
- for object , selector := range selectorsByObject {
419
+ func convertToByGVK [ T any ]( byObject map [client. Object ] T , def T , scheme * runtime.Scheme ) (map [schema. GroupVersionKind ] T , error ) {
420
+ byGVK := map [schema. GroupVersionKind ] T {}
421
+ for object , value := range byObject {
225
422
gvk , err := apiutil .GVKForObject (object , scheme )
226
423
if err != nil {
227
424
return nil , err
228
425
}
229
- selectorsByGVK [gvk ] = internal .Selector (selector )
426
+ byGVK [gvk ] = value
427
+ }
428
+ byGVK [schema.GroupVersionKind {}] = def
429
+ return byGVK , nil
430
+ }
431
+
432
+ func convertToByObject [T any ](byGVK map [schema.GroupVersionKind ]T , scheme * runtime.Scheme ) (map [client.Object ]T , T , error ) {
433
+ var byObject map [client.Object ]T
434
+ def := byGVK [schema.GroupVersionKind {}]
435
+ for gvk , value := range byGVK {
436
+ if gvk == (schema.GroupVersionKind {}) {
437
+ continue
438
+ }
439
+ obj , err := scheme .New (gvk )
440
+ if err != nil {
441
+ return nil , def , err
442
+ }
443
+ cObj , ok := obj .(client.Object )
444
+ if ! ok {
445
+ return nil , def , fmt .Errorf ("object %T for GVK %q does not implement client.Object" , obj , gvk )
446
+ }
447
+ if byObject == nil {
448
+ byObject = map [client.Object ]T {}
449
+ }
450
+ byObject [cObj ] = value
230
451
}
231
- selectorsByGVK [schema.GroupVersionKind {}] = internal .Selector (defaultSelector )
232
- return selectorsByGVK , nil
452
+ return byObject , def , nil
233
453
}
234
454
235
455
// DisableDeepCopyByObject associate a client.Object's GVK to disable DeepCopy during get or list from cache.
@@ -259,17 +479,30 @@ func convertToDisableDeepCopyByGVK(disableDeepCopyByObject DisableDeepCopyByObje
259
479
return disableDeepCopyByGVK , nil
260
480
}
261
481
262
- // TransformByObject associate a client.Object's GVK to a transformer function
263
- // to be applied when storing the object into the cache.
264
- type TransformByObject map [client.Object ]toolscache.TransformFunc
265
-
266
- func convertToTransformByKindAndGVK (t TransformByObject , defaultTransform toolscache.TransformFunc , scheme * runtime.Scheme ) (internal.TransformFuncByObject , error ) {
267
- result := internal .NewTransformFuncByObject ()
268
- for obj , transformation := range t {
269
- if err := result .Set (obj , scheme , transformation ); err != nil {
482
+ func convertToDisableDeepCopyByObject (byGVK internal.DisableDeepCopyByGVK , scheme * runtime.Scheme ) (DisableDeepCopyByObject , error ) {
483
+ var byObject DisableDeepCopyByObject
484
+ for gvk , value := range byGVK {
485
+ if byObject == nil {
486
+ byObject = DisableDeepCopyByObject {}
487
+ }
488
+ if gvk == (schema.GroupVersionKind {}) {
489
+ byObject [ObjectAll {}] = value
490
+ continue
491
+ }
492
+ obj , err := scheme .New (gvk )
493
+ if err != nil {
270
494
return nil , err
271
495
}
496
+ cObj , ok := obj .(client.Object )
497
+ if ! ok {
498
+ return nil , fmt .Errorf ("object %T for GVK %q does not implement client.Object" , obj , gvk )
499
+ }
500
+
501
+ byObject [cObj ] = value
272
502
}
273
- result .SetDefault (defaultTransform )
274
- return result , nil
503
+ return byObject , nil
275
504
}
505
+
506
+ // TransformByObject associate a client.Object's GVK to a transformer function
507
+ // to be applied when storing the object into the cache.
508
+ type TransformByObject map [client.Object ]toolscache.TransformFunc
0 commit comments