Skip to content

Commit bf4dd6f

Browse files
embikvincepristtts
committed
Add support for additional default indexers in cache
On-behalf-of: SAP [email protected] Co-authored-by: Vince Prignano <[email protected]> Co-authored-by: Dr. Stefan Schimanski <[email protected]> Signed-off-by: Marvin Beckers <[email protected]>
1 parent 853e799 commit bf4dd6f

File tree

4 files changed

+92
-72
lines changed

4 files changed

+92
-72
lines changed

pkg/cache/cache.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ type Options struct {
207207
// to reduce the caches memory usage.
208208
DefaultTransform toolscache.TransformFunc
209209

210+
// AdditionalDefaultIndexes are indexes that are added to every informer
211+
// beyond the namespace-name and namespace ones.
212+
AdditionalDefaultIndexes client.Indexers
213+
210214
// DefaultWatchErrorHandler will be used to the WatchErrorHandler which is called
211215
// whenever ListAndWatch drops the connection with an error.
212216
//
@@ -429,11 +433,12 @@ func newCache(restConfig *rest.Config, opts Options) newCacheFunc {
429433
Label: config.LabelSelector,
430434
Field: config.FieldSelector,
431435
},
432-
Transform: config.Transform,
433-
WatchErrorHandler: opts.DefaultWatchErrorHandler,
434-
UnsafeDisableDeepCopy: ptr.Deref(config.UnsafeDisableDeepCopy, false),
435-
EnableWatchBookmarks: ptr.Deref(config.EnableWatchBookmarks, true),
436-
NewInformer: opts.NewInformer,
436+
Transform: config.Transform,
437+
WatchErrorHandler: opts.DefaultWatchErrorHandler,
438+
UnsafeDisableDeepCopy: ptr.Deref(config.UnsafeDisableDeepCopy, false),
439+
EnableWatchBookmarks: ptr.Deref(config.EnableWatchBookmarks, true),
440+
NewInformer: opts.NewInformer,
441+
AdditionalDefaultIndexes: opts.AdditionalDefaultIndexes,
437442
}),
438443
readerFailOnMissingInformer: opts.ReaderFailOnMissingInformer,
439444
}

pkg/cache/informer_cache.go

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"fmt"
2222
"strings"
2323

24-
apimeta "k8s.io/apimachinery/pkg/api/meta"
2524
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2625
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2726
"k8s.io/apimachinery/pkg/runtime"
@@ -221,40 +220,5 @@ func (ic *informerCache) IndexField(ctx context.Context, obj client.Object, fiel
221220
}
222221

223222
func indexByField(informer Informer, field string, extractValue client.IndexerFunc) error {
224-
indexFunc := func(objRaw interface{}) ([]string, error) {
225-
// TODO(directxman12): check if this is the correct type?
226-
obj, isObj := objRaw.(client.Object)
227-
if !isObj {
228-
return nil, fmt.Errorf("object of type %T is not an Object", objRaw)
229-
}
230-
meta, err := apimeta.Accessor(obj)
231-
if err != nil {
232-
return nil, err
233-
}
234-
ns := meta.GetNamespace()
235-
236-
rawVals := extractValue(obj)
237-
var vals []string
238-
if ns == "" {
239-
// if we're not doubling the keys for the namespaced case, just create a new slice with same length
240-
vals = make([]string, len(rawVals))
241-
} else {
242-
// if we need to add non-namespaced versions too, double the length
243-
vals = make([]string, len(rawVals)*2)
244-
}
245-
for i, rawVal := range rawVals {
246-
// save a namespaced variant, so that we can ask
247-
// "what are all the object matching a given index *in a given namespace*"
248-
vals[i] = internal.KeyToNamespacedKey(ns, rawVal)
249-
if ns != "" {
250-
// if we have a namespace, also inject a special index key for listing
251-
// regardless of the object namespace
252-
vals[i+len(rawVals)] = internal.KeyToNamespacedKey("", rawVal)
253-
}
254-
}
255-
256-
return vals, nil
257-
}
258-
259-
return informer.AddIndexers(cache.Indexers{internal.FieldIndexName(field): indexFunc})
223+
return informer.AddIndexers(cache.Indexers{internal.FieldIndexName(field): internal.IndexFunc(extractValue)})
260224
}

pkg/cache/internal/informers.go

Lines changed: 78 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,25 @@ 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.
4445
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
5658
}
5759

5860
// NewInformers creates a new InformersMap that can create informers under the hood.
@@ -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+
}

pkg/client/interfaces.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ type WithWatch interface {
190190
// namespaced and non-spaced variants, so keys do not need to include namespace.
191191
type IndexerFunc func(Object) []string
192192

193+
// Indexers is a map of field name to IndexerFunc.
194+
type Indexers map[string]IndexerFunc
195+
193196
// FieldIndexer knows how to index over a particular "field" such that it
194197
// can later be used by a field selector.
195198
type FieldIndexer interface {

0 commit comments

Comments
 (0)