@@ -43,7 +43,7 @@ import (
4343// WildcardCache is a cache that operates on a /clusters/* endpoint.
4444type WildcardCache interface {
4545 cache.Cache
46- getSharedInformer (obj runtime.Object ) (k8scache.SharedIndexInformer , schema.GroupVersionKind , apimeta.RESTScopeName , bool , error )
46+ getSharedInformer (obj runtime.Object ) (k8scache.SharedIndexInformer , schema.GroupVersionKind , apimeta.RESTScopeName , error )
4747}
4848
4949// NewWildcardCache returns a cache.Cache that handles multi-cluster watches
@@ -80,6 +80,8 @@ func NewWildcardCache(config *rest.Config, opts cache.Options) (WildcardCache, e
8080 Unstructured : make (map [schema.GroupVersionKind ]k8scache.SharedIndexInformer ),
8181 Metadata : make (map [schema.GroupVersionKind ]k8scache.SharedIndexInformer ),
8282 },
83+
84+ readerFailOnMissingInformer : opts .ReaderFailOnMissingInformer ,
8385 }
8486
8587 opts .NewInformer = func (watcher k8scache.ListerWatcher , obj runtime.Object , duration time.Duration , indexers k8scache.Indexers ) k8scache.SharedIndexInformer {
@@ -121,25 +123,60 @@ type wildcardCache struct {
121123 scheme * runtime.Scheme
122124 mapper apimeta.RESTMapper
123125 tracker informerTracker
126+
127+ readerFailOnMissingInformer bool
124128}
125129
126- func (c * wildcardCache ) getSharedInformer (obj runtime.Object ) (k8scache.SharedIndexInformer , schema.GroupVersionKind , apimeta.RESTScopeName , bool , error ) {
130+ func (c * wildcardCache ) getSharedInformer (obj runtime.Object ) (k8scache.SharedIndexInformer , schema.GroupVersionKind , apimeta.RESTScopeName , error ) {
127131 gvk , err := apiutil .GVKForObject (obj , c .scheme )
128132 if err != nil {
129- return nil , gvk , "" , false , err
133+ return nil , gvk , "" , fmt . Errorf ( "failed to get GVK for object: %w" , err )
130134 }
131135
136+ // We need the non-list GVK, so chop off the "List" from the end of the kind.
137+ gvk .Kind = strings .TrimSuffix (gvk .Kind , "List" )
138+
132139 mapping , err := c .mapper .RESTMapping (gvk .GroupKind (), gvk .Version )
133140 if err != nil {
134- return nil , gvk , "" , false , err
141+ return nil , gvk , "" , fmt . Errorf ( "failed to get REST mapping: %w" , err )
135142 }
136143
137144 infs := c .tracker .informersByType (obj )
138145 c .tracker .lock .RLock ()
139146 inf , ok := infs [gvk ]
140147 c .tracker .lock .RUnlock ()
141148
142- return inf , gvk , mapping .Scope .Name (), ok , nil
149+ // we need to create a new informer here.
150+ if ! ok {
151+ // we have been instructed to fail if the informer is missing.
152+ if c .readerFailOnMissingInformer {
153+ return nil , gvk , "" , & cache.ErrResourceNotCached {}
154+ }
155+
156+ // Let's generate a new object from the chopped GVK, since the original obj might be of *List type.
157+ o , err := c .scheme .New (gvk )
158+ if err != nil {
159+ return nil , gvk , "" , fmt .Errorf ("failed to create object for GVK: %w" , err )
160+ }
161+
162+ // Call GetInformer, but we don't care about the output. We just need to make sure that our NewInformer
163+ // func has been called, which registers the new informer in our tracker.
164+ if _ , err := c .Cache .GetInformer (context .TODO (), o .(client.Object )); err != nil {
165+ return nil , gvk , "" , fmt .Errorf ("failed to create informer: %w" , err )
166+ }
167+
168+ // Now we should be able to find the informer.
169+ infs := c .tracker .informersByType (obj )
170+ c .tracker .lock .RLock ()
171+ inf , ok = infs [gvk ]
172+ c .tracker .lock .RUnlock ()
173+
174+ if ! ok {
175+ return nil , gvk , "" , fmt .Errorf ("failed to find newly started informer for %v" , gvk )
176+ }
177+ }
178+
179+ return inf , gvk , mapping .Scope .Name (), nil
143180}
144181
145182// IndexField adds an index for the given object kind.
0 commit comments