Skip to content

Commit 2d6828d

Browse files
authored
Merge pull request #1419 from qinqon/add-cache-filter-field-option
🌱 Add a design document to filter cache by selectors
2 parents 442d3ca + 141ddd6 commit 2d6828d

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

designs/use-selectors-at-cache.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
Filter cache ListWatch using selectors
2+
===================
3+
## Motivation
4+
5+
Controller-Runtime controllers use a cache to subscribe to events from
6+
Kubernetes objects and to read those objects more efficiently by avoiding
7+
to call out to the API. This cache is backed by Kubernetes informers.
8+
9+
The only way to filter this cache is by namespace and resource type.
10+
In cases where a controller is only interested in a small subset of objects
11+
(for example all pods on a node), this might end up not being efficient enough.
12+
13+
Requests to a client backed by a filtered cache for objects that do not match
14+
the filter will never return anything, so we need to make sure that we properly
15+
warn users to only use this when they are sure they know what they are doing.
16+
17+
This proposal sidesteps the issue of "How to we plug this into the cache-backed
18+
client so that users get feedback when they request something that is
19+
not matching the caches filter" by only implementing the filter logic in the
20+
cache package. This allows advanced users to combine a filtered cache with the
21+
already existing `NewCacheFunc` option in the manager and cluster package,
22+
while simultaneously hiding it from newer users that might not be aware of the
23+
implications and the associated foot-shoot potential.
24+
25+
The only alternative today to get a filtered cache with controller-runtime is
26+
to build it out-of tree. Because such a cache would mostly copy the existing
27+
cache and add just some options, this is not great for consumers.
28+
29+
This proposal is related to the following issue [2]
30+
31+
## Proposal
32+
33+
Add a new selector code at `pkg/cache/internal/selector.go` with common structs
34+
and helpers
35+
```golang
36+
package internal
37+
38+
...
39+
40+
// SelectorsByObject associate a runtime.Object to a field/label selector
41+
type SelectorsByObject map[client.Object]Selector
42+
43+
// SelectorsByGVK associate a GroupVersionResource to a field/label selector
44+
type SelectorsByGVK map[schema.GroupVersionKind]Selector
45+
46+
// Selector specify the label/field selector to fill in ListOptions
47+
type Selector struct {
48+
Label labels.Selector
49+
Field fields.Selector
50+
}
51+
52+
// ApplyToList fill in ListOptions LabelSelector and FieldSelector if needed
53+
func (s Selector) ApplyToList(listOpts *metav1.ListOptions) {
54+
...
55+
}
56+
57+
58+
Add a type alias to `pkg/cache/cache.go` to internal
59+
60+
```golang
61+
62+
type SelectorsByObject internal.SelectorsByObject
63+
64+
```
65+
66+
Extend `cache.Options` as follows:
67+
68+
```golang
69+
type Options struct {
70+
Scheme *runtime.Scheme
71+
Mapper meta.RESTMapper
72+
Resync *time.Duration
73+
Namespace string
74+
SelectorsByObject SelectorsByObject
75+
}
76+
```
77+
78+
Add new builder function that will return a cache constructor using the passed
79+
cache.Options, users can set SelectorsByObject there to filter out cache, it
80+
will convert SelectorByObject to SelectorsByGVK
81+
82+
83+
```golang
84+
func BuilderWithOptions(options cache.Options) NewCacheFunc {
85+
...
86+
}
87+
```
88+
89+
is passed to informer's ListWatch and add the filtering option:
90+
91+
```golang
92+
93+
# At pkg/cache/internal/informers_map.go
94+
95+
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
96+
ip.selectors[gvk].ApplyToList(&opts)
97+
...
98+
```
99+
100+
Here is a PR with the implementatin at the `pkg/cache` part [3]
101+
102+
## Example
103+
104+
User will override `NewCache` function to make clear that they know exactly the
105+
implications of using a different cache than the default one
106+
107+
```golang
108+
ctrl.Options.NewCache = cache.BuilderWithOptions(cache.Options{
109+
SelectorsByObject: cache.SelectorsByObject{
110+
&corev1.Node{}: {
111+
Field: fields.SelectorFromSet(fields.Set{"metadata.name": "node01"}),
112+
}
113+
&v1beta1.NodeNetworkState{}: {
114+
Field: fields.SelectorFromSet(fields.Set{"metadata.name": "node01"}),
115+
Label: labels.SelectorFromSet(labels.Set{"app": "kubernetes-nmstate})",
116+
}
117+
}
118+
}
119+
)
120+
```
121+
122+
123+
[1] https://github.com/nmstate/kubernetes-nmstate/pull/687
124+
[2] https://github.com/kubernetes-sigs/controller-runtime/issues/244
125+
[3] https://github.com/kubernetes-sigs/controller-runtime/pull/1404

0 commit comments

Comments
 (0)