@@ -36,23 +36,25 @@ import (
36
36
"k8s.io/client-go/metadata"
37
37
"k8s.io/client-go/rest"
38
38
"k8s.io/client-go/tools/cache"
39
+ "sigs.k8s.io/controller-runtime/pkg/client"
39
40
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
40
41
"sigs.k8s.io/controller-runtime/pkg/internal/syncs"
41
42
)
42
43
43
44
// InformersOpts configures an InformerMap.
44
45
type InformersOpts struct {
45
- HTTPClient * http.Client
46
- Scheme * runtime.Scheme
47
- Mapper meta.RESTMapper
48
- ResyncPeriod time.Duration
49
- Namespace string
50
- NewInformer func (cache.ListerWatcher , runtime.Object , time.Duration , cache.Indexers ) cache.SharedIndexInformer
51
- Selector Selector
52
- Transform cache.TransformFunc
53
- UnsafeDisableDeepCopy bool
54
- EnableWatchBookmarks bool
55
- WatchErrorHandler cache.WatchErrorHandler
46
+ HTTPClient * http.Client
47
+ Scheme * runtime.Scheme
48
+ Mapper meta.RESTMapper
49
+ ResyncPeriod time.Duration
50
+ Namespace string
51
+ NewInformer func (cache.ListerWatcher , runtime.Object , time.Duration , cache.Indexers ) cache.SharedIndexInformer
52
+ AdditionalDefaultIndexes client.Indexers
53
+ Selector Selector
54
+ Transform cache.TransformFunc
55
+ UnsafeDisableDeepCopy bool
56
+ EnableWatchBookmarks bool
57
+ WatchErrorHandler cache.WatchErrorHandler
56
58
}
57
59
58
60
// NewInformers creates a new InformersMap that can create informers under the hood.
@@ -71,17 +73,18 @@ func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
71
73
Unstructured : make (map [schema.GroupVersionKind ]* Cache ),
72
74
Metadata : make (map [schema.GroupVersionKind ]* Cache ),
73
75
},
74
- codecs : serializer .NewCodecFactory (options .Scheme ),
75
- paramCodec : runtime .NewParameterCodec (options .Scheme ),
76
- resync : options .ResyncPeriod ,
77
- startWait : make (chan struct {}),
78
- namespace : options .Namespace ,
79
- selector : options .Selector ,
80
- transform : options .Transform ,
81
- unsafeDisableDeepCopy : options .UnsafeDisableDeepCopy ,
82
- enableWatchBookmarks : options .EnableWatchBookmarks ,
83
- newInformer : newInformer ,
84
- watchErrorHandler : options .WatchErrorHandler ,
76
+ codecs : serializer .NewCodecFactory (options .Scheme ),
77
+ paramCodec : runtime .NewParameterCodec (options .Scheme ),
78
+ resync : options .ResyncPeriod ,
79
+ startWait : make (chan struct {}),
80
+ namespace : options .Namespace ,
81
+ selector : options .Selector ,
82
+ transform : options .Transform ,
83
+ additionalDefaultIndexes : options .AdditionalDefaultIndexes ,
84
+ unsafeDisableDeepCopy : options .UnsafeDisableDeepCopy ,
85
+ enableWatchBookmarks : options .EnableWatchBookmarks ,
86
+ newInformer : newInformer ,
87
+ watchErrorHandler : options .WatchErrorHandler ,
85
88
}
86
89
}
87
90
@@ -173,10 +176,11 @@ type Informers struct {
173
176
// default or empty string means all namespaces
174
177
namespace string
175
178
176
- selector Selector
177
- transform cache.TransformFunc
178
- unsafeDisableDeepCopy bool
179
- enableWatchBookmarks bool
179
+ selector Selector
180
+ transform cache.TransformFunc
181
+ additionalDefaultIndexes client.Indexers
182
+ unsafeDisableDeepCopy bool
183
+ enableWatchBookmarks bool
180
184
181
185
// NewInformer allows overriding of the shared index informer constructor for testing.
182
186
newInformer func (cache.ListerWatcher , runtime.Object , time.Duration , cache.Indexers ) cache.SharedIndexInformer
@@ -358,6 +362,13 @@ func (ip *Informers) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.O
358
362
if err != nil {
359
363
return nil , false , err
360
364
}
365
+
366
+ indexers := make (cache.Indexers , len (ip .additionalDefaultIndexes )+ 1 )
367
+ for k , fn := range ip .additionalDefaultIndexes {
368
+ indexers [FieldIndexName (k )] = IndexFunc (fn )
369
+ }
370
+
371
+ indexers [cache .NamespaceIndex ] = cache .MetaNamespaceIndexFunc
361
372
sharedIndexInformer := ip .newInformer (& cache.ListWatch {
362
373
ListFunc : func (opts metav1.ListOptions ) (runtime.Object , error ) {
363
374
ip .selector .ApplyToList (& opts )
@@ -370,10 +381,7 @@ func (ip *Informers) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.O
370
381
ip .selector .ApplyToList (& opts )
371
382
return listWatcher .WatchFunc (opts )
372
383
},
373
- }, obj , calculateResyncPeriod (ip .resync ), cache.Indexers {
374
- cache .NamespaceIndex : cache .MetaNamespaceIndexFunc ,
375
- })
376
-
384
+ }, obj , calculateResyncPeriod (ip .resync ), indexers )
377
385
// Set WatchErrorHandler on SharedIndexInformer if set
378
386
if ip .watchErrorHandler != nil {
379
387
if err := sharedIndexInformer .SetWatchErrorHandler (ip .watchErrorHandler ); err != nil {
@@ -608,3 +616,43 @@ func restrictNamespaceBySelector(namespaceOpt string, s Selector) string {
608
616
}
609
617
return ""
610
618
}
619
+
620
+ // IndexFunc constructs a low-level cache.IndexFunc from a client.IndexerFunc.
621
+ // Returned keys in the former are namespaced and non-namespaced variants of the
622
+ // latter.
623
+ func IndexFunc (extractValue client.IndexerFunc ) cache.IndexFunc {
624
+ return func (objRaw interface {}) ([]string , error ) {
625
+ // TODO(directxman12): check if this is the correct type?
626
+ obj , isObj := objRaw .(client.Object )
627
+ if ! isObj {
628
+ return nil , fmt .Errorf ("object of type %T is not an Object" , objRaw )
629
+ }
630
+ meta , err := meta .Accessor (obj )
631
+ if err != nil {
632
+ return nil , err
633
+ }
634
+ ns := meta .GetNamespace ()
635
+
636
+ rawVals := extractValue (obj )
637
+ var vals []string
638
+ if ns == "" {
639
+ // if we're not doubling the keys for the namespaced case, just create a new slice with same length
640
+ vals = make ([]string , len (rawVals ))
641
+ } else {
642
+ // if we need to add non-namespaced versions too, double the length
643
+ vals = make ([]string , len (rawVals )* 2 )
644
+ }
645
+ for i , rawVal := range rawVals {
646
+ // save a namespaced variant, so that we can ask
647
+ // "what are all the object matching a given index *in a given namespace*"
648
+ vals [i ] = KeyToNamespacedKey (ns , rawVal )
649
+ if ns != "" {
650
+ // if we have a namespace, also inject a special index key for listing
651
+ // regardless of the object namespace
652
+ vals [i + len (rawVals )] = KeyToNamespacedKey ("" , rawVal )
653
+ }
654
+ }
655
+
656
+ return vals , nil
657
+ }
658
+ }
0 commit comments