@@ -67,7 +67,11 @@ type HelmMetadataForwarder struct {
6767 // Value: *ReleaseEntry
6868 releaseSnapshots sync.Map
6969
70- // secretAccessEnabled tracks whether the operator has permission to read Secrets.
70+ // configMapAccessEnabled tracks whether the operator has permission to list/watch ConfigMaps.
71+ // Set once in Start() and used to skip the ConfigMap path in processKey.
72+ configMapAccessEnabled bool
73+
74+ // secretAccessEnabled tracks whether the operator has permission to list/watch Secrets.
7175 // Set once in Start() and used to skip the Secret path in processKey.
7276 secretAccessEnabled bool
7377}
@@ -160,19 +164,19 @@ func NewHelmMetadataForwarderWithManager(logger logr.Logger, mgr manager.Manager
160164 }
161165}
162166
163- // canListWatchSecrets checks if the operator has permission to list and watch Secrets
164- func (hmf * HelmMetadataForwarder ) canListWatchSecrets (ctx context.Context ) bool {
167+ // canListWatch checks if the operator has permission to list and watch the given resource
168+ func (hmf * HelmMetadataForwarder ) canListWatch (ctx context.Context , resource string ) bool {
165169 for _ , verb := range []string {"list" , "watch" } {
166170 sar := & authorizationv1.SelfSubjectAccessReview {
167171 Spec : authorizationv1.SelfSubjectAccessReviewSpec {
168172 ResourceAttributes : & authorizationv1.ResourceAttributes {
169173 Verb : verb ,
170- Resource : "secrets" ,
174+ Resource : resource ,
171175 },
172176 },
173177 }
174178 if err := hmf .mgr .GetClient ().Create (ctx , sar ); err != nil {
175- hmf .logger .V (1 ).Info ("Failed to check Secret RBAC permission" , "verb" , verb , "error" , err )
179+ hmf .logger .V (1 ).Info ("Failed to check RBAC permission" , "resource" , resource , "verb" , verb , "error" , err )
176180 return false
177181 }
178182 if ! sar .Status .Allowed {
@@ -188,41 +192,46 @@ func (hmf *HelmMetadataForwarder) canListWatchSecrets(ctx context.Context) bool
188192// https://github.com/kubernetes/client-go/blob/v0.35.0/tools/cache/shared_informer.go#L693-L697
189193// Errors are logged but do not prevent the operator from starting
190194func (hmf * HelmMetadataForwarder ) Start (ctx context.Context ) error {
191- cmInformer , err := hmf .mgr .GetCache ().GetInformer (ctx , & corev1.ConfigMap {})
192- if err != nil {
193- hmf .logger .Info ("Unable to get ConfigMap informer, Helm metadata collection will be disabled" , "error" , err )
194- return nil
195- }
196- _ , err = cmInformer .AddEventHandler (toolscache.FilteringResourceEventHandler {
197- FilterFunc : func (obj any ) bool {
198- cm , ok := obj .(* corev1.ConfigMap )
199- return ok &&
200- cm .Labels ["owner" ] == "helm" &&
201- strings .HasPrefix (cm .Name , releasePrefix )
202- },
203- Handler : toolscache.ResourceEventHandlerFuncs {
204- AddFunc : func (obj any ) {
205- if key , keyErr := toolscache .MetaNamespaceKeyFunc (obj ); keyErr == nil {
206- hmf .queue .Add (key )
207- hmf .logger .V (2 ).Info ("Enqueued ConfigMap for processing" , "key" , key )
208- }
209- },
210- DeleteFunc : func (obj any ) {
211- if key , keyErr := toolscache .DeletionHandlingMetaNamespaceKeyFunc (obj ); keyErr == nil {
212- hmf .queue .Add (deletePrefix + key )
213- hmf .logger .V (2 ).Info ("Enqueued ConfigMap deletion for processing" , "key" , key )
214- }
215- },
216- },
217- })
218-
219- if err != nil {
220- hmf .logger .Info ("Unable to add ConfigMap event handler, Helm metadata collection will be disabled" , "error" , err )
221- return nil
195+ hmf .configMapAccessEnabled = false
196+ if hmf .canListWatch (ctx , "configmaps" ) {
197+ cmInformer , err := hmf .mgr .GetCache ().GetInformer (ctx , & corev1.ConfigMap {})
198+ if err != nil {
199+ hmf .logger .Info ("Unable to get ConfigMap informer, Helm metadata collection from ConfigMaps will be disabled" , "error" , err )
200+ } else {
201+ _ , err = cmInformer .AddEventHandler (toolscache.FilteringResourceEventHandler {
202+ FilterFunc : func (obj any ) bool {
203+ cm , ok := obj .(* corev1.ConfigMap )
204+ return ok &&
205+ cm .Labels ["owner" ] == "helm" &&
206+ strings .HasPrefix (cm .Name , releasePrefix )
207+ },
208+ Handler : toolscache.ResourceEventHandlerFuncs {
209+ AddFunc : func (obj any ) {
210+ if key , keyErr := toolscache .MetaNamespaceKeyFunc (obj ); keyErr == nil {
211+ hmf .queue .Add (key )
212+ hmf .logger .V (2 ).Info ("Enqueued ConfigMap for processing" , "key" , key )
213+ }
214+ },
215+ DeleteFunc : func (obj any ) {
216+ if key , keyErr := toolscache .DeletionHandlingMetaNamespaceKeyFunc (obj ); keyErr == nil {
217+ hmf .queue .Add (deletePrefix + key )
218+ hmf .logger .V (2 ).Info ("Enqueued ConfigMap deletion for processing" , "key" , key )
219+ }
220+ },
221+ },
222+ })
223+ if err != nil {
224+ hmf .logger .Info ("Unable to add ConfigMap event handler, Helm metadata collection from ConfigMaps will be disabled" , "error" , err )
225+ } else {
226+ hmf .configMapAccessEnabled = true
227+ }
228+ }
229+ } else {
230+ hmf .logger .Info ("No permission to list/watch ConfigMaps, Helm metadata collection from ConfigMaps will be disabled" )
222231 }
223232
224- hmf .secretAccessEnabled = hmf . canListWatchSecrets ( ctx )
225- if hmf .secretAccessEnabled {
233+ hmf .secretAccessEnabled = false
234+ if hmf .canListWatch ( ctx , "secrets" ) {
226235 secretInformer , secretErr := hmf .mgr .GetCache ().GetInformer (ctx , & corev1.Secret {})
227236 if secretErr != nil {
228237 hmf .logger .Info ("Unable to get Secret informer, Helm metadata collection from Secrets will be disabled" , "error" , secretErr )
@@ -249,6 +258,8 @@ func (hmf *HelmMetadataForwarder) Start(ctx context.Context) error {
249258 })
250259 if secretErr != nil {
251260 hmf .logger .Info ("Unable to add Secret event handler, Helm metadata collection from Secrets will be disabled" , "error" , secretErr )
261+ } else {
262+ hmf .secretAccessEnabled = true
252263 }
253264 }
254265 } else {
@@ -322,30 +333,38 @@ func (hmf *HelmMetadataForwarder) processKey(ctx context.Context, key string) er
322333 return fmt .Errorf ("invalid key format: %w" , err )
323334 }
324335
325- // Try to get as ConfigMap first
326- cm := & corev1.ConfigMap {}
327- err = hmf .k8sClient .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, cm )
328- if err == nil && cm .Labels ["owner" ] == "helm" {
329- hmf .handleHelmResource (ctx , cm .Name , cm .Namespace , string (cm .UID ), []byte (cm .Data ["release" ]))
330- return nil
336+ var lastErr error
337+
338+ // Try to get as ConfigMap first (only if we have permission, to avoid lazily registering a ConfigMap informer)
339+ if hmf .configMapAccessEnabled {
340+ cm := & corev1.ConfigMap {}
341+ lastErr = hmf .k8sClient .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, cm )
342+ if lastErr == nil && cm .Labels ["owner" ] == "helm" {
343+ hmf .handleHelmResource (ctx , cm .Name , cm .Namespace , string (cm .UID ), []byte (cm .Data ["release" ]))
344+ return nil
345+ }
331346 }
332347
333348 // Try as Secret (only if we have permission, to avoid lazily registering a Secret informer)
334349 if hmf .secretAccessEnabled {
335350 secret := & corev1.Secret {}
336- err = hmf .k8sClient .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, secret )
337- if err == nil && secret .Labels ["owner" ] == "helm" {
351+ lastErr = hmf .k8sClient .Get (ctx , client.ObjectKey {Namespace : namespace , Name : name }, secret )
352+ if lastErr == nil && secret .Labels ["owner" ] == "helm" {
338353 hmf .handleHelmResource (ctx , secret .Name , secret .Namespace , string (secret .UID ), secret .Data ["release" ])
339354 return nil
340355 }
341356 }
342357
343358 // If not found, likely a race condition with deletion - ignore it
344- if errors .IsNotFound (err ) {
359+ if errors .IsNotFound (lastErr ) {
345360 return nil
346361 }
347362
348- return fmt .Errorf ("failed to get resource: %w" , err )
363+ if lastErr != nil {
364+ return fmt .Errorf ("failed to get resource: %w" , lastErr )
365+ }
366+
367+ return nil
349368}
350369
351370// handleDelete handles deletion of a Helm release
0 commit comments