Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Allow FirmwareUpdates via Servicing with HostUpdatePolicy #2044

Merged
merged 1 commit into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions controllers/metal3.io/baremetalhost_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1373,10 +1373,13 @@ func (r *BareMetalHostReconciler) doServiceIfNeeded(prov provisioner.Provisioner

var fwDirty bool
var hfsDirty bool
var liveFirmwareSettingsAllowed bool
var hfcDirty bool
var hfc *metal3api.HostFirmwareComponents
var liveFirmwareSettingsAllowed, liveFirmwareUpdatesAllowed bool

if hup != nil {
liveFirmwareSettingsAllowed = (hup.Spec.FirmwareSettings == metal3api.HostUpdatePolicyOnReboot)
liveFirmwareUpdatesAllowed = (hup.Spec.FirmwareUpdates == metal3api.HostUpdatePolicyOnReboot)
}

if liveFirmwareSettingsAllowed {
Expand All @@ -1398,7 +1401,18 @@ func (r *BareMetalHostReconciler) doServiceIfNeeded(prov provisioner.Provisioner
}
}

iurygregory marked this conversation as resolved.
Show resolved Hide resolved
hasChanges := fwDirty || hfsDirty
if liveFirmwareUpdatesAllowed {
var err error
hfcDirty, hfc, err = r.getHostFirmwareComponents(info)
if err != nil {
return actionError{fmt.Errorf("could not determine firmware components: %w", err)}
}
if hfcDirty {
servicingData.TargetFirmwareComponents = hfc.Spec.Updates
}
}

hasChanges := fwDirty || hfsDirty || hfcDirty

// Even if settings are clean, we need to check the result of the current servicing.
if !hasChanges && info.host.Status.OperationalStatus != metal3api.OperationalStatusServicing && info.host.Status.ErrorType != metal3api.ServicingError {
Expand All @@ -1422,6 +1436,12 @@ func (r *BareMetalHostReconciler) doServiceIfNeeded(prov provisioner.Provisioner
}
if provResult.ErrorMessage != "" {
info.host.Status.Provisioning.Firmware = nil
if hfcDirty && hfc.Status.Updates != nil {
hfc.Status.Updates = nil
iurygregory marked this conversation as resolved.
Show resolved Hide resolved
if err := r.Status().Update(info.ctx, hfc); err != nil {
return actionError{errors.Wrap(err, "failed to update hostfirmwarecomponents status")}
}
}
result = recordActionFailure(info, metal3api.ServicingError, provResult.ErrorMessage)
return result
}
Expand All @@ -1433,6 +1453,19 @@ func (r *BareMetalHostReconciler) doServiceIfNeeded(prov provisioner.Provisioner
dirty = true
}

if hfcDirty && started {
hfcDirty, err = r.saveHostFirmwareComponents(prov, info, hfc)
if err != nil {
return actionError{errors.Wrap(err, "could not save the host firmware components")}
}

if hfcDirty {
if err := r.Status().Update(info.ctx, hfc); err != nil {
dtantsur marked this conversation as resolved.
Show resolved Hide resolved
return actionError{errors.Wrap(err, "failed to update hostfirmwarecomponents status")}
}
}
}

resultAction := actionContinue{delay: provResult.RequeueAfter}
if dirty {
return actionUpdate{resultAction}
Expand Down
26 changes: 13 additions & 13 deletions pkg/provisioner/ironic/ironic.go
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,18 @@ func (p *ironicProvisioner) getNewFirmwareSettings(actualFirmwareSettings metal3
return newSettings
}

// getFirmwareComponentsUpdates extract the updates in a format that ironic accepts [{"component":"...", "url":"..."}, {"component":"...","url":".."}].
func (p *ironicProvisioner) getFirmwareComponentsUpdates(targetFirmwareComponents []metal3api.FirmwareUpdate) (newUpdates []map[string]string) {
for _, update := range targetFirmwareComponents {
newComponentUpdate := map[string]string{
"component": update.Component,
"url": update.URL,
}
newUpdates = append(newUpdates, newComponentUpdate)
}
return newUpdates
}

func (p *ironicProvisioner) buildManualCleaningSteps(bmcAccess bmc.AccessDetails, data provisioner.PrepareData) (cleanSteps []nodes.CleanStep, err error) {
// Build raid clean steps
raidCleanSteps, err := BuildRAIDCleanSteps(bmcAccess.RAIDInterface(), data.TargetRAIDConfig, data.ActualRAIDConfig)
Expand Down Expand Up @@ -1249,19 +1261,7 @@ func (p *ironicProvisioner) buildManualCleaningSteps(bmcAccess bmc.AccessDetails
)
}

// extract to generate the updates that will trigger a clean step
// the format we send to ironic is:
// [{"component":"...", "url":"..."}, {"component":"...","url":".."}]
var newUpdates []map[string]string
if data.TargetFirmwareComponents != nil {
for _, update := range data.TargetFirmwareComponents {
newComponentUpdate := map[string]string{
"component": update.Component,
"url": update.URL,
}
newUpdates = append(newUpdates, newComponentUpdate)
}
}
newUpdates := p.getFirmwareComponentsUpdates(data.TargetFirmwareComponents)

if len(newUpdates) != 0 {
p.log.Info("Applying Firmware Update clean steps", "settings", newUpdates)
Expand Down
17 changes: 15 additions & 2 deletions pkg/provisioner/ironic/servicing.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,22 @@ func (p *ironicProvisioner) buildServiceSteps(bmcAccess bmc.AccessDetails, data
)
}

// TODO: Add service steps for firmware updates
newUpdates := p.getFirmwareComponentsUpdates(data.TargetFirmwareComponents)
dtantsur marked this conversation as resolved.
Show resolved Hide resolved
if len(newUpdates) != 0 {
p.log.Info("Applying Firmware Update clean steps", "settings", newUpdates)
serviceSteps = append(
serviceSteps,
nodes.ServiceStep{
Interface: nodes.InterfaceFirmware,
Step: "update",
Args: map[string]interface{}{
"settings": newUpdates,
},
},
)
}

return
return serviceSteps, nil
}

func (p *ironicProvisioner) startServicing(bmcAccess bmc.AccessDetails, ironicNode *nodes.Node, data provisioner.ServicingData) (success bool, result provisioner.Result, err error) {
Expand Down
8 changes: 4 additions & 4 deletions pkg/provisioner/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ type PrepareData struct {
}

type ServicingData struct {
FirmwareConfig *metal3api.FirmwareConfig
TargetFirmwareSettings metal3api.DesiredSettingsMap
ActualFirmwareSettings metal3api.SettingsMap
// TargetFirmwareComponents []metal3api.FirmwareUpdate
FirmwareConfig *metal3api.FirmwareConfig
TargetFirmwareSettings metal3api.DesiredSettingsMap
ActualFirmwareSettings metal3api.SettingsMap
TargetFirmwareComponents []metal3api.FirmwareUpdate
iurygregory marked this conversation as resolved.
Show resolved Hide resolved
}

type ProvisionData struct {
Expand Down
Loading