@@ -41,7 +41,7 @@ const globalCache = "_cluster-scope"
41
41
// MultiNamespacedCacheBuilder - Builder function to create a new multi-namespaced cache.
42
42
// This will scope the cache to a list of namespaces. Listing for all namespaces
43
43
// will list for all the namespaces that this knows about. By default this will create
44
- // a global cache for cluster scoped resource (having empty namespace) . Note that this is not intended
44
+ // a global cache for cluster scoped resource. Note that this is not intended
45
45
// to be used for excluding namespaces, this is better done via a Predicate. Also note that
46
46
// you may face performance issues when using this with a high number of namespaces.
47
47
func MultiNamespacedCacheBuilder (namespaces []string ) NewCacheFunc {
@@ -50,9 +50,15 @@ func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
50
50
if err != nil {
51
51
return nil , err
52
52
}
53
- // create a cache for cluster scoped resources
54
- namespaces = append (namespaces , globalCache )
53
+
55
54
caches := map [string ]Cache {}
55
+
56
+ // create a cache for cluster scoped resources
57
+ gCache , err := New (config , opts )
58
+ if err != nil {
59
+ return nil , fmt .Errorf ("error creating global cache %v" , err )
60
+ }
61
+
56
62
for _ , ns := range namespaces {
57
63
opts .Namespace = ns
58
64
c , err := New (config , opts )
@@ -61,7 +67,7 @@ func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
61
67
}
62
68
caches [ns ] = c
63
69
}
64
- return & multiNamespaceCache {namespaceToCache : caches , Scheme : opts .Scheme , RESTMapper : opts .Mapper }, nil
70
+ return & multiNamespaceCache {namespaceToCache : caches , Scheme : opts .Scheme , RESTMapper : opts .Mapper , clusterCache : gCache }, nil
65
71
}
66
72
}
67
73
@@ -73,36 +79,82 @@ type multiNamespaceCache struct {
73
79
namespaceToCache map [string ]Cache
74
80
Scheme * runtime.Scheme
75
81
RESTMapper meta.RESTMapper
82
+ clusterCache Cache
76
83
}
77
84
78
85
var _ Cache = & multiNamespaceCache {}
79
86
80
87
// Methods for multiNamespaceCache to conform to the Informers interface
81
88
func (c * multiNamespaceCache ) GetInformer (ctx context.Context , obj client.Object ) (Informer , error ) {
82
89
informers := map [string ]Informer {}
90
+
91
+ // If the object is clusterscoped, get the informer from clusterCache,
92
+ // if not use the namespaced caches.
93
+ isNamespaced , err := objectutil .IsAPINamespaced (obj , c .Scheme , c .RESTMapper )
94
+ if err != nil {
95
+ return nil , err
96
+ }
97
+ if ! isNamespaced {
98
+ clusterCacheInf , err := c .clusterCache .GetInformer (ctx , obj )
99
+ if err != nil {
100
+ return nil , err
101
+ }
102
+ informers [globalCache ] = clusterCacheInf
103
+
104
+ return & multiNamespaceInformer {namespaceToInformer : informers }, nil
105
+ }
106
+
83
107
for ns , cache := range c .namespaceToCache {
84
108
informer , err := cache .GetInformer (ctx , obj )
85
109
if err != nil {
86
110
return nil , err
87
111
}
88
112
informers [ns ] = informer
89
113
}
114
+
90
115
return & multiNamespaceInformer {namespaceToInformer : informers }, nil
91
116
}
92
117
93
118
func (c * multiNamespaceCache ) GetInformerForKind (ctx context.Context , gvk schema.GroupVersionKind ) (Informer , error ) {
94
119
informers := map [string ]Informer {}
120
+
121
+ // If the object is clusterscoped, get the informer from clusterCache,
122
+ // if not use the namespaced caches.
123
+ isNamespaced , err := objectutil .IsAPINamespacedWithGVK (gvk , c .Scheme , c .RESTMapper )
124
+ if err != nil {
125
+ return nil , err
126
+ }
127
+ if ! isNamespaced {
128
+ clusterCacheInf , err := c .clusterCache .GetInformerForKind (ctx , gvk )
129
+ if err != nil {
130
+ return nil , err
131
+ }
132
+ informers [globalCache ] = clusterCacheInf
133
+
134
+ return & multiNamespaceInformer {namespaceToInformer : informers }, nil
135
+ }
136
+
95
137
for ns , cache := range c .namespaceToCache {
96
138
informer , err := cache .GetInformerForKind (ctx , gvk )
97
139
if err != nil {
98
140
return nil , err
99
141
}
100
142
informers [ns ] = informer
101
143
}
144
+
102
145
return & multiNamespaceInformer {namespaceToInformer : informers }, nil
103
146
}
104
147
105
148
func (c * multiNamespaceCache ) Start (ctx context.Context ) error {
149
+ // start global cache
150
+ go func () {
151
+ err := c .clusterCache .Start (ctx )
152
+ if err != nil {
153
+ log .Error (err , "cluster scoped cache failed to start" )
154
+ }
155
+ }()
156
+
157
+ // start namespaced caches
106
158
for ns , cache := range c .namespaceToCache {
107
159
go func (ns string , cache Cache ) {
108
160
err := cache .Start (ctx )
@@ -111,6 +163,7 @@ func (c *multiNamespaceCache) Start(ctx context.Context) error {
111
163
}
112
164
}(ns , cache )
113
165
}
166
+
114
167
<- ctx .Done ()
115
168
return nil
116
169
}
@@ -122,10 +175,24 @@ func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
122
175
synced = s
123
176
}
124
177
}
178
+
179
+ // check if cluster scoped cache has synced
180
+ if ! c .clusterCache .WaitForCacheSync (ctx ) {
181
+ synced = false
182
+ }
125
183
return synced
126
184
}
127
185
128
186
func (c * multiNamespaceCache ) IndexField (ctx context.Context , obj client.Object , field string , extractValue client.IndexerFunc ) error {
187
+ isNamespaced , err := objectutil .IsAPINamespaced (obj , c .Scheme , c .RESTMapper )
188
+ if err != nil {
189
+ return nil
190
+ }
191
+
192
+ if ! isNamespaced {
193
+ return c .clusterCache .IndexField (ctx , obj , field , extractValue )
194
+ }
195
+
129
196
for _ , cache := range c .namespaceToCache {
130
197
if err := cache .IndexField (ctx , obj , field , extractValue ); err != nil {
131
198
return err
@@ -142,8 +209,7 @@ func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj
142
209
143
210
if ! isNamespaced {
144
211
// Look into the global cache to fetch the object
145
- cache := c .namespaceToCache [globalCache ]
146
- return cache .Get (ctx , key , obj )
212
+ return c .clusterCache .Get (ctx , key , obj )
147
213
}
148
214
149
215
cache , ok := c .namespaceToCache [key .Namespace ]
@@ -165,8 +231,7 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
165
231
166
232
if ! isNamespaced {
167
233
// Look at the global cache to get the objects with the specified GVK
168
- cache := c .namespaceToCache [globalCache ]
169
- return cache .List (ctx , list , opts ... )
234
+ return c .clusterCache .List (ctx , list , opts ... )
170
235
}
171
236
172
237
if listOpts .Namespace != corev1 .NamespaceAll {
0 commit comments