@@ -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,36 +79,82 @@ type multiNamespaceCache struct {
8279 namespaceToCache map [string ]Cache
8380 Scheme * runtime.Scheme
8481 RESTMapper meta.RESTMapper
82+ clusterCache Cache
8583}
8684
8785var _ Cache = & multiNamespaceCache {}
8886
8987// Methods for multiNamespaceCache to conform to the Informers interface
9088func (c * multiNamespaceCache ) GetInformer (ctx context.Context , obj client.Object ) (Informer , error ) {
9189 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+
92107 for ns , cache := range c .namespaceToCache {
93108 informer , err := cache .GetInformer (ctx , obj )
94109 if err != nil {
95110 return nil , err
96111 }
97112 informers [ns ] = informer
98113 }
114+
99115 return & multiNamespaceInformer {namespaceToInformer : informers }, nil
100116}
101117
102118func (c * multiNamespaceCache ) GetInformerForKind (ctx context.Context , gvk schema.GroupVersionKind ) (Informer , error ) {
103119 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+
104137 for ns , cache := range c .namespaceToCache {
105138 informer , err := cache .GetInformerForKind (ctx , gvk )
106139 if err != nil {
107140 return nil , err
108141 }
109142 informers [ns ] = informer
110143 }
144+
111145 return & multiNamespaceInformer {namespaceToInformer : informers }, nil
112146}
113147
114148func (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
115158 for ns , cache := range c .namespaceToCache {
116159 go func (ns string , cache Cache ) {
117160 err := cache .Start (ctx )
@@ -120,6 +163,7 @@ func (c *multiNamespaceCache) Start(ctx context.Context) error {
120163 }
121164 }(ns , cache )
122165 }
166+
123167 <- ctx .Done ()
124168 return nil
125169}
@@ -131,10 +175,24 @@ func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
131175 synced = s
132176 }
133177 }
178+
179+ // check if cluster scoped cache has synced
180+ if ! c .clusterCache .WaitForCacheSync (ctx ) {
181+ synced = false
182+ }
134183 return synced
135184}
136185
137186func (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+
138196 for _ , cache := range c .namespaceToCache {
139197 if err := cache .IndexField (ctx , obj , field , extractValue ); err != nil {
140198 return err
@@ -151,8 +209,7 @@ func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj
151209
152210 if ! isNamespaced {
153211 // Look into the global cache to fetch the object
154- cache := c .namespaceToCache [globalCache ]
155- return cache .Get (ctx , key , obj )
212+ return c .clusterCache .Get (ctx , key , obj )
156213 }
157214
158215 cache , ok := c .namespaceToCache [key .Namespace ]
@@ -174,8 +231,7 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
174231
175232 if ! isNamespaced {
176233 // 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 ... )
234+ return c .clusterCache .List (ctx , list , opts ... )
179235 }
180236
181237 if listOpts .Namespace != corev1 .NamespaceAll {
@@ -199,10 +255,7 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
199255 limitSet := listOpts .Limit > 0
200256
201257 var resourceVersion string
202- for ns , cache := range c .namespaceToCache {
203- if ns == globalCache {
204- continue
205- }
258+ for _ , cache := range c .namespaceToCache {
206259 listObj := list .DeepCopyObject ().(client.ObjectList )
207260 err = cache .List (ctx , listObj , & listOpts )
208261 if err != nil {
0 commit comments