@@ -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 {
@@ -50,9 +50,15 @@ func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
5050 if err != nil {
5151 return nil , err
5252 }
53- // create a cache for cluster scoped resources
54- namespaces = append (namespaces , globalCache )
53+
5554 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+
5662 for _ , ns := range namespaces {
5763 opts .Namespace = ns
5864 c , err := New (config , opts )
@@ -61,7 +67,7 @@ func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
6167 }
6268 caches [ns ] = c
6369 }
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
6571 }
6672}
6773
@@ -73,36 +79,82 @@ type multiNamespaceCache struct {
7379 namespaceToCache map [string ]Cache
7480 Scheme * runtime.Scheme
7581 RESTMapper meta.RESTMapper
82+ clusterCache Cache
7683}
7784
7885var _ Cache = & multiNamespaceCache {}
7986
8087// Methods for multiNamespaceCache to conform to the Informers interface
8188func (c * multiNamespaceCache ) GetInformer (ctx context.Context , obj client.Object ) (Informer , error ) {
8289 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+
83107 for ns , cache := range c .namespaceToCache {
84108 informer , err := cache .GetInformer (ctx , obj )
85109 if err != nil {
86110 return nil , err
87111 }
88112 informers [ns ] = informer
89113 }
114+
90115 return & multiNamespaceInformer {namespaceToInformer : informers }, nil
91116}
92117
93118func (c * multiNamespaceCache ) GetInformerForKind (ctx context.Context , gvk schema.GroupVersionKind ) (Informer , error ) {
94119 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+
95137 for ns , cache := range c .namespaceToCache {
96138 informer , err := cache .GetInformerForKind (ctx , gvk )
97139 if err != nil {
98140 return nil , err
99141 }
100142 informers [ns ] = informer
101143 }
144+
102145 return & multiNamespaceInformer {namespaceToInformer : informers }, nil
103146}
104147
105148func (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
106158 for ns , cache := range c .namespaceToCache {
107159 go func (ns string , cache Cache ) {
108160 err := cache .Start (ctx )
@@ -111,6 +163,7 @@ func (c *multiNamespaceCache) Start(ctx context.Context) error {
111163 }
112164 }(ns , cache )
113165 }
166+
114167 <- ctx .Done ()
115168 return nil
116169}
@@ -122,10 +175,24 @@ func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
122175 synced = s
123176 }
124177 }
178+
179+ // check if cluster scoped cache has synced
180+ if ! c .clusterCache .WaitForCacheSync (ctx ) {
181+ synced = false
182+ }
125183 return synced
126184}
127185
128186func (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+
129196 for _ , cache := range c .namespaceToCache {
130197 if err := cache .IndexField (ctx , obj , field , extractValue ); err != nil {
131198 return err
@@ -142,8 +209,7 @@ func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj
142209
143210 if ! isNamespaced {
144211 // 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 )
147213 }
148214
149215 cache , ok := c .namespaceToCache [key .Namespace ]
@@ -165,8 +231,7 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
165231
166232 if ! isNamespaced {
167233 // 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 ... )
170235 }
171236
172237 if listOpts .Namespace != corev1 .NamespaceAll {
0 commit comments