@@ -41,7 +41,7 @@ const globalCache = "_cluster-scope"
4141// MultiNamespacedCacheBuilder - Builder function to create a new multi-namespaced cache. 
4242// This will scope the cache to a list of namespaces. Listing for all namespaces 
4343// 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 
4545// to be used for excluding namespaces, this is better done via a Predicate. Also note that 
4646// you may face performance issues when using this with a high number of namespaces. 
4747func  MultiNamespacedCacheBuilder (namespaces  []string ) NewCacheFunc  {
@@ -59,9 +59,6 @@ func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
5959			return  nil , fmt .Errorf ("error creating global cache %v" , err )
6060		}
6161
62- 		// add global cache to the cacheMap 
63- 		caches [globalCache ] =  gCache 
64- 
6562		for  _ , ns  :=  range  namespaces  {
6663			opts .Namespace  =  ns 
6764			c , err  :=  New (config , opts )
@@ -70,7 +67,7 @@ func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
7067			}
7168			caches [ns ] =  c 
7269		}
73- 		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 
7471	}
7572}
7673
@@ -82,6 +79,7 @@ type multiNamespaceCache struct {
8279	namespaceToCache  map [string ]Cache 
8380	Scheme            * runtime.Scheme 
8481	RESTMapper        meta.RESTMapper 
82+ 	clusterCache      Cache 
8583}
8684
8785var  _  Cache  =  & multiNamespaceCache {}
@@ -96,6 +94,21 @@ func (c *multiNamespaceCache) GetInformer(ctx context.Context, obj client.Object
9694		}
9795		informers [ns ] =  informer 
9896	}
97+ 
98+ 	isNamespaced , err  :=  objectutil .IsAPINamespaced (obj , c .Scheme , c .RESTMapper )
99+ 	if  err  !=  nil  {
100+ 		return  nil , err 
101+ 	}
102+ 
103+ 	if  ! isNamespaced  {
104+ 		clusterCacheInf , err  :=  c .clusterCache .GetInformer (ctx , obj )
105+ 		if  err  !=  nil  {
106+ 			return  nil , err 
107+ 		}
108+ 		informers [globalCache ] =  clusterCacheInf 
109+ 
110+ 	}
111+ 
99112	return  & multiNamespaceInformer {namespaceToInformer : informers }, nil 
100113}
101114
@@ -108,10 +121,33 @@ func (c *multiNamespaceCache) GetInformerForKind(ctx context.Context, gvk schema
108121		}
109122		informers [ns ] =  informer 
110123	}
124+ 
125+ 	isNamespaced , err  :=  objectutil .IsAPINamespacedWithGVK (gvk , c .Scheme , c .RESTMapper )
126+ 	if  err  !=  nil  {
127+ 		return  nil , err 
128+ 	}
129+ 
130+ 	if  ! isNamespaced  {
131+ 		clusterCacheInf , err  :=  c .clusterCache .GetInformerForKind (ctx , gvk )
132+ 		if  err  !=  nil  {
133+ 			return  nil , err 
134+ 		}
135+ 		informers [globalCache ] =  clusterCacheInf 
136+ 	}
137+ 
111138	return  & multiNamespaceInformer {namespaceToInformer : informers }, nil 
112139}
113140
114141func  (c  * multiNamespaceCache ) Start (ctx  context.Context ) error  {
142+ 	// start global cache 
143+ 	go  func () {
144+ 		err  :=  c .clusterCache .Start (ctx )
145+ 		if  err  !=  nil  {
146+ 			log .Error (err , "cluster scoped cache failed to start" )
147+ 		}
148+ 	}()
149+ 
150+ 	// start namespaced caches 
115151	for  ns , cache  :=  range  c .namespaceToCache  {
116152		go  func (ns  string , cache  Cache ) {
117153			err  :=  cache .Start (ctx )
@@ -120,6 +156,7 @@ func (c *multiNamespaceCache) Start(ctx context.Context) error {
120156			}
121157		}(ns , cache )
122158	}
159+ 
123160	<- ctx .Done ()
124161	return  nil 
125162}
@@ -131,6 +168,11 @@ func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
131168			synced  =  s 
132169		}
133170	}
171+ 
172+ 	// check if cluster scoped cache has synced 
173+ 	if  ! c .clusterCache .WaitForCacheSync (ctx ) {
174+ 		synced  =  false 
175+ 	}
134176	return  synced 
135177}
136178
@@ -140,6 +182,10 @@ func (c *multiNamespaceCache) IndexField(ctx context.Context, obj client.Object,
140182			return  err 
141183		}
142184	}
185+ 
186+ 	if  err  :=  c .clusterCache .IndexField (ctx , obj , field , extractValue ); err  !=  nil  {
187+ 		return  fmt .Errorf ("error adding index on object with cluster scoped cache %v" , err )
188+ 	}
143189	return  nil 
144190}
145191
@@ -151,8 +197,7 @@ func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj
151197
152198	if  ! isNamespaced  {
153199		// Look into the global cache to fetch the object 
154- 		cache  :=  c .namespaceToCache [globalCache ]
155- 		return  cache .Get (ctx , key , obj )
200+ 		return  c .clusterCache .Get (ctx , key , obj )
156201	}
157202
158203	cache , ok  :=  c .namespaceToCache [key .Namespace ]
@@ -174,8 +219,7 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
174219
175220	if  ! isNamespaced  {
176221		// Look at the global cache to get the objects with the specified GVK 
177- 		cache  :=  c .namespaceToCache [globalCache ]
178- 		return  cache .List (ctx , list , opts ... )
222+ 		return  c .clusterCache .List (ctx , list , opts ... )
179223	}
180224
181225	if  listOpts .Namespace  !=  corev1 .NamespaceAll  {
@@ -199,10 +243,7 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
199243	limitSet  :=  listOpts .Limit  >  0 
200244
201245	var  resourceVersion  string 
202- 	for  ns , cache  :=  range  c .namespaceToCache  {
203- 		if  ns  ==  globalCache  {
204- 			continue 
205- 		}
246+ 	for  _ , cache  :=  range  c .namespaceToCache  {
206247		listObj  :=  list .DeepCopyObject ().(client.ObjectList )
207248		err  =  cache .List (ctx , listObj , & listOpts )
208249		if  err  !=  nil  {
0 commit comments