Repository: metal3-io/baremetal-operator
Pull request #1044 (2021-12-03 07:43:59)

Uplift mongo-driver@v1.5.1 & ulikunitz/xz@v0.5.8
Adress security vulnerabilities:
https://github.com/advisories/GHSA-25xm-hr59-7c27
https://github.com/advisories/GHSA-f6mq-5m25-4r72

metal3-io-bot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **fmuyassarov** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @fmuyassarov` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=metal3-io%2Fbaremetal-operator).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/metal3-io/baremetal-operator/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["fmuyassarov"]} -->
kashifest: /assign @fmuyassarov 
/cc @zaneb 
kashifest: /test-v1b1-integration
/test-v1b1-centos-integration
zaneb: If this will get GitHub to stop telling me about it then I'm in favour :)
/lgtm
zaneb: /cc @honza 

Patch:
diff --git a/apis/metal3.io/v1alpha1/firmwareschema_types.go b/apis/metal3.io/v1alpha1/firmwareschema_types.go
index 67620b88..df76ff5d 100644
--- a/apis/metal3.io/v1alpha1/firmwareschema_types.go
+++ b/apis/metal3.io/v1alpha1/firmwareschema_types.go
@@ -18,7 +18,6 @@ package v1alpha1
 
 import (
 	"fmt"
-	"strings"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
@@ -72,10 +71,6 @@ func (schema *SettingSchema) Validate(name string, value intstr.IntOrString) err
 		return SchemaSettingError{name: name, message: "it is ReadOnly"}
 	}
 
-	if strings.Contains(name, "Password") {
-		return SchemaSettingError{name: name, message: "Password fields can't be set"}
-	}
-
 	// Check if valid based on type
 	switch schema.AttributeType {
 	case "Enumeration":
diff --git a/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go b/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go
index c170e967..8bca68d1 100644
--- a/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go
+++ b/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go
@@ -37,16 +37,19 @@ type SettingsConditionType string
 
 const (
 	// Indicates that the settings in the Spec are different than Status
-	FirmwareSettingsChangeDetected SettingsConditionType = "ChangeDetected"
+	UpdateRequested SettingsConditionType = "UpdateRequested"
 
 	// Indicates if the settings are valid and can be configured on the host
-	FirmwareSettingsValid SettingsConditionType = "Valid"
+	SettingsValid SettingsConditionType = "Valid"
 )
 
 // HostFirmwareSettingsSpec defines the desired state of HostFirmwareSettings
 type HostFirmwareSettingsSpec struct {
 
 	// Settings are the desired firmware settings stored as name/value pairs.
+	// This will be populated with the actual firmware settings and only
+	// contain the settings that can be modified (i.e. not ReadOnly), to
+	// facilitate making changes.
 	// +patchStrategy=merge
 	Settings DesiredSettingsMap `json:"settings" required:"true"`
 }
@@ -58,13 +61,9 @@ type HostFirmwareSettingsStatus struct {
 	// Namespace as the settings but it can be overwritten in the Spec
 	FirmwareSchema *SchemaReference `json:"schema,omitempty"`
 
-	// Settings are the firmware settings stored as name/value pairs
+	// Settings are the actual firmware settings stored as name/value pairs
 	Settings SettingsMap `json:"settings" required:"true"`
 
-	// Time that the status was last updated
-	// +optional
-	LastUpdated *metav1.Time `json:"lastUpdated,omitempty"`
-
 	// Track whether settings stored in the spec are valid based on the schema
 	// +patchMergeKey=type
 	// +patchStrategy=merge
diff --git a/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go b/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go
index e62c6071..a352fdbb 100644
--- a/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go
@@ -585,10 +585,6 @@ func (in *HostFirmwareSettingsStatus) DeepCopyInto(out *HostFirmwareSettingsStat
 			(*out)[key] = val
 		}
 	}
-	if in.LastUpdated != nil {
-		in, out := &in.LastUpdated, &out.LastUpdated
-		*out = (*in).DeepCopy()
-	}
 	if in.Conditions != nil {
 		in, out := &in.Conditions, &out.Conditions
 		*out = make([]metav1.Condition, len(*in))
diff --git a/config/crd/bases/metal3.io_hostfirmwaresettings.yaml b/config/crd/bases/metal3.io_hostfirmwaresettings.yaml
index 0c8ab5c3..62e08404 100644
--- a/config/crd/bases/metal3.io_hostfirmwaresettings.yaml
+++ b/config/crd/bases/metal3.io_hostfirmwaresettings.yaml
@@ -46,7 +46,9 @@ spec:
                   - type: string
                   x-kubernetes-int-or-string: true
                 description: Settings are the desired firmware settings stored as
-                  name/value pairs.
+                  name/value pairs. This will be populated with the actual firmware
+                  settings and only contain the settings that can be modified (i.e.
+                  not ReadOnly), to facilitate making changes.
                 type: object
             required:
             - settings
@@ -129,10 +131,6 @@ spec:
                 x-kubernetes-list-map-keys:
                 - type
                 x-kubernetes-list-type: map
-              lastUpdated:
-                description: Time that the status was last updated
-                format: date-time
-                type: string
               schema:
                 description: FirmwareSchema is a reference to the Schema used to describe
                   each FirmwareSetting. By default, this will be a Schema in the same
@@ -152,7 +150,7 @@ spec:
               settings:
                 additionalProperties:
                   type: string
-                description: Settings are the firmware settings stored as name/value
+                description: Settings are the actual firmware settings stored as name/value
                   pairs
                 type: object
             required:
diff --git a/config/render/capm3.yaml b/config/render/capm3.yaml
index 7cc6c57d..1b7f2199 100644
--- a/config/render/capm3.yaml
+++ b/config/render/capm3.yaml
@@ -1243,7 +1243,9 @@ spec:
                   - type: string
                   x-kubernetes-int-or-string: true
                 description: Settings are the desired firmware settings stored as
-                  name/value pairs.
+                  name/value pairs. This will be populated with the actual firmware
+                  settings and only contain the settings that can be modified (i.e.
+                  not ReadOnly), to facilitate making changes.
                 type: object
             required:
             - settings
@@ -1326,10 +1328,6 @@ spec:
                 x-kubernetes-list-map-keys:
                 - type
                 x-kubernetes-list-type: map
-              lastUpdated:
-                description: Time that the status was last updated
-                format: date-time
-                type: string
               schema:
                 description: FirmwareSchema is a reference to the Schema used to describe
                   each FirmwareSetting. By default, this will be a Schema in the same
@@ -1349,7 +1347,7 @@ spec:
               settings:
                 additionalProperties:
                   type: string
-                description: Settings are the firmware settings stored as name/value
+                description: Settings are the actual firmware settings stored as name/value
                   pairs
                 type: object
             required:
diff --git a/controllers/metal3.io/baremetalhost_controller.go b/controllers/metal3.io/baremetalhost_controller.go
index 8eb5b399..a33e0734 100644
--- a/controllers/metal3.io/baremetalhost_controller.go
+++ b/controllers/metal3.io/baremetalhost_controller.go
@@ -55,7 +55,6 @@ const (
 	unmanagedRetryDelay           = time.Minute * 10
 	preprovImageRetryDelay        = time.Minute * 5
 	provisionerNotReadyRetryDelay = time.Second * 30
-	subResourceNotReadyRetryDelay = time.Second * 60
 	rebootAnnotationPrefix        = "reboot.metal3.io"
 	inspectAnnotationPrefix       = "inspect.metal3.io"
 	hardwareDetailsAnnotation     = inspectAnnotationPrefix + "/hardwaredetails"
@@ -825,14 +824,6 @@ func (r *BareMetalHostReconciler) registerHost(prov provisioner.Provisioner, inf
 		return result
 	}
 
-	// Create the hostFirmwareSettings resource with same host name/namespace if it doesn't exist
-	if info.host.Name != "" {
-		if err = r.createHostFirmwareSettings(info); err != nil {
-			info.log.Info("failed creating hostfirmwaresettings")
-			return actionError{errors.Wrap(err, "failed creating hostFirmwareSettings")}
-		}
-	}
-
 	// Reaching this point means the credentials are valid and worked,
 	// so clear any previous error and record the success in the
 	// status block.
@@ -969,8 +960,7 @@ func (r *BareMetalHostReconciler) actionPreparing(prov provisioner.Provisioner,
 	// Use settings in hostFirmwareSettings if available
 	hfs, err := r.getHostFirmwareSettings(info)
 	if err != nil {
-		// wait until hostFirmwareSettings are ready
-		return actionContinue{subResourceNotReadyRetryDelay}
+		info.log.Info("hostFirmwareSettings not available for cleaning")
 	}
 	if hfs != nil {
 		prepareData.ActualFirmwareSettings = hfs.Status.Settings.DeepCopy()
@@ -1344,38 +1334,6 @@ func saveHostProvisioningSettings(host *metal3v1alpha1.BareMetalHost) (dirty boo
 	return
 }
 
-func (r *BareMetalHostReconciler) createHostFirmwareSettings(info *reconcileInfo) error {
-
-	// Check if HostFirmwareSettings already exists
-	hfs := &metal3v1alpha1.HostFirmwareSettings{}
-	if err := r.Get(context.TODO(), info.request.NamespacedName, hfs); err != nil {
-		if k8serrors.IsNotFound(err) {
-			// A resource doesn't exist, create one
-			hfs.ObjectMeta = metav1.ObjectMeta{
-				Name:      info.host.Name,
-				Namespace: info.host.Namespace}
-			hfs.Status.Settings = make(metal3v1alpha1.SettingsMap)
-			hfs.Spec.Settings = make(metal3v1alpha1.DesiredSettingsMap)
-
-			// Set bmh as owner, this makes sure the resource is deleted when bmh is deleted
-			if err = controllerutil.SetControllerReference(info.host, hfs, r.Scheme()); err != nil {
-				return errors.Wrap(err, "could not set bmh as controller")
-			}
-			if err = r.Create(context.TODO(), hfs); err != nil {
-				return errors.Wrap(err, "failure creating hostFirmwareSettings resource")
-			}
-
-			info.log.Info("created new hostFirmwareSettings resource")
-
-		} else {
-			// Error reading the object
-			return errors.Wrap(err, "could not load hostFirmwareSettings resource")
-		}
-	}
-
-	return nil
-}
-
 // Get the stored firmware settings if there are valid changes
 func (r *BareMetalHostReconciler) getHostFirmwareSettings(info *reconcileInfo) (hfs *metal3v1alpha1.HostFirmwareSettings, err error) {
 
@@ -1393,9 +1351,9 @@ func (r *BareMetalHostReconciler) getHostFirmwareSettings(info *reconcileInfo) (
 	}
 
 	// Check if there are settings in the Spec that are different than the Status
-	if meta.IsStatusConditionTrue(hfs.Status.Conditions, string(metal3v1alpha1.FirmwareSettingsChangeDetected)) {
+	if meta.IsStatusConditionTrue(hfs.Status.Conditions, string(metal3v1alpha1.UpdateRequested)) {
 
-		if meta.IsStatusConditionTrue(hfs.Status.Conditions, string(metal3v1alpha1.FirmwareSettingsValid)) {
+		if meta.IsStatusConditionTrue(hfs.Status.Conditions, string(metal3v1alpha1.SettingsValid)) {
 			return hfs, nil
 		}
 
diff --git a/controllers/metal3.io/hostfirmwaresettings_controller.go b/controllers/metal3.io/hostfirmwaresettings_controller.go
index a3370a48..566480e7 100644
--- a/controllers/metal3.io/hostfirmwaresettings_controller.go
+++ b/controllers/metal3.io/hostfirmwaresettings_controller.go
@@ -21,9 +21,7 @@ import (
 	"crypto/sha256"
 	"fmt"
 	"sort"
-	"strconv"
 	"strings"
-	"time"
 
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
@@ -32,21 +30,21 @@ import (
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/api/meta"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/builder"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+	"sigs.k8s.io/controller-runtime/pkg/event"
+	"sigs.k8s.io/controller-runtime/pkg/handler"
+	"sigs.k8s.io/controller-runtime/pkg/predicate"
+	"sigs.k8s.io/controller-runtime/pkg/source"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
 )
 
-const (
-	provisionerRetryDelay          = time.Second * 30
-	resourceNotAvailableRetryDelay = time.Second * 30
-	reconcilerRequeueDelay         = time.Minute * 5
-)
-
 // HostFirmwareSettingsReconciler reconciles a HostFirmwareSettings object
 type HostFirmwareSettingsReconciler struct {
 	client.Client
@@ -117,20 +115,24 @@ func (r *HostFirmwareSettingsReconciler) Reconcile(ctx context.Context, req ctrl
 	bmh := &metal3v1alpha1.BareMetalHost{}
 	if err = r.Get(context.TODO(), req.NamespacedName, bmh); err != nil {
 		reqLogger.Info("could not get baremetalhost, not running reconciler")
-		return ctrl.Result{Requeue: true, RequeueAfter: resourceNotAvailableRetryDelay}, nil
+		// only run again if created
+		return ctrl.Result{}, nil
 	}
 
 	// Fetch the HostFirmwareSettings
 	hfs := &metal3v1alpha1.HostFirmwareSettings{}
 	info := &rInfo{log: reqLogger, hfs: hfs, bmh: bmh}
 	if err = r.Get(ctx, req.NamespacedName, hfs); err != nil {
-		// The HFS resource may have been deleted
 		if k8serrors.IsNotFound(err) {
-			reqLogger.Info("hostFirmwareSettings not found")
-			return ctrl.Result{Requeue: true, RequeueAfter: resourceNotAvailableRetryDelay}, nil
+			// A resource doesn't exist, create one
+			if err = r.newHostFirmwareSettings(info, req.NamespacedName); err != nil {
+
+				return ctrl.Result{}, errors.Wrap(err, "could not create firmware settings")
+			}
+		} else {
+			// Error reading the object - requeue the request.
+			return ctrl.Result{}, errors.Wrap(err, "could not load host firmware settings")
 		}
-		// Error reading the object - requeue the request.
-		return ctrl.Result{}, errors.Wrap(err, "could not load hostFirmwareSettings")
 	}
 
 	// Create a provisioner that can access Ironic API
@@ -141,20 +143,13 @@ func (r *HostFirmwareSettingsReconciler) Reconcile(ctx context.Context, req ctrl
 
 	ready, err := prov.IsReady()
 	if err != nil || !ready {
-		reqLogger.Info("provisioner is not ready", "RequeueAfter:", provisionerRetryDelay)
-		return ctrl.Result{Requeue: true, RequeueAfter: provisionerRetryDelay}, nil
-	}
-
-	info.log.Info("retrieving firmware settings and saving to resource", "node", bmh.Status.Provisioning.ID)
-
-	// Get the current settings and schema, retry if provisioner returns error
-	currentSettings, schema, err := prov.GetFirmwareSettings(true)
-	if err != nil {
-		reqLogger.Info("provisioner returns error", "RequeueAfter:", provisionerRetryDelay)
-		return ctrl.Result{Requeue: true, RequeueAfter: provisionerRetryDelay}, nil
+		reqLogger.Info("provisioner is not ready", "RequeueAfter:", provisionerNotReadyRetryDelay)
+		return ctrl.Result{Requeue: true, RequeueAfter: provisionerNotReadyRetryDelay}, nil
 	}
 
-	if err = r.updateHostFirmwareSettings(currentSettings, schema, info); err != nil {
+	// Get the data from Ironic and update HFS, the call to provisioner may fail if settings can't
+	// be retrieved for the bios_interface.
+	if err = r.updateHostFirmwareSettings(prov, info); err != nil {
 		return ctrl.Result{}, errors.Wrap(err, "Could not update hostFirmwareSettings")
 	}
 
@@ -162,12 +157,20 @@ func (r *HostFirmwareSettingsReconciler) Reconcile(ctx context.Context, req ctrl
 		r.publishEvent(req, e)
 	}
 
-	// requeue to run again after delay
-	return ctrl.Result{Requeue: true, RequeueAfter: reconcilerRequeueDelay}, nil
+	// only run again on changes
+	return ctrl.Result{}, nil
 }
 
 // Get the firmware settings from the provisioner and update hostFirmwareSettings
-func (r *HostFirmwareSettingsReconciler) updateHostFirmwareSettings(currentSettings metal3v1alpha1.SettingsMap, schema map[string]metal3v1alpha1.SettingSchema, info *rInfo) (err error) {
+func (r *HostFirmwareSettingsReconciler) updateHostFirmwareSettings(prov provisioner.Provisioner, info *rInfo) (err error) {
+
+	info.log.Info("retrieving firmware settings and saving to resource", "node", info.bmh.Status.Provisioning.ID)
+
+	// Get the current settings and schema
+	currentSettings, schema, err := prov.GetFirmwareSettings(true)
+	if err != nil {
+		return errors.Wrap(err, "could not get firmware settings from provisioner")
+	}
 
 	// get or create a firmwareSchema to hold schema
 	firmwareSchema, err := r.getOrCreateFirmwareSchema(info, schema)
@@ -194,13 +197,12 @@ func (r *HostFirmwareSettingsReconciler) updateStatus(info *rInfo, settings meta
 		info.hfs.Status.Settings = make(metal3v1alpha1.SettingsMap)
 	}
 
-	// Update Status on changes
+	// Update Status
 	for k, v := range settings {
 		// Some vendors include encrypted password fields, don't add these
 		if strings.Contains(k, "Password") {
 			continue
 		}
-
 		info.hfs.Status.Settings[k] = v
 	}
 
@@ -212,10 +214,6 @@ func (r *HostFirmwareSettingsReconciler) updateStatus(info *rInfo, settings meta
 				specMismatch = true
 				break
 			}
-		} else {
-			// Spec setting is not in Status, this will be handled by validateHostFirmwareSettings
-			specMismatch = true
-			break
 		}
 	}
 
@@ -224,33 +222,26 @@ func (r *HostFirmwareSettingsReconciler) updateStatus(info *rInfo, settings meta
 	generation := info.hfs.GetGeneration()
 
 	if specMismatch {
-		setCondition(generation, &info.hfs.Status, metal3v1alpha1.FirmwareSettingsChangeDetected, metav1.ConditionTrue, reason, "")
+		setCondition(generation, &info.hfs.Status, metal3v1alpha1.UpdateRequested, metav1.ConditionTrue, reason, "")
 
-		// Run validation on the Spec to detect invalid values entered by user, including Spec settings not in Status
-		// Eventually this will be handled by a webhook
-		errors := r.validateHostFirmwareSettings(info, schema)
-		if len(errors) == 0 {
-			setCondition(generation, &info.hfs.Status, metal3v1alpha1.FirmwareSettingsValid, metav1.ConditionTrue, reason, "")
-		} else {
-			for _, error := range errors {
-				info.publishEvent("ValidationFailed", fmt.Sprintf("Invalid BIOS setting: %v", error))
-			}
+	} else {
+		setCondition(generation, &info.hfs.Status, metal3v1alpha1.UpdateRequested, metav1.ConditionFalse, reason, "")
+	}
 
-			reason = reasonConfigurationError
-			setCondition(generation, &info.hfs.Status, metal3v1alpha1.FirmwareSettingsValid, metav1.ConditionFalse, reason, "Invalid BIOS setting")
-		}
+	// Run validation on the Spec to detect invalid values entered by user, including Spec settings not in Status
+	// Eventually this will be handled by a webhook
+	errors := r.validateHostFirmwareSettings(info, schema)
+	if len(errors) == 0 {
+		setCondition(generation, &info.hfs.Status, metal3v1alpha1.SettingsValid, metav1.ConditionTrue, reason, "")
 	} else {
-		// Reset conditions
-		if meta.IsStatusConditionTrue(info.hfs.Status.Conditions, string(metal3v1alpha1.FirmwareSettingsChangeDetected)) {
-			setCondition(generation, &info.hfs.Status, metal3v1alpha1.FirmwareSettingsChangeDetected, metav1.ConditionFalse, reason, "")
-		}
-		if !meta.IsStatusConditionTrue(info.hfs.Status.Conditions, string(metal3v1alpha1.FirmwareSettingsValid)) {
-			setCondition(generation, &info.hfs.Status, metal3v1alpha1.FirmwareSettingsValid, metav1.ConditionTrue, reason, "")
+		for _, error := range errors {
+			info.publishEvent("ValidationFailed", fmt.Sprintf("Invalid BIOS setting: %v", error))
 		}
+
+		reason = reasonConfigurationError
+		setCondition(generation, &info.hfs.Status, metal3v1alpha1.SettingsValid, metav1.ConditionFalse, reason, "Invalid BIOS setting")
 	}
 
-	t := metav1.Now()
-	info.hfs.Status.LastUpdated = &t
 	return r.Status().Update(context.TODO(), info.hfs)
 }
 
@@ -268,19 +259,12 @@ func (r *HostFirmwareSettingsReconciler) getOrCreateFirmwareSchema(info *rInfo,
 
 		info.log.Info("found existing firmwareSchema resource")
 
-		// Add hfs as owner so can be garbage collected on delete, if already an owner it will just be overwritten
-		if err = controllerutil.SetOwnerReference(info.hfs, firmwareSchema, r.Scheme()); err != nil {
-			return nil, errors.Wrap(err, "could not set owner of existing firmwareSchema")
-		}
-		if err = r.Update(context.TODO(), firmwareSchema); err != nil {
-			return nil, err
-		}
-
 		return firmwareSchema, nil
 	}
 	if !k8serrors.IsNotFound(err) {
 		// Error reading the object
 		return nil, err
+
 	}
 
 	firmwareSchema = &metal3v1alpha1.FirmwareSchema{
@@ -301,25 +285,108 @@ func (r *HostFirmwareSettingsReconciler) getOrCreateFirmwareSchema(info *rInfo,
 	for k, v := range schema {
 		firmwareSchema.Spec.Schema[k] = v
 	}
-	// Set hfs as owner
-	if err = controllerutil.SetOwnerReference(info.hfs, firmwareSchema, r.Scheme()); err != nil {
-		return nil, errors.Wrap(err, "could not set owner of firmwareSchema")
-	}
 
 	if err = r.Create(context.TODO(), firmwareSchema); err != nil {
 		return nil, err
 	}
+	// Set hfs as owner after the create
+	if controllerutil.SetOwnerReference(info.hfs, firmwareSchema, r.Scheme()); err != nil {
+		return nil, errors.Wrap(err, "could not set owner of firmwareSchema")
+	}
+	if err = r.Update(context.TODO(), firmwareSchema); err != nil {
+		return nil, err
+	}
 
 	info.log.Info("created new firmwareSchema resource")
 
 	return firmwareSchema, nil
 }
 
+// Create a hostFirmwareSettings
+func (r *HostFirmwareSettingsReconciler) newHostFirmwareSettings(info *rInfo, namespacedName types.NamespacedName) (err error) {
+
+	info.hfs.ObjectMeta = metav1.ObjectMeta{
+		Name: namespacedName.Name, Namespace: namespacedName.Namespace}
+	info.hfs.Status.Settings = make(metal3v1alpha1.SettingsMap)
+	info.hfs.Spec.Settings = make(metal3v1alpha1.DesiredSettingsMap)
+
+	if err = r.Create(context.TODO(), info.hfs); err != nil {
+		return errors.Wrap(err, "failure creating hostFirmwareSettings resource")
+	}
+
+	// Set bmh as owner, this makes sure the resource is deleted when bmh is deleted
+	if controllerutil.SetControllerReference(info.bmh, info.hfs, r.Scheme()); err != nil {
+		return errors.Wrap(err, "could not set bmh as controller")
+	}
+	if err = r.Update(context.TODO(), info.hfs); err != nil {
+		return errors.Wrap(err, "could not update hostfirmwaresettings")
+	}
+
+	info.log.Info("created new hostFirmwareSettings resource")
+
+	return nil
+}
+
+// EventHandler for updates to both the baremetalhost and hostfirmwarettings
+func (r *HostFirmwareSettingsReconciler) updateEventHandler(e event.UpdateEvent) bool {
+
+	r.Log.Info("hostfirmwaresettings in event handler")
+
+	// If this is a baremetalhost, only return true on certain state transitions
+	var oldState metal3v1alpha1.ProvisioningState = metal3v1alpha1.StateNone
+	newState := oldState
+
+	oldHost, oldHostExists := e.ObjectOld.(*metal3v1alpha1.BareMetalHost)
+	if oldHostExists {
+		oldState = oldHost.Status.Provisioning.State
+	}
+	newHost, newHostExists := e.ObjectNew.(*metal3v1alpha1.BareMetalHost)
+	if newHostExists {
+		newState = newHost.Status.Provisioning.State
+	}
+
+	if newHostExists && !oldHostExists {
+		// The baremetalhost has been created
+		return true
+	}
+	if oldHostExists || newHostExists {
+		// Data needs to be retrieved from Ironic when node is moved to Ready  e.g. after cleaning and when
+		// provisioned, its not necessary on every state change as data from Ironic will be the same.
+		if (newState == metal3v1alpha1.StateReady || newState == metal3v1alpha1.StateProvisioned) && oldState != newState {
+			r.Log.Info("baremetalhost event state update", "oldstate", oldState, "newstate", newState)
+			return true
+		}
+
+		return false
+	}
+
+	_, oldHFS := e.ObjectOld.(*metal3v1alpha1.HostFirmwareSettings)
+	_, newHFS := e.ObjectNew.(*metal3v1alpha1.HostFirmwareSettings)
+	if !(oldHFS || newHFS) {
+		// Don't process if not a hostFirmwareSetting
+		return false
+	}
+
+	// This is a hostfirmwaresettings resource, if the update increased the resource generation then process it
+	// changes to LastUpdated will not increase the resource generation
+	if e.ObjectNew.GetGeneration() != e.ObjectOld.GetGeneration() {
+		r.Log.Info("hostfirmwaresettings resource generation changed, updating")
+		return true
+	}
+
+	return false
+}
+
 // SetupWithManager sets up the controller with the Manager.
 func (r *HostFirmwareSettingsReconciler) SetupWithManager(mgr ctrl.Manager) error {
 
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&metal3v1alpha1.HostFirmwareSettings{}).
+		WithEventFilter(
+			predicate.Funcs{
+				UpdateFunc: r.updateEventHandler,
+			}).
+		Watches(&source.Kind{Type: &metal3v1alpha1.BareMetalHost{}}, &handler.EnqueueRequestForObject{}, builder.Predicates{}).
 		Complete(r)
 }
 
@@ -380,37 +447,19 @@ func setCondition(generation int64, status *metal3v1alpha1.HostFirmwareSettingsS
 	meta.SetStatusCondition(&status.Conditions, newCondition)
 }
 
-// Generate a name based on the schema key and values which should be the same for similar hardware
+// Generate a name based on the schema keys which should be the same for similar hardware
 func GetSchemaName(schema map[string]metal3v1alpha1.SettingSchema) string {
 
 	// Schemas from the same vendor and model should be identical for both keys and values.
-	hashkeys := make([]string, 0, len(schema))
-	for k, v := range schema {
-		hashkeys = append(hashkeys, k)
-		hashkeys = append(hashkeys, v.AttributeType)
-		for _, av := range v.AllowableValues {
-			hashkeys = append(hashkeys, av)
-		}
-		if v.LowerBound != nil {
-			hashkeys = append(hashkeys, strconv.Itoa(*v.LowerBound))
-		}
-		if v.UpperBound != nil {
-			hashkeys = append(hashkeys, strconv.Itoa(*v.UpperBound))
-		}
-		if v.MinLength != nil {
-			hashkeys = append(hashkeys, strconv.Itoa(*v.MinLength))
-		}
-		if v.MaxLength != nil {
-			hashkeys = append(hashkeys, strconv.Itoa(*v.MaxLength))
-		}
-		if v.ReadOnly != nil {
-			hashkeys = append(hashkeys, strconv.FormatBool(*v.ReadOnly))
-		}
+	// Hash the keys of the map to get a identifier unique to this schema.
+	keys := make([]string, 0, len(schema))
+	for k := range schema {
+		keys = append(keys, k)
 	}
-	sort.Strings(hashkeys)
+	sort.Strings(keys)
 
 	h := sha256.New()
-	h.Write([]byte(fmt.Sprintf("%v", hashkeys)))
+	h.Write([]byte(fmt.Sprintf("%v", keys)))
 	hash := fmt.Sprintf("%x", h.Sum(nil))[:8]
 
 	return "schema-" + hash
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index ba11beb3..ddfca475 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -170,14 +170,14 @@ require (
 	github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94 // indirect
 	github.com/tomarrell/wrapcheck/v2 v2.1.0 // indirect
 	github.com/tommy-muehle/go-mnd/v2 v2.4.0 // indirect
-	github.com/ulikunitz/xz v0.5.5 // indirect
+	github.com/ulikunitz/xz v0.5.8 // indirect
 	github.com/ultraware/funlen v0.0.3 // indirect
 	github.com/ultraware/whitespace v0.0.4 // indirect
 	github.com/uudashr/gocognit v1.0.1 // indirect
 	github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
 	github.com/yeya24/promlinter v0.1.0 // indirect
 	github.com/yujunz/go-getter v1.4.1-lite // indirect
-	go.mongodb.org/mongo-driver v1.1.2 // indirect
+	go.mongodb.org/mongo-driver v1.5.1 // indirect
 	go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
 	golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
 	golang.org/x/mod v0.4.2 // indirect
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index 8381922b..debc8e73 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -120,6 +120,7 @@ github.com/ashanbrown/makezero v0.0.0-20210520155254-b6261585ddde h1:YOsoVXsZQPA
 github.com/ashanbrown/makezero v0.0.0-20210520155254-b6261585ddde/go.mod h1:oG9Dnez7/ESBqc4EdrdNlryeo7d0KcW1ftXHm7nU/UU=
 github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
 github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -335,8 +336,32 @@ github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYw
 github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
 github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo=
 github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
+github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
+github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
+github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
+github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
+github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
 github.com/gobuffalo/flect v0.2.3 h1:f/ZukRnSNA/DUpSNDadko7Qc0PhGvsew35p/2tu+CRY=
 github.com/gobuffalo/flect v0.2.3/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
+github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
+github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
+github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
+github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
+github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
+github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
+github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
+github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
+github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
+github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
+github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
+github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
 github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
 github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -384,6 +409,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
 github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
 github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
 github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
@@ -549,6 +575,7 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
 github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -567,6 +594,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
 github.com/julz/importas v0.0.0-20210419104244-841f0c0fe66d h1:XeSMXURZPtUffuWAaq90o6kLgZdgu+QA8wk4MPC8ikI=
 github.com/julz/importas v0.0.0-20210419104244-841f0c0fe66d/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0=
 github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
+github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
+github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@@ -576,6 +605,7 @@ github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
 github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
 github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
@@ -623,6 +653,8 @@ github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM
 github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
 github.com/maratori/testpackage v1.0.1 h1:QtJ5ZjqapShm0w5DosRjg0PRlSdAdlx+W6cCKoALdbQ=
 github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU=
+github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
+github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
 github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
 github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7RXkts09K+dEBJWakUWwICVqYbA=
 github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
@@ -687,6 +719,7 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
 github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
 github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 github.com/moricho/tparallel v0.2.1 h1:95FytivzT6rYzdJLdtfn6m1bfFJylOJK41+lgv/EHf4=
 github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k=
 github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8=
@@ -741,6 +774,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
 github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
 github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
 github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
@@ -801,6 +835,8 @@ github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf
 github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
@@ -830,6 +866,8 @@ github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxr
 github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
@@ -914,8 +952,9 @@ github.com/tommy-muehle/go-mnd/v2 v2.4.0 h1:1t0f8Uiaq+fqKteUR4N9Umr6E99R+lDnLnq7
 github.com/tommy-muehle/go-mnd/v2 v2.4.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
 github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
+github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
+github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
 github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
 github.com/ultraware/funlen v0.0.3 h1:5ylVWm8wsNwH5aWo9438pwvsK0QiqVuUrt9bn7S/iLA=
 github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
@@ -934,6 +973,9 @@ github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD
 github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
 github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
 github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
+github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
 github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
@@ -941,6 +983,7 @@ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1z
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/yeya24/promlinter v0.1.0 h1:goWULN0jH5Yajmu/K+v1xCqIREeB+48OiJ2uu2ssc7U=
 github.com/yeya24/promlinter v0.1.0/go.mod h1:rs5vtZzeBHqqMwXqFScncpCF6u06lezhZepno9AB1Oc=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
 github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
 github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
 github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
@@ -962,8 +1005,9 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3
 go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
 go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
 go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
 go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
+go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI=
+go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw=
 go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@@ -994,6 +1038,7 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -1001,6 +1046,7 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
@@ -1141,10 +1187,13 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1237,10 +1286,14 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
 golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
diff --git a/pkg/provisioner/ironic/ironic.go b/pkg/provisioner/ironic/ironic.go
index 284e8348..5b9140a2 100644
--- a/pkg/provisioner/ironic/ironic.go
+++ b/pkg/provisioner/ironic/ironic.go
@@ -1149,7 +1149,7 @@ func (p *ironicProvisioner) buildManualCleaningSteps(bmcAccess bmc.AccessDetails
 		bmcConfig := bmc.FirmwareConfig(*data.FirmwareConfig)
 		firmwareConfig = &bmcConfig
 	}
-	fwConfigSettings, err := bmcAccess.BuildBIOSSettings(firmwareConfig)
+	bmcsettings, err := bmcAccess.BuildBIOSSettings(firmwareConfig)
 	if err != nil {
 		return nil, err
 	}
@@ -1158,13 +1158,13 @@ func (p *ironicProvisioner) buildManualCleaningSteps(bmcAccess bmc.AccessDetails
 	if data.ActualFirmwareSettings != nil {
 		// If we have the current settings from Ironic, update the settings to contain:
 		// 1. settings converted by BMC drivers that are different than current settings
-		for _, fwConfigSetting := range fwConfigSettings {
-			if val, exists := data.ActualFirmwareSettings[fwConfigSetting["name"]]; exists {
-				if fwConfigSetting["value"] != val {
-					newSettings = buildFirmwareSettings(newSettings, fwConfigSetting["name"], fwConfigSetting["value"])
+		for _, bmcsetting := range bmcsettings {
+			if val, exists := data.ActualFirmwareSettings[bmcsetting["name"]]; exists {
+				if bmcsetting["value"] != val {
+					newSettings = buildFirmwareSettings(newSettings, bmcsetting["name"], bmcsetting["value"])
 				}
 			} else {
-				p.log.Info("name converted from bmc driver not found in firmware settings", "name", fwConfigSetting["name"], "node", p.nodeID)
+				p.log.Info("name converted from bmc driver not found in firmware settings", "name", bmcsetting["name"], "node", p.nodeID)
 			}
 		}
 
@@ -1172,20 +1172,14 @@ func (p *ironicProvisioner) buildManualCleaningSteps(bmcAccess bmc.AccessDetails
 		if data.TargetFirmwareSettings != nil {
 			for k, v := range data.TargetFirmwareSettings {
 				if data.ActualFirmwareSettings[k] != v.String() {
-					// Skip changing this setting if it was defined in the vendor specific settings
-					for _, fwConfigSetting := range fwConfigSettings {
-						if fwConfigSetting["name"] == k {
-							continue
-						}
-					}
 					newSettings = buildFirmwareSettings(newSettings, k, v.String())
 				}
 			}
 		}
 	} else {
 		// use only the settings converted by bmc driver
-		for _, fwConfigSetting := range fwConfigSettings {
-			newSettings = append(newSettings, fwConfigSetting)
+		for _, bmcsetting := range bmcsettings {
+			newSettings = append(newSettings, bmcsetting)
 		}
 	}
 


Test patch:
diff --git a/controllers/metal3.io/hostfirmwaresettings_test.go b/controllers/metal3.io/hostfirmwaresettings_test.go
index ec44ae0a..667cb3e7 100644
--- a/controllers/metal3.io/hostfirmwaresettings_test.go
+++ b/controllers/metal3.io/hostfirmwaresettings_test.go
@@ -21,7 +21,7 @@ import (
 const (
 	hostName      string = "myHostName"
 	hostNamespace string = "myHostNamespace"
-	schemaName    string = "schema-4bcc035f" // Hash generated from schema, change this if the schema is changed
+	schemaName    string = "schema-17e7ebad" // Hash generated from schema, change this if the schema is changed
 )
 
 var (
@@ -67,6 +67,10 @@ func (m *hsfMockProvisioner) ValidateManagementAccess(data provisioner.Managemen
 	return
 }
 
+func (m *hsfMockProvisioner) PreprovisioningImageFormats() ([]metal3v1alpha1.ImageFormat, error) {
+	return nil, nil
+}
+
 func (m *hsfMockProvisioner) InspectHardware(data provisioner.InspectData, force, refresh bool) (result provisioner.Result, started bool, details *metal3v1alpha1.HardwareDetails, err error) {
 	return
 }
@@ -129,7 +133,7 @@ func getSchema() *metal3v1alpha1.FirmwareSchema {
 				{
 					APIVersion: "metal3.io/v1alpha1",
 					Kind:       "HostFirmwareSettings",
-					Name:       "dummyhfs",
+					Name:       hostName,
 				},
 			},
 		},
@@ -210,36 +214,8 @@ func createBaremetalHost() *metal3v1alpha1.BareMetalHost {
 	return bmh
 }
 
-func getExpectedSchema() *metal3v1alpha1.FirmwareSchema {
-	firmwareSchema := getSchema()
-	firmwareSchema.ObjectMeta.ResourceVersion = "1"
-	firmwareSchema.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
-		{
-			APIVersion: "metal3.io/v1alpha1",
-			Kind:       "HostFirmwareSettings",
-			Name:       hostName,
-		},
-	}
-	firmwareSchema.Spec.Schema = getCurrentSchemaSettings()
-
-	return firmwareSchema
-}
-
-func getExpectedSchemaTwoOwners() *metal3v1alpha1.FirmwareSchema {
+func getExpectedSchemaResource() *metal3v1alpha1.FirmwareSchema {
 	firmwareSchema := getSchema()
-	firmwareSchema.ObjectMeta.ResourceVersion = "2"
-	firmwareSchema.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
-		{
-			APIVersion: "metal3.io/v1alpha1",
-			Kind:       "HostFirmwareSettings",
-			Name:       "dummyhfs",
-		},
-		{
-			APIVersion: "metal3.io/v1alpha1",
-			Kind:       "HostFirmwareSettings",
-			Name:       hostName,
-		},
-	}
 	firmwareSchema.Spec.Schema = getCurrentSchemaSettings()
 
 	return firmwareSchema
@@ -319,6 +295,7 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						"SecureBoot":            "Enabled",
 					},
 					Conditions: []metav1.Condition{
+						{Type: "UpdateRequested", Status: "False", Reason: "Success"},
 						{Type: "Valid", Status: "True", Reason: "Success"},
 					},
 				},
@@ -358,6 +335,7 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						"SecureBoot":            "Enabled",
 					},
 					Conditions: []metav1.Condition{
+						{Type: "UpdateRequested", Status: "False", Reason: "Success"},
 						{Type: "Valid", Status: "True", Reason: "Success"},
 					},
 				},
@@ -378,7 +356,6 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 					Settings: metal3v1alpha1.DesiredSettingsMap{
 						"NetworkBootRetryCount": intstr.FromString("10"),
 						"ProcVirtualization":    intstr.FromString("Enabled"),
-						"AssetTag":              intstr.FromString("Z98765432"),
 					},
 				},
 				Status: metal3v1alpha1.HostFirmwareSettingsStatus{
@@ -387,7 +364,6 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						Namespace: hostNamespace,
 					},
 					Settings: metal3v1alpha1.SettingsMap{
-						"AssetTag":              "Z98765432",
 						"L2Cache":               "10x256 KB",
 						"NetworkBootRetryCount": "10",
 						"ProcVirtualization":    "Enabled",
@@ -400,7 +376,6 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 					Settings: metal3v1alpha1.DesiredSettingsMap{
 						"NetworkBootRetryCount": intstr.FromString("10"),
 						"ProcVirtualization":    intstr.FromString("Enabled"),
-						"AssetTag":              intstr.FromString("Z98765432"),
 					},
 				},
 				Status: metal3v1alpha1.HostFirmwareSettingsStatus{
@@ -416,7 +391,7 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						"SecureBoot":            "Enabled",
 					},
 					Conditions: []metav1.Condition{
-						{Type: "ChangeDetected", Status: "True", Reason: "Success"},
+						{Type: "UpdateRequested", Status: "True", Reason: "Success"},
 						{Type: "Valid", Status: "True", Reason: "Success"},
 					},
 				},
@@ -472,7 +447,7 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						"SecureBoot":            "Enabled",
 					},
 					Conditions: []metav1.Condition{
-						{Type: "ChangeDetected", Status: "True", Reason: "Success"},
+						{Type: "UpdateRequested", Status: "True", Reason: "Success"},
 						{Type: "Valid", Status: "False", Reason: "ConfigurationError", Message: "Invalid BIOS setting"},
 					},
 				},
@@ -507,17 +482,14 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 			}
 
 			if tc.CreateSchemaResource {
-				// Create an existing schema with different hfs owner
 				firmwareSchema := getSchema()
 				firmwareSchema.Spec.Schema = getCurrentSchemaSettings()
 
 				r.Client.Create(ctx, firmwareSchema)
+				r.Client.Update(ctx, firmwareSchema) // in order to set resource version
 			}
 
-			currentSettings, schema, err := prov.GetFirmwareSettings(true)
-			assert.Equal(t, nil, err)
-
-			err = r.updateHostFirmwareSettings(currentSettings, schema, info)
+			err := r.updateHostFirmwareSettings(prov, info)
 			assert.Equal(t, nil, err)
 
 			// Check that resources get created or updated
@@ -529,12 +501,11 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 
 			// Use the same time for expected and actual
 			currentTime := metav1.Now()
-			tc.ExpectedSettings.Status.LastUpdated = &currentTime
-			actualSettings.Status.LastUpdated = &currentTime
-			for i := range tc.ExpectedSettings.Status.Conditions {
+			for i := 0; i < 2; i++ {
 				tc.ExpectedSettings.Status.Conditions[i].LastTransitionTime = currentTime
 				actualSettings.Status.Conditions[i].LastTransitionTime = currentTime
 			}
+
 			assert.Equal(t, tc.ExpectedSettings, actualSettings)
 
 			key = client.ObjectKey{
@@ -542,12 +513,8 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 			actualSchema := &metal3v1alpha1.FirmwareSchema{}
 			err = r.Client.Get(ctx, key, actualSchema)
 			assert.Equal(t, nil, err)
-			var expectedSchema *metal3v1alpha1.FirmwareSchema
-			if tc.CreateSchemaResource {
-				expectedSchema = getExpectedSchemaTwoOwners()
-			} else {
-				expectedSchema = getExpectedSchema()
-			}
+			expectedSchema := getExpectedSchemaResource()
+			expectedSchema.ObjectMeta.ResourceVersion = "2"
 			assert.Equal(t, expectedSchema, actualSchema)
 		})
 	}
@@ -638,7 +605,7 @@ func TestValidateHostFirmwareSettings(t *testing.T) {
 				hfs: hfs,
 			}
 
-			errors := r.validateHostFirmwareSettings(info, getExpectedSchema())
+			errors := r.validateHostFirmwareSettings(info, getExpectedSchemaResource())
 			if len(errors) == 0 {
 				assert.Equal(t, tc.ExpectedError, "")
 			} else {