@@ -34,9 +34,13 @@ import (
34
34
// NewCacheFunc - Function for creating a new cache from the options and a rest config
35
35
type NewCacheFunc func (config * rest.Config , opts Options ) (Cache , error )
36
36
37
+ // a new global namespaced cache to handle cluster scoped resources
38
+ var globalCache = ""
39
+
37
40
// MultiNamespacedCacheBuilder - Builder function to create a new multi-namespaced cache.
38
41
// This will scope the cache to a list of namespaces. Listing for all namespaces
39
- // will list for all the namespaces that this knows about. Note that this is not intended
42
+ // will list for all the namespaces that this knows about. By default this will create
43
+ // a global cache for cluster scoped resource (having empty namespace). Note that this is not intended
40
44
// to be used for excluding namespaces, this is better done via a Predicate. Also note that
41
45
// you may face performance issues when using this with a high number of namespaces.
42
46
func MultiNamespacedCacheBuilder (namespaces []string ) NewCacheFunc {
@@ -45,6 +49,8 @@ func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
45
49
if err != nil {
46
50
return nil , err
47
51
}
52
+ // create a cache for cluster scoped resources
53
+ namespaces = append (namespaces , globalCache )
48
54
caches := map [string ]Cache {}
49
55
for _ , ns := range namespaces {
50
56
opts .Namespace = ns
@@ -143,7 +149,16 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
143
149
if ! ok {
144
150
return fmt .Errorf ("unable to get: %v because of unknown namespace for the cache" , listOpts .Namespace )
145
151
}
146
- return cache .List (ctx , list , opts ... )
152
+ err := cache .List (ctx , list , opts ... )
153
+ if err != nil {
154
+ return err
155
+ }
156
+ items , err := apimeta .ExtractList (list )
157
+ if err != nil {
158
+ return err
159
+ }
160
+ uniqueItems := removeDuplicates (items )
161
+ return apimeta .SetList (list , uniqueItems )
147
162
}
148
163
149
164
listAccessor , err := meta .ListAccessor (list )
@@ -174,9 +189,28 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
174
189
// The last list call should have the most correct resource version.
175
190
resourceVersion = accessor .GetResourceVersion ()
176
191
}
192
+
193
+ uniqueItems := removeDuplicates (allItems )
177
194
listAccessor .SetResourceVersion (resourceVersion )
178
195
179
- return apimeta .SetList (list , allItems )
196
+ return apimeta .SetList (list , uniqueItems )
197
+ }
198
+
199
+ // removeDuplicates removes the duplicate objects obtained from all namespaces so that
200
+ // the resulting list has objects with unique name and namespace.
201
+ func removeDuplicates (items []runtime.Object ) []runtime.Object {
202
+ objects := make (map [string ]bool )
203
+ unique := []runtime.Object {}
204
+
205
+ for _ , obj := range items {
206
+ metaObj , _ := meta .Accessor (obj )
207
+ key := metaObj .GetName () + " " + metaObj .GetNamespace ()
208
+ if _ , value := objects [key ]; ! value {
209
+ objects [key ] = true
210
+ unique = append (unique , obj )
211
+ }
212
+ }
213
+ return unique
180
214
}
181
215
182
216
// multiNamespaceInformer knows how to handle interacting with the underlying informer across multiple namespaces
0 commit comments