@@ -35,29 +35,31 @@ import (
35
35
"k8s.io/client-go/metadata"
36
36
"k8s.io/client-go/rest"
37
37
"k8s.io/client-go/tools/cache"
38
+ "sigs.k8s.io/controller-runtime/pkg/client"
38
39
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
39
40
"sigs.k8s.io/controller-runtime/pkg/internal/syncs"
40
41
)
41
42
42
43
// InformersOpts configures an InformerMap.
43
44
type 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
54
56
}
55
57
56
58
// NewInformers creates a new InformersMap that can create informers under the hood.
57
59
func NewInformers (config * rest.Config , options * InformersOpts ) * Informers {
58
60
newInformer := cache .NewSharedIndexInformer
59
61
if options .NewInformer != nil {
60
- newInformer = * options .NewInformer
62
+ newInformer = options .NewInformer
61
63
}
62
64
return & Informers {
63
65
config : config ,
@@ -69,16 +71,17 @@ func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
69
71
Unstructured : make (map [schema.GroupVersionKind ]* Cache ),
70
72
Metadata : make (map [schema.GroupVersionKind ]* Cache ),
71
73
},
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 ,
82
85
}
83
86
}
84
87
@@ -170,9 +173,10 @@ type Informers struct {
170
173
// default or empty string means all namespaces
171
174
namespace string
172
175
173
- selector Selector
174
- transform cache.TransformFunc
175
- unsafeDisableDeepCopy bool
176
+ selector Selector
177
+ transform cache.TransformFunc
178
+ additionalDefaultIndexes client.Indexers
179
+ unsafeDisableDeepCopy bool
176
180
177
181
// NewInformer allows overriding of the shared index informer constructor for testing.
178
182
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
346
350
if err != nil {
347
351
return nil , false , err
348
352
}
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
349
358
sharedIndexInformer := ip .newInformer (& cache.ListWatch {
350
359
ListFunc : func (opts metav1.ListOptions ) (runtime.Object , error ) {
351
360
ip .selector .ApplyToList (& opts )
@@ -356,9 +365,7 @@ func (ip *Informers) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.O
356
365
opts .Watch = true // Watch needs to be set to true separately
357
366
return listWatcher .WatchFunc (opts )
358
367
},
359
- }, obj , calculateResyncPeriod (ip .resync ), cache.Indexers {
360
- cache .NamespaceIndex : cache .MetaNamespaceIndexFunc ,
361
- })
368
+ }, obj , calculateResyncPeriod (ip .resync ), indexers )
362
369
363
370
// Set WatchErrorHandler on SharedIndexInformer if set
364
371
if ip .watchErrorHandler != nil {
@@ -585,3 +592,43 @@ func restrictNamespaceBySelector(namespaceOpt string, s Selector) string {
585
592
}
586
593
return ""
587
594
}
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