@@ -174,59 +174,61 @@ func (r *ReconcileMachineSet) Reconcile(ctx context.Context, request reconcile.R
174
174
}
175
175
176
176
if r .gate .Enabled (featuregate .Feature (openshiftfeatures .FeatureGateMachineAPIMigration )) {
177
- machineSetName := machineSet .GetName ()
178
- machineSetCopy := machineSet .DeepCopy ()
179
- // Check Status.AuthoritativeAPI. If it's not set to MachineAPI. Set the
180
- // paused condition true and return early.
181
- //
182
- // Once we have a webhook, we want to remove the check that the AuthoritativeAPI
183
- // field is populated.
184
- if machineSet .Status .AuthoritativeAPI != "" &&
185
- machineSet .Status .AuthoritativeAPI != machinev1 .MachineAuthorityMachineAPI {
186
- conditions .Set (machineSetCopy , conditions .TrueConditionWithReason (
187
- machine .PausedCondition ,
188
- machine .PausedConditionReason ,
189
- "The AuthoritativeAPI is set to %s" , string (machineSet .Status .AuthoritativeAPI ),
190
- ))
191
-
192
- _ , err := updateMachineSetStatus (r .Client , machineSet , machineSetCopy .Status )
193
- if err != nil && ! apierrors .IsNotFound (err ) {
194
- klog .Errorf ("%v: error updating status: %v" , machineSetName , err )
195
- return reconcile.Result {}, fmt .Errorf ("error updating status: %w" , err )
196
- } else if apierrors .IsNotFound (err ) {
197
- return reconcile.Result {}, nil
177
+ switch machineSet .Status .AuthoritativeAPI {
178
+ case "" :
179
+ // An empty .status.authoritativeAPI normally means the resource has not yet been reconciled.
180
+ // and that the value in .spec.authoritativeAPI has not been propagated to .status.authoritativeAPI yet.
181
+ // This value can be set by two separate controllers, depending which one of them is running at that time,
182
+ // or in case they are both running, which one gets to set it first (the operation is idempotent so there is no harm in racing).
183
+ // - the cluster-capi-operator machine-api-migration's migration controller
184
+ // - this controller
185
+
186
+ klog .Infof ("%v: machine set .status.authoritativeAPI is not yet set, setting it to .spec.authoritativeAPI" , machineSet .Name )
187
+
188
+ if err := r .patchStatusAuthoritativeAPI (ctx , machineSet , machineSet .Spec .AuthoritativeAPI ); err != nil {
189
+ klog .Errorf ("%v: error patching status to set .status.authoritativeAPI for machine set: %v" , machineSet .Name , err )
190
+ return reconcile.Result {}, fmt .Errorf ("error patching status to set .status.authoritativeAPI for machine set %s: %w" , machineSet .Name , err )
198
191
}
199
192
200
- klog . Infof ( "%v: machine set is paused, taking no further action" , machineSetName )
193
+ // Return to give a chance to the changes to get propagated.
201
194
return reconcile.Result {}, nil
202
- }
203
195
204
- var pausedFalseReason string
205
- if machineSet .Status .AuthoritativeAPI != "" {
206
- pausedFalseReason = fmt .Sprintf ("The AuthoritativeAPI is set to %s" , string (machineSet .Status .AuthoritativeAPI ))
207
- } else {
208
- pausedFalseReason = "The AuthoritativeAPI is not set"
209
- }
196
+ case machinev1 .MachineAuthorityClusterAPI , machinev1 .MachineAuthorityMigrating :
197
+ // In case .status.authoritativeAPI is set to machinev1.MachineAuthorityClusterAPI, machinev1.MachineAuthorityMigrating
198
+ // the resource should be paused and not reconciled further.
199
+ desiredCondition := conditions .TrueConditionWithReason (
200
+ machine .PausedCondition , machine .PausedConditionReason ,
201
+ "The AuthoritativeAPI status is set to '%s'" , string (machineSet .Status .AuthoritativeAPI ),
202
+ )
203
+
204
+ if _ , err := r .ensureUpdatedPausedCondition (machineSet , desiredCondition ,
205
+ fmt .Sprintf ("%v: machine set .status.authoritativeAPI is set to '%s', ensuring machine set is paused" , machineSet .Name , machineSet .Status .AuthoritativeAPI )); err != nil {
206
+ return reconcile.Result {}, fmt .Errorf ("failed to ensure paused condition: %w" , err )
207
+ }
210
208
211
- // Set the paused condition to false, continue reconciliation
212
- conditions .Set (machineSetCopy , conditions .FalseCondition (
213
- machine .PausedCondition ,
214
- machine .NotPausedConditionReason ,
215
- machinev1 .ConditionSeverityInfo ,
216
- "%s" ,
217
- pausedFalseReason ,
218
- ))
209
+ klog .Infof ("%v: machine set is paused, taking no further action" , machineSet .Name )
219
210
220
- var err error
221
- machineSet , err = updateMachineSetStatus (r .Client , machineSet , machineSetCopy .Status )
222
- if err != nil && ! apierrors .IsNotFound (err ) {
223
- klog .Errorf ("%v: error updating status: %v" , machineSetName , err )
224
- return reconcile.Result {}, fmt .Errorf ("error updating status: %w" , err )
225
- } else if apierrors .IsNotFound (err ) {
226
211
return reconcile.Result {}, nil
227
- }
228
212
229
- klog .Infof ("%v: setting paused to false and continuing reconcile" , machineSetName )
213
+ case machinev1 .MachineAuthorityMachineAPI :
214
+ // The authority is MachineAPI and the resource should not be paused.
215
+ desiredCondition := conditions .FalseCondition (
216
+ machine .PausedCondition , machine .NotPausedConditionReason , machinev1 .ConditionSeverityInfo , "%s" ,
217
+ fmt .Sprintf ("The AuthoritativeAPI status is set to '%s'" , string (machineSet .Status .AuthoritativeAPI )),
218
+ )
219
+
220
+ if updated , err := r .ensureUpdatedPausedCondition (machineSet , desiredCondition ,
221
+ fmt .Sprintf ("%v: machine set .status.authoritativeAPI is set to '%s', unpausing machine set" , machineSet .Name , machineSet .Status .AuthoritativeAPI )); err != nil {
222
+ return reconcile.Result {}, fmt .Errorf ("failed to ensure paused condition: %w" , err )
223
+ } else if updated {
224
+ klog .Infof ("%v: setting machine set paused condition to false" , machineSet .Name )
225
+ }
226
+
227
+ // Fallthrough and continue reconciliation.
228
+ default :
229
+ klog .Errorf ("%v: invalid .status.authoritativeAPI '%s'" , machineSet .Name , machineSet .Status .AuthoritativeAPI )
230
+ return reconcile.Result {}, nil // Do not return an error to avoid immediate requeue.
231
+ }
230
232
}
231
233
232
234
result , err := r .reconcile (ctx , machineSet )
@@ -329,6 +331,23 @@ func (r *ReconcileMachineSet) reconcile(ctx context.Context, machineSet *machine
329
331
return reconcile.Result {}, nil
330
332
}
331
333
334
+ // ensureUpdatedPausedCondition updates the paused condition if needed.
335
+ func (r * ReconcileMachineSet ) ensureUpdatedPausedCondition (ms * machinev1.MachineSet , desiredCondition * machinev1.Condition , logMessage string ) (bool , error ) {
336
+ newMs := ms .DeepCopy ()
337
+ if ! conditions .IsEquivalentTo (conditions .Get (ms , machine .PausedCondition ), desiredCondition ) {
338
+ klog .Info (logMessage )
339
+ conditions .Set (newMs , desiredCondition )
340
+ if _ , err := updateMachineSetStatus (r .Client , ms , newMs .Status ); err != nil {
341
+ klog .Errorf ("%v: error updating status: %v" , newMs .Name , err )
342
+ return false , fmt .Errorf ("error updating status for machine set %s: %w" , newMs .Name , err )
343
+ }
344
+
345
+ return true , nil
346
+ }
347
+
348
+ return false , nil
349
+ }
350
+
332
351
// syncReplicas essentially scales machine resources up and down.
333
352
func (r * ReconcileMachineSet ) syncReplicas (ms * machinev1.MachineSet , machines []* machinev1.Machine ) error {
334
353
if ms .Spec .Replicas == nil {
@@ -500,6 +519,17 @@ func (r *ReconcileMachineSet) waitForMachineDeletion(machineList []*machinev1.Ma
500
519
return nil
501
520
}
502
521
522
+ func (r * ReconcileMachineSet ) patchStatusAuthoritativeAPI (ctx context.Context , machineSet * machinev1.MachineSet , authoritativeAPI machinev1.MachineAuthority ) error {
523
+ baseToPatch := client .MergeFrom (machineSet .DeepCopy ())
524
+ machineSet .Status .AuthoritativeAPI = authoritativeAPI
525
+
526
+ if err := r .Client .Status ().Patch (ctx , machineSet , baseToPatch ); err != nil {
527
+ return fmt .Errorf ("error patching machine set status: %w" , err )
528
+ }
529
+
530
+ return nil
531
+ }
532
+
503
533
func validateMachineset (m * machinev1.MachineSet ) field.ErrorList {
504
534
errors := field.ErrorList {}
505
535
0 commit comments