@@ -35,29 +35,31 @@ import (
3535 "k8s.io/client-go/metadata"
3636 "k8s.io/client-go/rest"
3737 "k8s.io/client-go/tools/cache"
38+ "sigs.k8s.io/controller-runtime/pkg/client"
3839 "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
3940 "sigs.k8s.io/controller-runtime/pkg/internal/syncs"
4041)
4142
4243// InformersOpts configures an InformerMap.
4344type InformersOpts struct {
44- HTTPClient * http.Client
45- Scheme * runtime.Scheme
46- Mapper meta.RESTMapper
47- ResyncPeriod time.Duration
48- Namespace string
49- NewInformer * func (cache.ListerWatcher , runtime.Object , time.Duration , cache.Indexers ) cache.SharedIndexInformer
50- Selector Selector
51- Transform cache.TransformFunc
52- UnsafeDisableDeepCopy bool
53- WatchErrorHandler cache.WatchErrorHandler
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+ AdditionalDefaultIndexes client.Indexers
52+ Selector Selector
53+ Transform cache.TransformFunc
54+ UnsafeDisableDeepCopy bool
55+ WatchErrorHandler cache.WatchErrorHandler
5456}
5557
5658// NewInformers creates a new InformersMap that can create informers under the hood.
5759func NewInformers (config * rest.Config , options * InformersOpts ) * Informers {
5860 newInformer := cache .NewSharedIndexInformer
5961 if options .NewInformer != nil {
60- newInformer = * options .NewInformer
62+ newInformer = options .NewInformer
6163 }
6264 return & Informers {
6365 config : config ,
@@ -69,16 +71,17 @@ func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
6971 Unstructured : make (map [schema.GroupVersionKind ]* Cache ),
7072 Metadata : make (map [schema.GroupVersionKind ]* Cache ),
7173 },
72- codecs : serializer .NewCodecFactory (options .Scheme ),
73- paramCodec : runtime .NewParameterCodec (options .Scheme ),
74- resync : options .ResyncPeriod ,
75- startWait : make (chan struct {}),
76- namespace : options .Namespace ,
77- selector : options .Selector ,
78- transform : options .Transform ,
79- unsafeDisableDeepCopy : options .UnsafeDisableDeepCopy ,
80- newInformer : newInformer ,
81- watchErrorHandler : options .WatchErrorHandler ,
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+ additionalDefaultIndexes : options .AdditionalDefaultIndexes ,
82+ unsafeDisableDeepCopy : options .UnsafeDisableDeepCopy ,
83+ newInformer : newInformer ,
84+ watchErrorHandler : options .WatchErrorHandler ,
8285 }
8386}
8487
@@ -170,9 +173,10 @@ type Informers struct {
170173 // default or empty string means all namespaces
171174 namespace string
172175
173- selector Selector
174- transform cache.TransformFunc
175- unsafeDisableDeepCopy bool
176+ selector Selector
177+ transform cache.TransformFunc
178+ additionalDefaultIndexes client.Indexers
179+ unsafeDisableDeepCopy bool
176180
177181 // NewInformer allows overriding of the shared index informer constructor for testing.
178182 newInformer func (cache.ListerWatcher , runtime.Object , time.Duration , cache.Indexers ) cache.SharedIndexInformer
@@ -346,6 +350,11 @@ func (ip *Informers) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.O
346350 if err != nil {
347351 return nil , false , err
348352 }
353+ indexers := make (cache.Indexers , len (ip .additionalDefaultIndexes )+ 1 )
354+ for k , fn := range ip .additionalDefaultIndexes {
355+ indexers [FieldIndexName (k )] = IndexFunc (fn )
356+ }
357+ indexers [cache .NamespaceIndex ] = cache .MetaNamespaceIndexFunc
349358 sharedIndexInformer := ip .newInformer (& cache.ListWatch {
350359 ListFunc : func (opts metav1.ListOptions ) (runtime.Object , error ) {
351360 ip .selector .ApplyToList (& opts )
@@ -356,9 +365,7 @@ func (ip *Informers) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.O
356365 opts .Watch = true // Watch needs to be set to true separately
357366 return listWatcher .WatchFunc (opts )
358367 },
359- }, obj , calculateResyncPeriod (ip .resync ), cache.Indexers {
360- cache .NamespaceIndex : cache .MetaNamespaceIndexFunc ,
361- })
368+ }, obj , calculateResyncPeriod (ip .resync ), indexers )
362369
363370 // Set WatchErrorHandler on SharedIndexInformer if set
364371 if ip .watchErrorHandler != nil {
@@ -585,3 +592,43 @@ func restrictNamespaceBySelector(namespaceOpt string, s Selector) string {
585592 }
586593 return ""
587594}
595+
596+ // IndexFunc constructs a low-level cache.IndexFunc from a client.IndexerFunc.
597+ // Returned keys in the former are namespaced and non-namespaced variants of the
598+ // latter.
599+ func IndexFunc (extractValue client.IndexerFunc ) cache.IndexFunc {
600+ return func (objRaw interface {}) ([]string , error ) {
601+ // TODO(directxman12): check if this is the correct type?
602+ obj , isObj := objRaw .(client.Object )
603+ if ! isObj {
604+ return nil , fmt .Errorf ("object of type %T is not an Object" , objRaw )
605+ }
606+ meta , err := meta .Accessor (obj )
607+ if err != nil {
608+ return nil , err
609+ }
610+ ns := meta .GetNamespace ()
611+
612+ rawVals := extractValue (obj )
613+ var vals []string
614+ if ns == "" {
615+ // if we're not doubling the keys for the namespaced case, just create a new slice with same length
616+ vals = make ([]string , len (rawVals ))
617+ } else {
618+ // if we need to add non-namespaced versions too, double the length
619+ vals = make ([]string , len (rawVals )* 2 )
620+ }
621+ for i , rawVal := range rawVals {
622+ // save a namespaced variant, so that we can ask
623+ // "what are all the object matching a given index *in a given namespace*"
624+ vals [i ] = KeyToNamespacedKey (ns , rawVal )
625+ if ns != "" {
626+ // if we have a namespace, also inject a special index key for listing
627+ // regardless of the object namespace
628+ vals [i + len (rawVals )] = KeyToNamespacedKey ("" , rawVal )
629+ }
630+ }
631+
632+ return vals , nil
633+ }
634+ }
0 commit comments