@@ -20,6 +20,7 @@ import (
2020 "encoding/json"
2121 "fmt"
2222 "os"
23+ "reflect"
2324
2425 corev1 "k8s.io/api/core/v1"
2526 rbacv1 "k8s.io/api/rbac/v1"
@@ -163,42 +164,51 @@ func (feast *FeastServices) createNamespaceRegistryRoleBinding(targetNamespace s
163164
164165// setNamespaceRegistryRoleBinding sets the RoleBinding for namespace registry access
165166func (feast * FeastServices ) setNamespaceRegistryRoleBinding (rb * rbacv1.RoleBinding ) error {
166- // Create a Role that allows reading the ConfigMap
167+ roleName := NamespaceRegistryConfigMapName + "-reader"
168+
169+ desiredRules := []rbacv1.PolicyRule {
170+ {
171+ APIGroups : []string {"" },
172+ Resources : []string {"configmaps" },
173+ ResourceNames : []string {NamespaceRegistryConfigMapName },
174+ Verbs : []string {"get" , "list" },
175+ },
176+ }
177+
167178 role := & rbacv1.Role {
168179 ObjectMeta : metav1.ObjectMeta {
169- Name : NamespaceRegistryConfigMapName + "-reader" ,
180+ Name : roleName ,
170181 Namespace : rb .Namespace ,
171182 },
172- Rules : []rbacv1.PolicyRule {
173- {
174- APIGroups : []string {"" },
175- Resources : []string {"configmaps" },
176- ResourceNames : []string {NamespaceRegistryConfigMapName },
177- Verbs : []string {"get" , "list" },
178- },
179- },
180183 }
184+ role .Rules = desiredRules
181185
182- // Create or update the Role
183- if _ , err := controllerutil .CreateOrUpdate (feast .Handler .Context , feast .Handler .Client , role , controllerutil .MutateFn (func () error {
184- role .Rules = []rbacv1.PolicyRule {
185- {
186- APIGroups : []string {"" },
187- Resources : []string {"configmaps" },
188- ResourceNames : []string {NamespaceRegistryConfigMapName },
189- Verbs : []string {"get" , "list" },
190- },
186+ // Attempt to create; tolerate AlreadyExists so concurrent reconcilers don't fail.
187+ if err := feast .Handler .Client .Create (feast .Handler .Context , role ); err != nil && ! apierrors .IsAlreadyExists (err ) {
188+ return fmt .Errorf ("failed to create namespace registry Role: %w" , err )
189+ }
190+
191+ // Re-fetch the authoritative copy to compare rules and obtain the latest resourceVersion.
192+ existingRole := & rbacv1.Role {}
193+ if err := feast .Handler .Client .Get (feast .Handler .Context , types.NamespacedName {
194+ Name : roleName ,
195+ Namespace : rb .Namespace ,
196+ }, existingRole ); err != nil {
197+ return fmt .Errorf ("failed to get namespace registry Role: %w" , err )
198+ }
199+
200+ if ! reflect .DeepEqual (existingRole .Rules , desiredRules ) {
201+ existingRole .Rules = desiredRules
202+ // On conflict the reconciler will re-queue automatically.
203+ if err := feast .Handler .Client .Update (feast .Handler .Context , existingRole ); err != nil {
204+ return fmt .Errorf ("failed to update namespace registry Role: %w" , err )
191205 }
192- return nil
193- })); err != nil {
194- return err
195206 }
196207
197- // Set the RoleBinding
198208 rb .RoleRef = rbacv1.RoleRef {
199209 APIGroup : "rbac.authorization.k8s.io" ,
200210 Kind : "Role" ,
201- Name : role . Name ,
211+ Name : roleName ,
202212 }
203213
204214 rb .Subjects = []rbacv1.Subject {
0 commit comments