Skip to content

Commit fa57241

Browse files
iurygregorymetal3-io-bot
authored andcommitted
Fix Status logic for HostFirmwareComponents
Make Updates and Components optional in HostFirmwareComponentsStatus, so we don't get errors when they are empty. The UpdatedAt field for FirmwareComponentStatus can be nil, this caused runtime error in the BMO. Change logic in GetFirmwareComponents, so we fail earlier in case is not supported, now we raise a specific error ErrFirmwareUpdateUnsupported. Simplify the logic in the Controller, so we handle conditions in only one function Signed-off-by: Iury Gregory Melo Ferreira <imelofer@redhat.com>
1 parent 3086599 commit fa57241

7 files changed

Lines changed: 35 additions & 60 deletions

File tree

apis/metal3.io/v1alpha1/hostfirmwarecomponents_types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ type HostFirmwareComponentsSpec struct {
5656
type HostFirmwareComponentsStatus struct {
5757
// Updates is the list of all firmware components that should be updated
5858
// they are specified via name and url fields.
59+
// +optional
5960
Updates []FirmwareUpdate `json:"updates"`
6061

6162
// Components is the list of all available firmware components and their information.
62-
Components []FirmwareComponentStatus `json:"components"`
63+
Components []FirmwareComponentStatus `json:"components,omitempty"`
6364

6465
// Time that the status was last updated
6566
// +optional

config/base/crds/bases/metal3.io_hostfirmwarecomponents.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,6 @@ spec:
170170
- url
171171
type: object
172172
type: array
173-
required:
174-
- components
175-
- updates
176173
type: object
177174
type: object
178175
served: true

config/render/capm3.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,9 +1770,6 @@ spec:
17701770
- url
17711771
type: object
17721772
type: array
1773-
required:
1774-
- components
1775-
- updates
17761773
type: object
17771774
type: object
17781775
served: true

controllers/metal3.io/hostfirmwarecomponents_controller.go

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package controllers
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223
"reflect"
2324

@@ -151,23 +152,21 @@ func (r *HostFirmwareComponentsReconciler) Reconcile(ctx context.Context, req ct
151152
return ctrl.Result{Requeue: true, RequeueAfter: provisionerRetryDelay}, nil
152153
}
153154

154-
newStatus, err := r.updateHostFirmware(info)
155-
if err != nil {
156-
return ctrl.Result{}, fmt.Errorf("could not update hostfirmwarecomponents: %w", err)
157-
}
158-
155+
info.log.Info("retrieving firmware components and saving to resource", "Node", bmh.Status.Provisioning.ID)
159156
// Check ironic for the components information if possible
160157
components, err := prov.GetFirmwareComponents()
161-
info.log.Info("retrieving firmware components and saving to resource", "Node", bmh.Status.Provisioning.ID)
162158

163159
if err != nil {
164-
reqLogger.Error(err, "provisioner returns error", "RequeueAfter", provisionerRetryDelay)
165-
setUpdatesCondition(info.hfc.GetGeneration(), &newStatus, info, metal3api.HostFirmwareComponentsValid, metav1.ConditionFalse, reasonInvalidComponent, err.Error())
160+
if errors.Is(err, provisioner.ErrFirmwareUpdateUnsupported) {
161+
return ctrl.Result{Requeue: false}, err
162+
}
163+
reqLogger.Info("provisioner returns error", "Error", err.Error(), "RequeueAfter", provisionerRetryDelay)
166164
return ctrl.Result{Requeue: true, RequeueAfter: provisionerRetryDelay}, err
167165
}
168166

169-
if err = r.updateHostFirmwareComponents(newStatus, components, info); err != nil {
170-
return ctrl.Result{Requeue: false}, err
167+
if err = r.updateHostFirmware(info, components); err != nil {
168+
info.log.Info("updateHostFirmware returned error")
169+
return ctrl.Result{}, fmt.Errorf("could not update hostfirmwarecomponents: %w", err)
171170
}
172171

173172
for _, e := range info.events {
@@ -181,14 +180,19 @@ func (r *HostFirmwareComponentsReconciler) Reconcile(ctx context.Context, req ct
181180
}
182181

183182
// Update the HostFirmwareComponents resource using the components from provisioner.
184-
func (r *HostFirmwareComponentsReconciler) updateHostFirmware(info *rhfcInfo) (newStatus metal3api.HostFirmwareComponentsStatus, err error) {
183+
func (r *HostFirmwareComponentsReconciler) updateHostFirmware(info *rhfcInfo, components []metal3api.FirmwareComponentStatus) (err error) {
185184
dirty := false
186-
185+
var newStatus metal3api.HostFirmwareComponentsStatus
187186
// change the Updates in Status
188187
newStatus.Updates = info.hfc.Spec.Updates
188+
// change the Components in Status
189+
newStatus.Components = components
189190

190191
// Check if the updates in the Spec are different than Status
191192
updatesMismatch := !reflect.DeepEqual(info.hfc.Status.Updates, info.hfc.Spec.Updates)
193+
if len(info.hfc.Spec.Updates) == 0 && len(info.hfc.Status.Updates) == 0 {
194+
updatesMismatch = false
195+
}
192196

193197
reason := reasonValidComponent
194198
generation := info.hfc.GetGeneration()
@@ -222,32 +226,6 @@ func (r *HostFirmwareComponentsReconciler) updateHostFirmware(info *rhfcInfo) (n
222226
info.log.Info("Status for HostFirmwareComponents changed")
223227
info.hfc.Status = *newStatus.DeepCopy()
224228

225-
t := metav1.Now()
226-
info.hfc.Status.LastUpdated = &t
227-
return newStatus, r.Status().Update(info.ctx, info.hfc)
228-
}
229-
return newStatus, nil
230-
}
231-
232-
// Update the HostFirmwareComponents resource using the components from provisioner.
233-
func (r *HostFirmwareComponentsReconciler) updateHostFirmwareComponents(newStatus metal3api.HostFirmwareComponentsStatus, components []metal3api.FirmwareComponentStatus, info *rhfcInfo) (err error) {
234-
dirty := false
235-
// change the Components in Status
236-
newStatus.Components = components
237-
// Check if the components information we retrieved is different from the one in Status
238-
componentsInfoMismatch := !reflect.DeepEqual(components, info.hfc.Status.Components)
239-
reason := reasonValidComponent
240-
generation := info.hfc.GetGeneration()
241-
// Log the components we have
242-
info.log.Info("firmware components for node", "components", components, "bmh", info.bmh.Name)
243-
if componentsInfoMismatch {
244-
setUpdatesCondition(generation, &newStatus, info, metal3api.HostFirmwareComponentsChangeDetected, metav1.ConditionTrue, reason, "")
245-
dirty = true
246-
}
247-
if dirty {
248-
info.log.Info("Components Status for HostFirmwareComponents changed")
249-
info.hfc.Status = *newStatus.DeepCopy()
250-
251229
t := metav1.Now()
252230
info.hfc.Status.LastUpdated = &t
253231
return r.Status().Update(info.ctx, info.hfc)

controllers/metal3.io/hostfirmwarecomponents_test.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -425,12 +425,9 @@ func TestStoreHostFirmwareComponents(t *testing.T) {
425425
bmh: bmh,
426426
}
427427

428-
currentStatus, err := r.updateHostFirmware(info)
429-
assert.NoError(t, err)
430-
431428
components, err := prov.GetFirmwareComponents()
432429
assert.NoError(t, err)
433-
err = r.updateHostFirmwareComponents(currentStatus, components, info)
430+
err = r.updateHostFirmware(info, components)
434431
assert.NoError(t, err)
435432

436433
// Check that resources get created or updated

pkg/provisioner/ironic/ironic.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,21 +1162,20 @@ func (p *ironicProvisioner) GetFirmwareComponents() ([]metal3api.FirmwareCompone
11621162
if !p.availableFeatures.HasFirmwareUpdates() {
11631163
return nil, fmt.Errorf("current ironic version does not support firmware updates")
11641164
}
1165+
1166+
// Setting to 2 since we only support bmc and bios
1167+
componentsInfo := make([]metal3api.FirmwareComponentStatus, 0, 2)
1168+
1169+
if ironicNode.FirmwareInterface == "no-firmware" {
1170+
return componentsInfo, provisioner.ErrFirmwareUpdateUnsupported
1171+
}
11651172
// Get the components from Ironic via Gophercloud
11661173
componentList, componentListErr := nodes.ListFirmware(p.ctx, p.client, ironicNode.UUID).Extract()
11671174

1168-
if componentListErr != nil || len(componentList) == 0 {
1169-
bmcAccess, _ := p.bmcAccess()
1170-
if ironicNode.FirmwareInterface == "no-firmware" {
1171-
return nil, fmt.Errorf("driver %s does not support firmware updates", bmcAccess.Driver())
1172-
}
1173-
1175+
if componentListErr != nil {
11741176
return nil, fmt.Errorf("could not get firmware components for node %s: %w", ironicNode.UUID, componentListErr)
11751177
}
11761178

1177-
// Setting to 2 since we only support bmc and bios
1178-
componentsInfo := make([]metal3api.FirmwareComponentStatus, 0, 2)
1179-
11801179
// Iterate over the list of components to extract their information and update the list.
11811180
for _, fwc := range componentList {
11821181
if fwc.Component != "bios" && fwc.Component != "bmc" {
@@ -1188,9 +1187,12 @@ func (p *ironicProvisioner) GetFirmwareComponents() ([]metal3api.FirmwareCompone
11881187
InitialVersion: fwc.InitialVersion,
11891188
CurrentVersion: fwc.CurrentVersion,
11901189
LastVersionFlashed: fwc.LastVersionFlashed,
1191-
UpdatedAt: metav1.Time{
1190+
}
1191+
// Check if UpdatedAt is nil before adding it.
1192+
if fwc.UpdatedAt != nil {
1193+
component.UpdatedAt = metav1.Time{
11921194
Time: *fwc.UpdatedAt,
1193-
},
1195+
}
11941196
}
11951197
componentsInfo = append(componentsInfo, component)
11961198
p.log.Info("firmware component added for node", "component", fwc.Component, "node", ironicNode.UUID)

pkg/provisioner/provisioner.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,6 @@ var ErrNeedsRegistration = errors.New("host not registered")
231231
// ErrNeedsPreprovisioningImage is returned if a preprovisioning image is
232232
// required.
233233
var ErrNeedsPreprovisioningImage = errors.New("no suitable Preprovisioning image available")
234+
235+
// ErrFirmwareUpdateUnsupported is returned if the host can't execute firmware updates.
236+
var ErrFirmwareUpdateUnsupported = errors.New("host does not support Firmware Updates")

0 commit comments

Comments
 (0)