@@ -20,6 +20,7 @@ import (
2020 "context"
2121 "fmt"
2222 "reflect"
23+ "strings"
2324 "time"
2425
2526 appsv1 "k8s.io/api/apps/v1"
@@ -28,9 +29,11 @@ import (
2829 apiextensionv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2930 apiequality "k8s.io/apimachinery/pkg/api/equality"
3031 apierrors "k8s.io/apimachinery/pkg/api/errors"
32+ apimeta "k8s.io/apimachinery/pkg/api/meta"
3133 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3234 "k8s.io/apimachinery/pkg/labels"
3335 "k8s.io/apimachinery/pkg/runtime"
36+ "k8s.io/apimachinery/pkg/util/sets"
3437 "k8s.io/client-go/tools/record"
3538 "k8s.io/klog/v2"
3639
@@ -139,6 +142,14 @@ func (r *NUMAResourcesOperatorReconciler) Reconcile(ctx context.Context, req ctr
139142 return ctrl.Result {}, err
140143 }
141144
145+ initialStatus := * instance .Status .DeepCopy ()
146+ if len (initialStatus .Conditions ) == 0 {
147+ instance .Status .Conditions = status .NewNUMAResourcesOperatorConditions ()
148+ } else {
149+ // on upgrade, backfill conditions added in newer versions
150+ instance .Status .Conditions = status .EnsureNUMAResourcesOperatorConditions (instance .Status .Conditions )
151+ }
152+
142153 if req .Name != objectnames .DefaultNUMAResourcesOperatorCrName {
143154 err := fmt .Errorf ("incorrect NUMAResourcesOperator resource name: %s" , instance .Name )
144155 return r .degradeStatus (ctx , instance , status .ConditionTypeIncorrectNUMAResourcesOperatorResourceName , err )
@@ -202,6 +213,11 @@ func updateStatusConditionsIfNeeded(instance *nropv1.NUMAResourcesOperator, cond
202213 ObservedGeneration : instance .Generation ,
203214 }, time .Now ())
204215 if ok {
216+ for _ , c := range instance .Status .Conditions {
217+ if status .FindCondition (conditions , c .Type ) == nil {
218+ conditions = append (conditions , c )
219+ }
220+ }
205221 instance .Status .Conditions = conditions
206222 }
207223}
@@ -247,7 +263,7 @@ func (r *NUMAResourcesOperatorReconciler) reconcileResourceAPI(ctx context.Conte
247263func (r * NUMAResourcesOperatorReconciler ) reconcileResourceMachineConfig (ctx context.Context , instance * nropv1.NUMAResourcesOperator , existing * rtestate.ExistingManifests , trees []nodegroupv1.Tree ) intreconcile.Step {
248264 // we need to sync machine configs first and wait for the MachineConfigPool updates
249265 // before checking additional components for updates
250- mcpUpdatedFunc , err := r .syncMachineConfigs (ctx , instance , existing , trees )
266+ waitByPool , pausedMCPNames , err := r .syncMachineConfigs (ctx , instance , existing , trees )
251267 if err != nil {
252268 r .Recorder .Eventf (instance , corev1 .EventTypeWarning , "FailedMCSync" , "Failed to set up machine configuration for worker nodes: %v" , err )
253269 err = fmt .Errorf ("failed to sync machine configs: %w" , err )
@@ -257,8 +273,9 @@ func (r *NUMAResourcesOperatorReconciler) reconcileResourceMachineConfig(ctx con
257273
258274 // MCO needs to update the SELinux context removal and other stuff, and need to trigger a reboot.
259275 // It can take a while.
260- mcpStatuses , mcpNamePending := syncMachineConfigPoolsStatuses (instance .Name , trees , r .ForwardMCPConds , mcpUpdatedFunc )
276+ mcpStatuses , mcpNamePending := syncMachineConfigPoolsStatuses (instance .Name , trees , r .ForwardMCPConds , waitByPool )
261277 instance .Status .MachineConfigPools = mcpStatuses
278+ instance .Status .Conditions = updateMachineConfigPoolPausedCondition (instance .Status .Conditions , instance .Generation , pausedMCPNames )
262279
263280 if mcpNamePending != "" {
264281 // the Machine Config Pool still did not apply the machine config, wait for one minute
@@ -305,7 +322,9 @@ func (r *NUMAResourcesOperatorReconciler) reconcileResource(ctx context.Context,
305322 existing := rtestate .FromClient (ctx , r .Client , r .Platform , r .RTEManifests , instance , trees , r .Namespace )
306323
307324 if r .Platform == platform .OpenShift {
308- if step := r .reconcileResourceMachineConfig (ctx , instance , existing , trees ); step .EarlyStop () {
325+ var step intreconcile.Step
326+ step = r .reconcileResourceMachineConfig (ctx , instance , existing , trees )
327+ if step .EarlyStop () {
309328 updateStatusConditionsIfNeeded (instance , step .ConditionInfo )
310329 return step
311330 }
@@ -408,7 +427,7 @@ func (r *NUMAResourcesOperatorReconciler) syncNodeResourceTopologyAPI(ctx contex
408427 return (updatedCount == len (objStates )), err
409428}
410429
411- func (r * NUMAResourcesOperatorReconciler ) syncMachineConfigs (ctx context.Context , instance * nropv1.NUMAResourcesOperator , existing * rtestate.ExistingManifests , trees []nodegroupv1.Tree ) (rtestate.MCPWaitForUpdatedFunc , error ) {
430+ func (r * NUMAResourcesOperatorReconciler ) syncMachineConfigs (ctx context.Context , instance * nropv1.NUMAResourcesOperator , existing * rtestate.ExistingManifests , trees []nodegroupv1.Tree ) (map [ string ] rtestate.MCPWaitForUpdatedFunc , sets. Set [ string ] , error ) {
412431 klog .V (4 ).InfoS ("Machine Config Sync start" , "trees" , len (trees ))
413432 defer klog .V (4 ).Info ("Machine Config Sync stop" )
414433
@@ -418,8 +437,11 @@ func (r *NUMAResourcesOperatorReconciler) syncMachineConfigs(ctx context.Context
418437 // In case of operator upgrade from 4.1X → 4.18, it's necessary to remove the old MachineConfig,
419438 // unless an emergency annotation is provided which forces the operator to use custom policy
420439
421- objStates , waitFunc := existing .MachineConfigsState (r .RTEManifests )
422- for _ , objState := range objStates {
440+ mcObjStates , pausedMCPNames := existing .MachineConfigsState (r .RTEManifests )
441+ waitByPool := make (map [string ]rtestate.MCPWaitForUpdatedFunc , len (mcObjStates ))
442+ for _ , mcObjState := range mcObjStates {
443+ waitByPool [mcObjState .PoolName ] = mcObjState .WaitForUpdated
444+ objState := mcObjState .ObjectState
423445 klog .InfoS ("objState" , "desired" , objState .Desired , "existing" , objState .Existing , "createOrUpdate" , objState .IsCreateOrUpdate ())
424446 if objState .IsCreateOrUpdate () {
425447 if err2 := controllerutil .SetControllerReference (instance , objState .Desired , r .Scheme ); err2 != nil {
@@ -438,19 +460,24 @@ func (r *NUMAResourcesOperatorReconciler) syncMachineConfigs(ctx context.Context
438460 break
439461 }
440462 }
441- return waitFunc , err
463+ return waitByPool , pausedMCPNames , err
442464}
443465
444- func syncMachineConfigPoolsStatuses (instanceName string , trees []nodegroupv1.Tree , forwardMCPConds bool , updatedFunc rtestate.MCPWaitForUpdatedFunc ) ([]nropv1.MachineConfigPool , string ) {
445- klog .V (4 ).InfoS ("Machine Config Status Sync start" , "trees" , len (trees ))
446- defer klog .V (4 ).Info ("Machine Config Status Sync stop" )
466+ func syncMachineConfigPoolsStatuses (instanceName string , trees []nodegroupv1.Tree , forwardMCPConds bool , waitByPool map [ string ] rtestate.MCPWaitForUpdatedFunc ) ([]nropv1.MachineConfigPool , string ) {
467+ klog .V (4 ).InfoS ("Machine Config Pools Status Sync start" , "trees" , len (trees ))
468+ defer klog .V (4 ).Info ("Machine Config Pools Status Sync stop" )
447469
448470 mcpStatuses := []nropv1.MachineConfigPool {}
449471 for _ , tree := range trees {
450472 for _ , mcp := range tree .MachineConfigPools {
451473 mcpStatuses = append (mcpStatuses , extractMCPStatus (mcp , forwardMCPConds ))
452474
453- isUpdated := updatedFunc (instanceName , mcp )
475+ waitFunc , ok := waitByPool [mcp .Name ]
476+ if ! ok {
477+ continue
478+ }
479+
480+ isUpdated := waitFunc (instanceName , mcp )
454481 klog .V (5 ).InfoS ("Machine Config Pool state" , "name" , mcp .Name , "instance" , instanceName , "updated" , isUpdated )
455482
456483 if ! isUpdated {
@@ -615,7 +642,8 @@ func (r *NUMAResourcesOperatorReconciler) SetupWithManager(mgr ctrl.Manager) err
615642 return ! reflect .DeepEqual (mcpOld .Status .Conditions , mcpNew .Status .Conditions ) ||
616643 ! apiequality .Semantic .DeepEqual (mcpOld .Labels , mcpNew .Labels ) ||
617644 ! apiequality .Semantic .DeepEqual (mcpOld .Spec .MachineConfigSelector , mcpNew .Spec .MachineConfigSelector ) ||
618- ! apiequality .Semantic .DeepEqual (mcpOld .Spec .NodeSelector , mcpNew .Spec .NodeSelector )
645+ ! apiequality .Semantic .DeepEqual (mcpOld .Spec .NodeSelector , mcpNew .Spec .NodeSelector ) ||
646+ mcpOld .Spec .Paused != mcpNew .Spec .Paused
619647 },
620648 }
621649
@@ -671,29 +699,35 @@ func (r *NUMAResourcesOperatorReconciler) mcpToNUMAResourceOperator(ctx context.
671699 nro := & nros .Items [i ]
672700 mcpLabels := labels .Set (mcp .Labels )
673701 for _ , nodeGroup := range nro .Spec .NodeGroups {
674- if nodeGroup .MachineConfigPoolSelector == nil {
675- continue
676- }
677-
678- nodeGroupSelector , err := metav1 .LabelSelectorAsSelector (nodeGroup .MachineConfigPoolSelector )
679- if err != nil {
680- klog .Errorf ("failed to parse the selector %v" , mcp .Spec .NodeSelector )
681- return nil
682- }
683-
684- if nodeGroupSelector .Matches (mcpLabels ) {
702+ if nodeGroupMatchesMCP (nodeGroup , mcp .Name , mcpLabels ) {
685703 requests = append (requests , reconcile.Request {
686704 NamespacedName : client.ObjectKey {
687705 Name : nro .Name ,
688706 },
689707 })
708+ break
690709 }
691710 }
692711 }
693712
694713 return requests
695714}
696715
716+ func nodeGroupMatchesMCP (nodeGroup nropv1.NodeGroup , mcpName string , mcpLabels labels.Set ) bool {
717+ if nodeGroup .PoolName != nil {
718+ return mcpName == * nodeGroup .PoolName
719+ }
720+ if nodeGroup .MachineConfigPoolSelector == nil {
721+ return false
722+ }
723+ selector , err := metav1 .LabelSelectorAsSelector (nodeGroup .MachineConfigPoolSelector )
724+ if err != nil {
725+ klog .Errorf ("failed to parse the selector %v" , nodeGroup .MachineConfigPoolSelector )
726+ return false
727+ }
728+ return selector .Matches (mcpLabels )
729+ }
730+
697731func (r * NUMAResourcesOperatorReconciler ) configMapToNUMAResourceOperator (ctx context.Context , cmObj client.Object ) []reconcile.Request {
698732 cm := & corev1.ConfigMap {}
699733
@@ -806,6 +840,26 @@ func isDaemonSetReady(ds *appsv1.DaemonSet) bool {
806840 return ds .Status .DesiredNumberScheduled > 0 && ds .Status .DesiredNumberScheduled == ds .Status .NumberReady
807841}
808842
843+ func updateMachineConfigPoolPausedCondition (conditions []metav1.Condition , generation int64 , pausedMCPNames sets.Set [string ]) []metav1.Condition {
844+ pausedStatus := metav1 .ConditionFalse
845+ message := ""
846+ if pausedMCPNames .Len () > 0 {
847+ klog .InfoS ("detected paused MCPs" , "pausedMCPs" , pausedMCPNames )
848+ pausedStatus = metav1 .ConditionTrue
849+ message = "detected paused MCPs: " + strings .Join (pausedMCPNames .UnsortedList (), ", " )
850+ }
851+ condition := metav1.Condition {
852+ Type : status .ConditionMachineConfigPoolPaused ,
853+ Status : pausedStatus ,
854+ Reason : status .ConditionMachineConfigPoolPaused ,
855+ Message : message ,
856+ ObservedGeneration : generation ,
857+ LastTransitionTime : metav1 .Now (),
858+ }
859+ apimeta .SetStatusCondition (& conditions , condition )
860+ return conditions
861+ }
862+
809863func getTreesByNodeGroup (ctx context.Context , cli client.Client , nodeGroups []nropv1.NodeGroup , platf platform.Platform ) ([]nodegroupv1.Tree , error ) {
810864 switch platf {
811865 case platform .OpenShift :
0 commit comments