@@ -93,7 +93,8 @@ func (r *NamespaceScopeReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
93
93
instance = r .setDefaults (instance )
94
94
95
95
klog .Infof ("Reconciling NamespaceScope: %s" , req .NamespacedName )
96
- if err := r .InitConfigMap (instance ); err != nil {
96
+
97
+ if err := r .UpdateStatus (instance ); err != nil {
97
98
return ctrl.Result {}, err
98
99
}
99
100
@@ -123,23 +124,41 @@ func (r *NamespaceScopeReconciler) addFinalizer(nss *operatorv1.NamespaceScope)
123
124
return nil
124
125
}
125
126
126
- func (r * NamespaceScopeReconciler ) InitConfigMap (instance * operatorv1.NamespaceScope ) error {
127
+ func (r * NamespaceScopeReconciler ) UpdateStatus (instance * operatorv1.NamespaceScope ) error {
128
+ // Get validated namespaces
129
+ validatedNamespaces , err := r .getValidatedNamespaces (instance )
130
+ if err != nil {
131
+ klog .Errorf ("Failed to get validated namespaces: %v" , err )
132
+ return err
133
+ }
134
+ // Update instance status with the validated namespaces
135
+ if ! util .StringSliceContentEqual (instance .Status .ValidatedMembers , validatedNamespaces ) {
136
+ instance .Status .ValidatedMembers = validatedNamespaces
137
+ if err := r .Status ().Update (ctx , instance ); err != nil {
138
+ klog .Errorf ("Failed to update instance %s/%s: %v" , instance .Namespace , instance .Name , err )
139
+ return err
140
+ }
141
+ }
142
+
143
+ return nil
144
+ }
145
+
146
+ func (r * NamespaceScopeReconciler ) UpdateConfigMap (instance * operatorv1.NamespaceScope ) error {
127
147
cm := & corev1.ConfigMap {}
128
148
cmName := instance .Spec .ConfigmapName
129
149
cmNamespace := instance .Namespace
150
+ cmKey := types.NamespacedName {Name : cmName , Namespace : cmNamespace }
151
+ validatedMembers , err := r .getAllValidatedNamespaceMembers (instance )
152
+ if err != nil {
153
+ klog .Errorf ("Failed to get all validated namespace members: %v" , err )
154
+ return err
155
+ }
130
156
131
- if err := r .Get (ctx , types.NamespacedName {Name : cmName , Namespace : cmNamespace }, cm ); err != nil {
132
- // If ConfigMap does not exist, create it
157
+ if err := r .Get (ctx , cmKey , cm ); err != nil {
133
158
if errors .IsNotFound (err ) {
134
- cm .Name = cmName
135
- cm .Namespace = cmNamespace
136
159
cm .Labels = map [string ]string {constant .NamespaceScopeLabel : "true" }
137
160
cm .Data = make (map [string ]string )
138
- nsMembers , err := r .getNamespaceList (instance )
139
- if err != nil {
140
- return err
141
- }
142
- cm .Data ["namespaces" ] = strings .Join (nsMembers , "," )
161
+ cm .Data ["namespaces" ] = strings .Join (validatedMembers , "," )
143
162
// Set NamespaceScope instance as the owner of the ConfigMap.
144
163
if err := controllerutil .SetOwnerReference (instance , cm , r .Scheme ); err != nil {
145
164
klog .Errorf ("Failed to set owner reference for ConfigMap %s/%s: %v" , cmNamespace , cmName , err )
@@ -158,33 +177,13 @@ func (r *NamespaceScopeReconciler) InitConfigMap(instance *operatorv1.NamespaceS
158
177
return err
159
178
}
160
179
161
- return nil
162
- }
163
-
164
- func (r * NamespaceScopeReconciler ) UpdateConfigMap (instance * operatorv1.NamespaceScope ) error {
165
- cm := & corev1.ConfigMap {}
166
- cmKey := types.NamespacedName {Name : instance .Spec .ConfigmapName , Namespace : instance .Namespace }
167
- if err := r .Get (ctx , cmKey , cm ); err != nil {
168
- if errors .IsNotFound (err ) {
169
- klog .Infof ("ConfigMap %s not found " , cmKey .String ())
170
- return nil
171
- }
172
- return err
173
- }
174
-
175
- // If NamespaceMembers changed, update ConfigMap
176
- nsMembers , err := r .getNamespaceList (instance )
177
- if err != nil {
178
- return err
179
- }
180
-
181
180
// Get owner uids
182
181
ownerRefUIDs := util .GetOwnerReferenceUIDs (cm .GetOwnerReferences ())
183
182
184
- if util .CheckListDifference (nsMembers , strings .Split (cm .Data ["namespaces" ], "," )) || ! util .UIDContains (ownerRefUIDs , instance .UID ) {
185
- restartpod := util .CheckListDifference (nsMembers , strings .Split (cm .Data ["namespaces" ], "," ))
183
+ if util .CheckListDifference (validatedMembers , strings .Split (cm .Data ["namespaces" ], "," )) || ! util .UIDContains (ownerRefUIDs , instance .UID ) {
184
+ restartpod := util .CheckListDifference (validatedMembers , strings .Split (cm .Data ["namespaces" ], "," ))
186
185
if restartpod {
187
- cm .Data ["namespaces" ] = strings .Join (nsMembers , "," )
186
+ cm .Data ["namespaces" ] = strings .Join (validatedMembers , "," )
188
187
}
189
188
190
189
if err := controllerutil .SetOwnerReference (instance , cm , r .Scheme ); err != nil {
@@ -220,7 +219,7 @@ func (r *NamespaceScopeReconciler) PushRbacToNamespace(instance *operatorv1.Name
220
219
return err
221
220
}
222
221
223
- for _ , toNs := range instance .Spec . NamespaceMembers {
222
+ for _ , toNs := range instance .Status . ValidatedMembers {
224
223
if toNs == operatorNs {
225
224
continue
226
225
}
@@ -246,7 +245,7 @@ func (r *NamespaceScopeReconciler) DeleteRbacFromUnmanagedNamespace(instance *op
246
245
if cm .Data ["namespaces" ] != "" {
247
246
nsInCm = strings .Split (cm .Data ["namespaces" ], "," )
248
247
}
249
- nsInCr , err := r .getNamespaceList (instance )
248
+ nsInCr , err := r .getAllValidatedNamespaceMembers (instance )
250
249
if err != nil {
251
250
return err
252
251
}
@@ -286,7 +285,6 @@ func (r *NamespaceScopeReconciler) DeleteRbacFromUnmanagedNamespace(instance *op
286
285
287
286
// When delete NamespaceScope instance, cleanup all RBAC resources
288
287
func (r * NamespaceScopeReconciler ) DeleteAllRbac (instance * operatorv1.NamespaceScope ) error {
289
- instance = r .setDefaults (instance )
290
288
labels := map [string ]string {
291
289
"namespace-scope-configmap" : instance .Namespace + "-" + instance .Spec .ConfigmapName ,
292
290
}
@@ -297,7 +295,7 @@ func (r *NamespaceScopeReconciler) DeleteAllRbac(instance *operatorv1.NamespaceS
297
295
return err
298
296
}
299
297
300
- usingMembers , err := r .getNamespaceList (instance )
298
+ usingMembers , err := r .getAllValidatedNamespaceMembers (instance )
301
299
if err != nil {
302
300
return err
303
301
}
@@ -618,21 +616,13 @@ func (r *NamespaceScopeReconciler) setDefaults(instance *operatorv1.NamespaceSco
618
616
constant .DefaultRestartLabelsKey : constant .DefaultRestartLabelsValue ,
619
617
}
620
618
}
621
- if r .checkGetNSAuth () {
622
- if validatedNs , err := r .getValidatedNamespaces (instance ); err != nil {
623
- klog .Errorf ("Failed to validate namespace: %v" , err )
624
- } else {
625
- instance .Spec .NamespaceMembers = validatedNs
626
- }
627
- }
628
-
629
619
return instance
630
620
}
631
621
632
- func (r * NamespaceScopeReconciler ) getNamespaceList (instance * operatorv1.NamespaceScope ) ([]string , error ) {
622
+ func (r * NamespaceScopeReconciler ) getAllValidatedNamespaceMembers (instance * operatorv1.NamespaceScope ) ([]string , error ) {
633
623
// List the instance using the same configmap
634
624
crList := & operatorv1.NamespaceScopeList {}
635
- namespaceMembersList := util . MakeSet ( []string {})
625
+ namespaceMembers := []string {}
636
626
if err := r .List (ctx , crList , & client.ListOptions {Namespace : instance .Namespace }); err != nil {
637
627
klog .Errorf ("Cannot list namespacescope with in namespace %s: %v" , instance .Namespace , err )
638
628
return nil , err
@@ -643,16 +633,13 @@ func (r *NamespaceScopeReconciler) getNamespaceList(instance *operatorv1.Namespa
643
633
continue
644
634
}
645
635
if instance .Spec .ConfigmapName == cr .Spec .ConfigmapName {
646
- for _ , ns := range cr .Spec .NamespaceMembers {
647
- namespaceMembersList .Add (ns )
648
- }
636
+ namespaceMembers = append (namespaceMembers , cr .Status .ValidatedMembers ... )
649
637
}
650
638
}
651
- return util .ToStringSlice (namespaceMembersList ), nil
639
+ return util .ToStringSlice (util . MakeSet ( namespaceMembers ) ), nil
652
640
}
653
641
654
642
func (r * NamespaceScopeReconciler ) checkGetNSAuth () bool {
655
- // List the instance using the same configmap
656
643
sar := & authorizationv1.SelfSubjectAccessReview {
657
644
Spec : authorizationv1.SelfSubjectAccessReviewSpec {
658
645
ResourceAttributes : & authorizationv1.ResourceAttributes {
@@ -667,27 +654,59 @@ func (r *NamespaceScopeReconciler) checkGetNSAuth() bool {
667
654
klog .Errorf ("Failed to check if operator has permission to get namespace: %v" , err )
668
655
return false
669
656
}
657
+ klog .V (2 ).Infof ("Get Namespace permission, Allowed: %t, Denied: %t, Reason: %s" , sar .Status .Allowed , sar .Status .Denied , sar .Status .Reason )
658
+ return sar .Status .Allowed
659
+ }
660
+
661
+ // Check if operator has namespace admin permission
662
+ func (r * NamespaceScopeReconciler ) checkNamespaceAdminAuth (namespace string ) bool {
663
+ sar := & authorizationv1.SelfSubjectAccessReview {
664
+ Spec : authorizationv1.SelfSubjectAccessReviewSpec {
665
+ ResourceAttributes : & authorizationv1.ResourceAttributes {
666
+ Namespace : namespace ,
667
+ Verb : "*" ,
668
+ Group : "*" ,
669
+ Resource : "*" ,
670
+ },
671
+ },
672
+ }
673
+
674
+ if err := r .Create (ctx , sar ); err != nil {
675
+ klog .Errorf ("Failed to check operator namespace admin permission: %v" , err )
676
+ return false
677
+ }
678
+
679
+ klog .V (2 ).Infof ("Namespace admin permission in namesapce %s, Allowed: %t, Denied: %t, Reason: %s" , namespace , sar .Status .Allowed , sar .Status .Denied , sar .Status .Reason )
670
680
return sar .Status .Allowed
671
681
}
672
682
673
683
func (r * NamespaceScopeReconciler ) getValidatedNamespaces (instance * operatorv1.NamespaceScope ) ([]string , error ) {
674
684
var validatedNs []string
675
685
for _ , nsMem := range instance .Spec .NamespaceMembers {
676
- ns := & corev1.Namespace {}
677
- key := types.NamespacedName {Name : nsMem }
678
- if err := r .Get (ctx , key , ns ); err != nil {
679
- if errors .IsNotFound (err ) {
680
- klog .Infof ("Namespace %s does not exist and will be ignored" , nsMem )
681
- continue
682
- } else {
683
- return nil , err
686
+ // Check if operator has target namespace admin permission
687
+ if r .checkNamespaceAdminAuth (nsMem ) {
688
+ // Check if operator has permission to get namespace resource
689
+ if r .checkGetNSAuth () {
690
+ ns := & corev1.Namespace {}
691
+ key := types.NamespacedName {Name : nsMem }
692
+ if err := r .Get (ctx , key , ns ); err != nil {
693
+ if errors .IsNotFound (err ) {
694
+ klog .Infof ("Namespace %s does not exist and will be ignored" , nsMem )
695
+ continue
696
+ } else {
697
+ return nil , err
698
+ }
699
+ }
700
+ if ns .Status .Phase == corev1 .NamespaceTerminating {
701
+ klog .Infof ("Namespace %s is terminating. Ignore this namespace " , nsMem )
702
+ continue
703
+ }
684
704
}
705
+ validatedNs = append (validatedNs , nsMem )
706
+ } else {
707
+ klog .Infof ("ibm-namespace-scope-operator has not admin permission in namespace %s" , nsMem )
708
+ r .Recorder .Eventf (instance , corev1 .EventTypeWarning , "Forbidden" , "ibm-namespace-scope-operator has not admin permission in namespace %s" , nsMem )
685
709
}
686
- if ns .Status .Phase == corev1 .NamespaceTerminating {
687
- klog .Infof ("Namespace %s is terminating. Ignore this namespace " , nsMem )
688
- continue
689
- }
690
- validatedNs = append (validatedNs , nsMem )
691
710
}
692
711
return validatedNs , nil
693
712
}
0 commit comments