@@ -19,7 +19,9 @@ package machinepool
1919import (
2020 "context"
2121 "fmt"
22+ "time"
2223
24+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2325 "k8s.io/utils/ptr"
2426 ctrl "sigs.k8s.io/controller-runtime"
2527
@@ -41,7 +43,8 @@ func (r *Reconciler) updateStatus(ctx context.Context, s *scope) error {
4143
4244 setReplicas (s .machinePool , hasMachinePoolMachines , s .machines )
4345
44- // TODO: in future add setting conditions here
46+ // Set MachinesUpToDate condition to surface when machines are not up-to-date with the spec.
47+ setMachinesUpToDateCondition (ctx , s .machinePool , s .machines , hasMachinePoolMachines )
4548
4649 return nil
4750}
@@ -73,3 +76,77 @@ func setReplicas(mp *clusterv1.MachinePool, hasMachinePoolMachines bool, machine
7376 mp .Status .AvailableReplicas = ptr .To (availableReplicas )
7477 mp .Status .UpToDateReplicas = ptr .To (upToDateReplicas )
7578}
79+
80+ // setMachinesUpToDateCondition sets the MachinesUpToDate condition on the MachinePool.
81+ func setMachinesUpToDateCondition (ctx context.Context , mp * clusterv1.MachinePool , machines []* clusterv1.Machine , hasMachinePoolMachines bool ) {
82+ log := ctrl .LoggerFrom (ctx )
83+
84+ // For MachinePool providers that don't use Machine objects (like managed pools),
85+ // we derive the MachinesUpToDate condition from the infrastructure status.
86+ // If InfrastructureReady is False, machines are not up-to-date.
87+ if ! hasMachinePoolMachines {
88+ // Check if infrastructure is ready by looking at the initialization status
89+ if mp .Status .Initialization .InfrastructureProvisioned == nil || ! * mp .Status .Initialization .InfrastructureProvisioned {
90+ conditions .Set (mp , metav1.Condition {
91+ Type : clusterv1 .MachinesUpToDateCondition ,
92+ Status : metav1 .ConditionFalse ,
93+ Reason : clusterv1 .NotUpToDateReason ,
94+ Message : "Infrastructure is not yet provisioned" ,
95+ })
96+ return
97+ }
98+
99+ conditions .Set (mp , metav1.Condition {
100+ Type : clusterv1 .MachinesUpToDateCondition ,
101+ Status : metav1 .ConditionTrue ,
102+ Reason : clusterv1 .UpToDateReason ,
103+ })
104+ return
105+ }
106+
107+ // Only consider Machines that have an UpToDate condition or are older than 10s.
108+ // This is done to ensure the MachinesUpToDate condition doesn't flicker after a new Machine is created,
109+ // because it can take a bit until the UpToDate condition is set on a new Machine.
110+ filteredMachines := make ([]* clusterv1.Machine , 0 , len (machines ))
111+ for _ , machine := range machines {
112+ if conditions .Has (machine , clusterv1 .MachineUpToDateCondition ) || time .Since (machine .CreationTimestamp .Time ) > 10 * time .Second {
113+ filteredMachines = append (filteredMachines , machine )
114+ }
115+ }
116+
117+ if len (filteredMachines ) == 0 {
118+ conditions .Set (mp , metav1.Condition {
119+ Type : clusterv1 .MachinesUpToDateCondition ,
120+ Status : metav1 .ConditionTrue ,
121+ Reason : clusterv1 .NoReplicasReason ,
122+ })
123+ return
124+ }
125+
126+ upToDateCondition , err := conditions .NewAggregateCondition (
127+ filteredMachines , clusterv1 .MachineUpToDateCondition ,
128+ conditions .TargetConditionType (clusterv1 .MachinesUpToDateCondition ),
129+ // Using a custom merge strategy to override reasons applied during merge.
130+ conditions.CustomMergeStrategy {
131+ MergeStrategy : conditions .DefaultMergeStrategy (
132+ conditions .ComputeReasonFunc (conditions .GetDefaultComputeMergeReasonFunc (
133+ clusterv1 .NotUpToDateReason ,
134+ clusterv1 .UpToDateUnknownReason ,
135+ clusterv1 .UpToDateReason ,
136+ )),
137+ ),
138+ },
139+ )
140+ if err != nil {
141+ log .Error (err , "Failed to aggregate Machine's UpToDate conditions" )
142+ conditions .Set (mp , metav1.Condition {
143+ Type : clusterv1 .MachinesUpToDateCondition ,
144+ Status : metav1 .ConditionUnknown ,
145+ Reason : clusterv1 .InternalErrorReason ,
146+ Message : "Please check controller logs for errors" ,
147+ })
148+ return
149+ }
150+
151+ conditions .Set (mp , * upToDateCondition )
152+ }
0 commit comments