@@ -36,30 +36,32 @@ import (
3636 "k8s.io/client-go/metadata"
3737 "k8s.io/client-go/rest"
3838 "k8s.io/client-go/tools/cache"
39+ "sigs.k8s.io/controller-runtime/pkg/client"
3940 "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
4041 "sigs.k8s.io/controller-runtime/pkg/internal/syncs"
4142)
4243
4344// InformersOpts configures an InformerMap.
4445type 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
5658}
5759
5860// NewInformers creates a new InformersMap that can create informers under the hood.
5961func NewInformers (config * rest.Config , options * InformersOpts ) * Informers {
6062 newInformer := cache .NewSharedIndexInformer
6163 if options .NewInformer != nil {
62- newInformer = * options .NewInformer
64+ newInformer = options .NewInformer
6365 }
6466 return & Informers {
6567 config : config ,
@@ -71,17 +73,18 @@ func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
7173 Unstructured : make (map [schema.GroupVersionKind ]* Cache ),
7274 Metadata : make (map [schema.GroupVersionKind ]* Cache ),
7375 },
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 ,
8588 }
8689}
8790
@@ -173,10 +176,11 @@ type Informers struct {
173176 // default or empty string means all namespaces
174177 namespace string
175178
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
180184
181185 // NewInformer allows overriding of the shared index informer constructor for testing.
182186 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
358362 if err != nil {
359363 return nil , false , err
360364 }
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
361372 sharedIndexInformer := ip .newInformer (& cache.ListWatch {
362373 ListFunc : func (opts metav1.ListOptions ) (runtime.Object , error ) {
363374 ip .selector .ApplyToList (& opts )
@@ -370,10 +381,7 @@ func (ip *Informers) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.O
370381 ip .selector .ApplyToList (& opts )
371382 return listWatcher .WatchFunc (opts )
372383 },
373- }, obj , calculateResyncPeriod (ip .resync ), cache.Indexers {
374- cache .NamespaceIndex : cache .MetaNamespaceIndexFunc ,
375- })
376-
384+ }, obj , calculateResyncPeriod (ip .resync ), indexers )
377385 // Set WatchErrorHandler on SharedIndexInformer if set
378386 if ip .watchErrorHandler != nil {
379387 if err := sharedIndexInformer .SetWatchErrorHandler (ip .watchErrorHandler ); err != nil {
@@ -608,3 +616,43 @@ func restrictNamespaceBySelector(namespaceOpt string, s Selector) string {
608616 }
609617 return ""
610618}
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