@@ -234,8 +234,16 @@ func (r *BiosSettingsReconciler) ensureServerMaintenanceStateTransition(
234234) (ctrl.Result , error ) {
235235 switch biosSettings .Status .State {
236236 case "" , metalv1alpha1 .BIOSSettingsStatePending :
237- //todo: check that in initial state there is no pending BIOS maintenance left behind
238- err := r .updateBiosSettingsStatus (ctx , log , biosSettings , metalv1alpha1 .BIOSSettingsStateInProgress )
237+ pendingPresent , pendingSettings , err := r .checkforPendingSettingsOnBIOS (ctx , log , server , nil )
238+ if err != nil {
239+ return ctrl.Result {}, fmt .Errorf ("failed to get pending settings on bios: %w" , err )
240+ }
241+ if len (pendingSettings ) > 0 || pendingPresent {
242+ log .V (1 ).Info ("Pending bios setting tasks found" , "biosSettings pending tasks" , pendingSettings )
243+ err := r .updateBiosSettingsStatus (ctx , log , biosSettings , metalv1alpha1 .BIOSSettingsStateFailed )
244+ return ctrl.Result {}, err
245+ }
246+ err = r .updateBiosSettingsStatus (ctx , log , biosSettings , metalv1alpha1 .BIOSSettingsStateInProgress )
239247 return ctrl.Result {}, err
240248 case metalv1alpha1 .BIOSSettingsStateInProgress :
241249 return r .handleSettingInProgressState (ctx , log , biosSettings , server )
@@ -256,11 +264,9 @@ func (r *BiosSettingsReconciler) handleSettingInProgressState(
256264) (ctrl.Result , error ) {
257265
258266 currentBiosVersion , settingsDiff , err := r .getBIOSVersionAndSettingDifference (ctx , log , biosSettings , server )
259-
260267 if err != nil {
261268 return ctrl.Result {}, fmt .Errorf ("failed to get BIOS settings: %w" , err )
262269 }
263-
264270 // if setting is not different, complete the BIOS tasks, does not matter if the bios version do not match
265271 if len (settingsDiff ) == 0 {
266272 // move status to completed
@@ -344,16 +350,43 @@ func (r *BiosSettingsReconciler) applySettingUpdateStateTransition(
344350 log .V (1 ).Info ("Reconciled biosSettings at Pending state" )
345351 return ctrl.Result {}, err
346352 case metalv1alpha1 .BIOSSettingUpdateStateIssue :
347- // todo: make it idepotent
348353 bmcClient , err := bmcutils .GetBMCClientForServer (ctx , r .Client , server , r .Insecure , r .BMCOptions )
349354 if err != nil {
350355 return ctrl.Result {}, err
351356 }
352357 defer bmcClient .Logout ()
353358
354- err = bmcClient .SetBiosAttributesOnReset (ctx , server .Spec .SystemUUID , settingsDiff )
359+ // check if the pending tasks not present on the bios settings
360+ pendingPresent , _ , err := r .checkforPendingSettingsOnBIOS (ctx , log , server , nil )
355361 if err != nil {
356- return ctrl.Result {}, fmt .Errorf ("failed to set BMC settings: %w" , err )
362+ return ctrl.Result {}, fmt .Errorf ("failed to get pending BIOS settings: %w" , err )
363+ }
364+ var pendingSettingsDiff redfish.SettingsAttributes
365+ if ! pendingPresent {
366+ err = bmcClient .SetBiosAttributesOnReset (ctx , server .Spec .SystemUUID , settingsDiff )
367+ if err != nil {
368+ return ctrl.Result {}, fmt .Errorf ("failed to set BMC settings: %w" , err )
369+ }
370+ }
371+
372+ // get latest pending settings, and expect it to be zero different from the required settings.
373+ pendingPresent , pendingSettingsDiff , err = r .checkforPendingSettingsOnBIOS (ctx , log , server , settingsDiff )
374+ if err != nil {
375+ return ctrl.Result {}, fmt .Errorf ("failed to get pending BIOS settings: %w" , err )
376+ }
377+
378+ // at this point the bios setting update needs to be already issued.
379+ if ! pendingPresent {
380+ // todo: fail after X amount of time
381+ log .V (1 ).Info ("bios Setting update issued to bmc not accepted. retrying...." )
382+ return ctrl.Result {}, errors .Join (err , fmt .Errorf ("bios setting issued to bmc not accepted" ))
383+ }
384+
385+ // latest pending settings to be zero different from the required settings.
386+ if len (pendingSettingsDiff ) > 0 {
387+ log .V (1 ).Info ("Unknown pending BIOS settings found" , "Unknown pending settings" , pendingSettingsDiff )
388+ err := r .updateBiosSettingsStatus (ctx , log , biosSettings , metalv1alpha1 .BIOSSettingsStateFailed )
389+ return ctrl.Result {}, err
357390 }
358391
359392 // if we dont need (have not requested maintenance) reboot. skip reboot steps.
@@ -367,7 +400,6 @@ func (r *BiosSettingsReconciler) applySettingUpdateStateTransition(
367400 return ctrl.Result {}, err
368401 case metalv1alpha1 .BIOSSettingUpdateWaitOnServerRebootPowerOff :
369402 // expected state it to be off and initial state is to be on.
370- // todo: check that the BIOSSettings setting is actually been issued.
371403 if r .checkForRequiredPowerStatus (server , metalv1alpha1 .ServerOnPowerState ) {
372404 err := r .patchServerMaintenancePowerState (ctx , log , biosSettings , metalv1alpha1 .PowerOff )
373405 if err != nil {
@@ -382,7 +414,6 @@ func (r *BiosSettingsReconciler) applySettingUpdateStateTransition(
382414 return ctrl.Result {}, nil
383415 case metalv1alpha1 .BIOSSettingUpdateWaitOnServerRebootPowerOn :
384416 // expected power state it to be on and initial state is to be off.
385- // todo: check that the BIOSSettings setting is actually been issued.
386417 if r .checkForRequiredPowerStatus (server , metalv1alpha1 .ServerOffPowerState ) {
387418 err := r .patchServerMaintenancePowerState (ctx , log , biosSettings , metalv1alpha1 .PowerOn )
388419 if err != nil {
@@ -408,6 +439,7 @@ func (r *BiosSettingsReconciler) applySettingUpdateStateTransition(
408439 err := r .updateBiosSettingsStatus (ctx , log , biosSettings , metalv1alpha1 .BIOSSettingsStateApplied )
409440 return ctrl.Result {}, err
410441 }
442+ // todo: can take some time to setting to take place. might need to fail after certain time.
411443 log .V (1 ).Info ("Reconciled biosSettings at wait for verification" )
412444 return ctrl.Result {}, fmt .Errorf ("waiting on the BIOS setting to take place" )
413445 }
@@ -454,6 +486,42 @@ func (r *BiosSettingsReconciler) handleFailedState(
454486 return ctrl.Result {}, nil
455487}
456488
489+ func (r * BiosSettingsReconciler ) checkforPendingSettingsOnBIOS (
490+ ctx context.Context ,
491+ log logr.Logger ,
492+ server * metalv1alpha1.Server ,
493+ settingsDiff redfish.SettingsAttributes ,
494+ ) (pendingSettingPresent bool , pendingSettingsDiff redfish.SettingsAttributes , err error ) {
495+ bmcClient , err := bmcutils .GetBMCClientForServer (ctx , r .Client , server , r .Insecure , r .BMCOptions )
496+ if err != nil {
497+ return pendingSettingPresent , pendingSettingsDiff , fmt .Errorf ("failed to create BMC client: %w" , err )
498+ }
499+ defer bmcClient .Logout ()
500+
501+ pendingSettingsDiff , err = bmcClient .GetPendingAttributeValues (ctx , server .Spec .SystemUUID )
502+ if err != nil {
503+ return pendingSettingPresent , pendingSettingsDiff , err
504+ }
505+ pendingSettingPresent = len (pendingSettingsDiff ) > 0
506+
507+ // if settingsDiff is provided find the difference between settingsDiff and pending
508+ if len (settingsDiff ) > 0 {
509+ log .V (1 ).Info ("checking for the difference in the pending settings than that of required" )
510+ if ! pendingSettingPresent {
511+ return pendingSettingPresent , settingsDiff , nil
512+ }
513+ unknownpendingSettings := make (redfish.SettingsAttributes , len (settingsDiff ))
514+ for name , value := range settingsDiff {
515+ if pendingValue , ok := pendingSettingsDiff [name ]; ok && value != pendingValue {
516+ unknownpendingSettings [name ] = pendingValue
517+ }
518+ }
519+ return pendingSettingPresent , unknownpendingSettings , nil
520+ }
521+
522+ return pendingSettingPresent , pendingSettingsDiff , nil
523+ }
524+
457525func (r * BiosSettingsReconciler ) getBIOSVersionAndSettingDifference (
458526 ctx context.Context ,
459527 log logr.Logger ,
0 commit comments