@@ -30,6 +30,7 @@ import (
3030 "k8s.io/apimachinery/pkg/api/equality"
3131 apierrors "k8s.io/apimachinery/pkg/api/errors"
3232 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33+ "k8s.io/apimachinery/pkg/types"
3334 utilerrors "k8s.io/apimachinery/pkg/util/errors"
3435 "k8s.io/apimachinery/pkg/util/sets"
3536 "k8s.io/client-go/informers"
@@ -94,6 +95,7 @@ type InstallerController struct {
9495 configMapsGetter corev1client.ConfigMapsGetter
9596 secretsGetter corev1client.SecretsGetter
9697 podsGetter corev1client.PodsGetter
98+ nodesGetter corev1client.NodesGetter
9799 eventRecorder events.Recorder
98100 now func () time.Time // for test plumbing
99101
@@ -183,6 +185,7 @@ func NewInstallerController(
183185 configMapsGetter corev1client.ConfigMapsGetter ,
184186 secretsGetter corev1client.SecretsGetter ,
185187 podsGetter corev1client.PodsGetter ,
188+ nodesGetter corev1client.NodesGetter ,
186189 eventRecorder events.Recorder ,
187190) * InstallerController {
188191 c := & InstallerController {
@@ -197,6 +200,7 @@ func NewInstallerController(
197200 configMapsGetter : configMapsGetter ,
198201 secretsGetter : secretsGetter ,
199202 podsGetter : podsGetter ,
203+ nodesGetter : nodesGetter ,
200204 eventRecorder : eventRecorder .WithComponentSuffix ("installer-controller" ),
201205 now : time .Now ,
202206 startupMonitorEnabled : func () (bool , error ) {
@@ -494,6 +498,14 @@ func (c *InstallerController) manageInstallationPods(ctx context.Context, operat
494498 nodeChoiceReason = fmt .Sprintf ("node %s is the next node in the line" , currNodeState .NodeName )
495499 }
496500
501+ // Verify the node UID matches the actual node before updating its status.
502+ // A UID mismatch means the node was replaced and the node controller will handle resetting status.
503+ if uidChanged , uidErr := c .hasNodeUIDChanged (ctx , currNodeState .NodeName , currNodeState .NodeUID ); uidErr != nil {
504+ return true , 0 , nil , nil , uidErr
505+ } else if uidChanged {
506+ return true , c .installerBackOff (1 ), nil , nil , nil
507+ }
508+
497509 // if we are in a transition, check to see whether our installer pod completed
498510 if currNodeState .TargetRevision > currNodeState .CurrentRevision {
499511 if operatorStatus .LatestAvailableRevision > currNodeState .TargetRevision {
@@ -599,6 +611,7 @@ func prepareNodeStatusApplyConfigurationFor(nodeStatuses []operatorv1.NodeStatus
599611func nodeStatusToNodeStatusApplyConfigurations (nodeStatus operatorv1.NodeStatus ) * applyoperatorv1.NodeStatusApplyConfiguration {
600612 nodeStatusApplyConfiguration := applyoperatorv1 .NodeStatus ().
601613 WithNodeName (nodeStatus .NodeName ).
614+ WithNodeUID (nodeStatus .NodeUID ).
602615 WithCurrentRevision (nodeStatus .CurrentRevision ).
603616 WithTargetRevision (nodeStatus .TargetRevision ).
604617 WithLastFailedRevision (nodeStatus .LastFailedRevision ).
@@ -615,6 +628,7 @@ func nodeStatusToNodeStatusApplyConfigurations(nodeStatus operatorv1.NodeStatus)
615628func nodeStatusApplyConfigToOperatorNodeStatus (nodeStatusApplyConfiguration * applyoperatorv1.NodeStatusApplyConfiguration ) * operatorv1.NodeStatus {
616629 return & operatorv1.NodeStatus {
617630 NodeName : ptr .Deref (nodeStatusApplyConfiguration .NodeName , "" ),
631+ NodeUID : ptr .Deref (nodeStatusApplyConfiguration .NodeUID , "" ),
618632 CurrentRevision : ptr .Deref (nodeStatusApplyConfiguration .CurrentRevision , 0 ),
619633 TargetRevision : ptr .Deref (nodeStatusApplyConfiguration .TargetRevision , 0 ),
620634 LastFailedRevision : ptr .Deref (nodeStatusApplyConfiguration .LastFailedRevision , 0 ),
@@ -1123,6 +1137,25 @@ func (c InstallerController) ensureRequiredResourcesExist(ctx context.Context, r
11231137 return fmt .Errorf ("missing required resources: %v" , aggregatedErr )
11241138}
11251139
1140+ func (c * InstallerController ) hasNodeUIDChanged (ctx context.Context , nodeName string , nodeUid types.UID ) (bool , error ) {
1141+ if nodeUid == "" {
1142+ return false , nil
1143+ }
1144+ node , err := c .nodesGetter .Nodes ().Get (ctx , nodeName , metav1.GetOptions {})
1145+ if apierrors .IsNotFound (err ) {
1146+ klog .Warningf ("Skipping node status update for %s: node not found" , nodeName )
1147+ return true , nil
1148+ }
1149+ if err != nil {
1150+ return false , err
1151+ }
1152+ if node .UID != nodeUid {
1153+ klog .Warningf ("Skipping node status update for %s: node UID changed (stored=%s, actual=%s)" , nodeName , nodeUid , node .UID )
1154+ return true , nil
1155+ }
1156+ return false , nil
1157+ }
1158+
11261159func (c * InstallerController ) Sync (ctx context.Context , syncCtx factory.SyncContext ) error {
11271160 operatorSpec , originalOperatorStatus , operatorResourceVersion , err := c .operatorClient .GetStaticPodOperatorState ()
11281161 if err != nil {
@@ -1204,6 +1237,7 @@ func deepCopyNodeStatusWithoutOldFailedState(ns *operatorv1.NodeStatus) *operato
12041237 if ns .TargetRevision == 0 || ns .TargetRevision != ns .LastFailedRevision {
12051238 return & operatorv1.NodeStatus {
12061239 NodeName : ns .NodeName ,
1240+ NodeUID : ns .NodeUID ,
12071241 CurrentRevision : ns .CurrentRevision ,
12081242 TargetRevision : ns .TargetRevision ,
12091243 }
0 commit comments