@@ -91,6 +91,8 @@ func (r *RuleReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager)
9191// +kubebuilder:rbac:groups=readiness.node.x-k8s.io,resources=nodereadinessrules/status,verbs=get;update;patch
9292// +kubebuilder:rbac:groups=readiness.node.x-k8s.io,resources=nodereadinessrules/finalizers,verbs=update
9393// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
94+ // +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;patch;delete
95+ // +kubebuilder:rbac:groups="",resources=nodes,verbs=get;list;watch;create;update;patch;delete
9496
9597func (r * RuleReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
9698 log := ctrl .LoggerFrom (ctx )
@@ -167,13 +169,20 @@ func (r *RuleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.
167169 return ctrl.Result {RequeueAfter : time .Minute }, err
168170 }
169171
172+ // Sync taints to ConfigMap for MutatingAdmissionPolicy
173+ if err := r .Controller .syncTaintsConfigMap (ctx ); err != nil {
174+ log .Error (err , "Failed to sync taints configmap" , "rule" , rule .Name )
175+ // Don't fail reconciliation for this - log and continue
176+ }
177+
170178 return ctrl.Result {}, nil
171179}
172180
173181// reconcileDelete handles the rules deletion, It performs following actions
174182// 1. Deletes the taints associated with the rule.
175183// 2. Remove the rule from the cache.
176184// 3. Remove the finalizer from the rule.
185+ // 4. Sync the Taints ConfigMap.
177186func (r * RuleReconciler ) reconcileDelete (ctx context.Context , rule * readinessv1alpha1.NodeReadinessRule ) (ctrl.Result , error ) {
178187 log := ctrl .LoggerFrom (ctx )
179188
@@ -197,6 +206,13 @@ func (r *RuleReconciler) reconcileDelete(ctx context.Context, rule *readinessv1a
197206 if err != nil {
198207 return ctrl.Result {}, err
199208 }
209+
210+ // Sync taints to ConfigMap for MutatingAdmissionPolicy
211+ if err := r .Controller .syncTaintsConfigMap (ctx ); err != nil {
212+ log .Error (err , "Failed to sync taints configmap" , "rule" , rule .Name )
213+ // Don't fail reconciliation for this - log and continue
214+ }
215+
200216 return ctrl.Result {}, nil
201217}
202218
@@ -678,6 +694,79 @@ func (r *RuleReadinessController) cleanupNodesAfterSelectorChange(ctx context.Co
678694 return nil
679695}
680696
697+ // syncTaintsConfigMap synchronizes readiness taints to a ConfigMap for admission policy.
698+ func (r * RuleReadinessController ) syncTaintsConfigMap (ctx context.Context ) error {
699+ log := ctrl .LoggerFrom (ctx )
700+
701+ // List all NodeReadinessRules
702+ var ruleList readinessv1alpha1.NodeReadinessRuleList
703+ if err := r .List (ctx , & ruleList ); err != nil {
704+ return fmt .Errorf ("failed to list NodeReadinessRules: %w" , err )
705+ }
706+
707+ // Extract unique taint keys with readiness.k8s.io/ prefix and NoSchedule effect
708+ taintKeysSet := make (map [string ]struct {})
709+ for _ , rule := range ruleList .Items {
710+ // Skip rules that are being deleted
711+ if ! rule .DeletionTimestamp .IsZero () {
712+ continue
713+ }
714+ if rule .Spec .Taint .Key != "" &&
715+ strings .HasPrefix (rule .Spec .Taint .Key , "readiness.k8s.io/" ) &&
716+ rule .Spec .Taint .Effect == corev1 .TaintEffectNoSchedule {
717+ taintKeysSet [rule .Spec .Taint .Key ] = struct {}{}
718+ }
719+ }
720+
721+ // Convert set to comma-separated string
722+ taintKeys := make ([]string , 0 , len (taintKeysSet ))
723+ for key := range taintKeysSet {
724+ taintKeys = append (taintKeys , key )
725+ }
726+ taintKeysStr := strings .Join (taintKeys , "," )
727+
728+ // Update or create ConfigMap
729+ cm := & corev1.ConfigMap {
730+ ObjectMeta : metav1.ObjectMeta {
731+ Name : "readiness-taints" ,
732+ Namespace : "nrr-system" ,
733+ },
734+ }
735+
736+ // Try to get existing ConfigMap
737+ existingCM := & corev1.ConfigMap {}
738+ err := r .Get (ctx , client.ObjectKey {Name : "readiness-taints" , Namespace : "nrr-system" }, existingCM )
739+ if err != nil && ! apierrors .IsNotFound (err ) {
740+ return fmt .Errorf ("failed to get configmap: %w" , err )
741+ }
742+
743+ // Set data
744+ cm .Data = map [string ]string {
745+ "taint-keys" : taintKeysStr ,
746+ }
747+
748+ if apierrors .IsNotFound (err ) {
749+ // Create new ConfigMap
750+ log .Info ("Creating readiness-taints ConfigMap" , "taintCount" , len (taintKeys ))
751+ if err := r .Create (ctx , cm ); err != nil {
752+ return fmt .Errorf ("failed to create configmap: %w" , err )
753+ }
754+ } else {
755+ // Update existing ConfigMap
756+ log .V (1 ).Info ("Updating readiness-taints ConfigMap" , "taintCount" , len (taintKeys ))
757+ patch := client .MergeFrom (existingCM .DeepCopy ())
758+ existingCM .Data = cm .Data
759+ if err := r .Patch (ctx , existingCM , patch ); err != nil {
760+ return fmt .Errorf ("failed to update configmap: %w" , err )
761+ }
762+ }
763+
764+ log .V (2 ).Info ("Successfully synced taints to ConfigMap" ,
765+ "totalRules" , len (ruleList .Items ),
766+ "readinessTaints" , len (taintKeys ))
767+ return nil
768+ }
769+
681770func (r * RuleReconciler ) ensureFinalizer (ctx context.Context , rule * readinessv1alpha1.NodeReadinessRule , finalizer string ) (finalizerAdded bool , err error ) {
682771 // Finalizers can only be added when the deletionTimestamp is not set.
683772 if ! rule .GetDeletionTimestamp ().IsZero () {
0 commit comments