Repository: metal3-io/baremetal-operator
Pull request #942 (2021-07-22 11:18:09)

Fix missing case of BuildRAIDCleanSteps
Signed-off-by: Zou Yu <zouy.fnst@cn.fujitsu.com>

This PR replaces #941. I closed PR941 to avoid affecting openshift [PR165](https://github.com/openshift/baremetal-operator/pull/165).
PR165 should only track #908, rather than includes PR941, since it is a bug fix.
Unfortunately, PR941 and PR908 was on the same branch, so I have to close PR941 and open this one, sorry about that.

This PR aims to address a case in BuildRAIDCleanSteps which I missed in PR908.

In summary, it add the handling of the case when hardwareRAIDVolumes is nil and the target node doesn't have a RAID controller.  We shouldn't delete the RAID configuration on that node in that case, otherwise the `ironic` node will enter the clean failed state because of  `delete_configuration` clean step failure.


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 **russellb** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @russellb` 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":["russellb"]} -->
Hellcatlk: /assign @russellb
Hellcatlk: /assign @dtantsur 
Hellcatlk: /test-integration
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 ask for approval from **dtantsur** after the PR has been reviewed.

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":["dtantsur"]} -->
andfasano: /lgtm

Patch:
diff --git a/PROJECT b/PROJECT
index e546544e..1031f087 100644
--- a/PROJECT
+++ b/PROJECT
@@ -4,10 +4,4 @@ resources:
 - group: metal3.io
   kind: BareMetalHost
   version: v1alpha1
-- group: metal3.io
-  kind: HostFirmwareSettings
-  version: v1alpha1
-- group: metal3.io
-  kind: FirmwareSchema
-  version: v1alpha1
 version: "2"
diff --git a/apis/go.sum b/apis/go.sum
index 04c07372..b0c7635f 100644
--- a/apis/go.sum
+++ b/apis/go.sum
@@ -584,7 +584,6 @@ k8s.io/apiextensions-apiserver v0.19.2/go.mod h1:EYNjpqIAvNZe+svXVx9j4uBaVhTB4C9
 k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
 k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg=
 k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
-k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc=
 k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA=
 k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA=
 k8s.io/code-generator v0.19.2/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk=
diff --git a/apis/metal3.io/v1alpha1/firmwareschema_types.go b/apis/metal3.io/v1alpha1/firmwareschema_types.go
deleted file mode 100644
index 58b0247b..00000000
--- a/apis/metal3.io/v1alpha1/firmwareschema_types.go
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
-
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1alpha1
-
-import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
-)
-
-// Additional data describing the firmware setting
-type SettingSchema struct {
-
-	// The type of setting.
-	// +kubebuilder:validation:Enum=Enumeration;String;Integer;Boolean;Password
-	AttributeType string `json:"attribute_type,omitempty"`
-
-	// The allowable value for an Enumeration type setting.
-	AllowableValues []string `json:"allowable_values,omitempty"`
-
-	// The lowest value for an Integer type setting.
-	LowerBound *int `json:"lower_bound,omitempty"`
-
-	// The highest value for an Integer type setting.
-	UpperBound *int `json:"upper_bound,omitempty"`
-
-	// Minimum length for a String type setting.
-	MinLength *int `json:"min_length,omitempty"`
-
-	// Maximum length for a String type setting.
-	MaxLength *int `json:"max_length,omitempty"`
-
-	// Whether or not this setting is read only.
-	ReadOnly *bool `json:"read_only,omitempty"`
-
-	// Whether or not a reset is required after changing this setting.
-	ResetRequired *bool `json:"reset_required,omitempty"`
-
-	// Whether or not this setting's value is unique to this node, e.g.
-	// a serial number.
-	Unique *bool `json:"unique,omitempty"`
-}
-
-// FirmwareSchemaSpec defines the desired state of FirmwareSchema
-type FirmwareSchemaSpec struct {
-
-	// The hardware vendor associated with this schema
-	// +optional
-	HardwareVendor string `json:"hardwareVendor,omitempty"`
-
-	// The hardware model associated with this schema
-	// +optional
-	HardwareModel string `json:"hardwareModel,omitempty"`
-
-	// Map of firmware name to schema
-	Schema map[string]SettingSchema `json:"schema" required:"true"`
-}
-
-//+kubebuilder:object:root=true
-
-// FirmwareSchema is the Schema for the firmwareschemas API
-type FirmwareSchema struct {
-	metav1.TypeMeta   `json:",inline"`
-	metav1.ObjectMeta `json:"metadata,omitempty"`
-
-	Spec FirmwareSchemaSpec `json:"spec,omitempty"`
-}
-
-// Check whether the setting's name and value is valid using the schema
-func (host *FirmwareSchema) CheckSettingIsValid(name string, value intstr.IntOrString, schemas map[string]SettingSchema) bool {
-
-	schema, ok := schemas[name]
-	if !ok {
-		// The setting must exist in the status
-		return false
-	}
-
-	if schema.ReadOnly != nil && *schema.ReadOnly == true {
-		return false
-	}
-
-	// Check if valid based on type
-	switch schema.AttributeType {
-	case "Enumeration":
-		for _, av := range schema.AllowableValues {
-			if value.String() == av {
-				return true
-			}
-		}
-		return false
-
-	case "Integer":
-		if schema.LowerBound == nil || schema.UpperBound == nil {
-			// return true if no settings to check validity
-			return true
-		}
-		return (value.IntValue() >= *schema.LowerBound && value.IntValue() <= *schema.UpperBound)
-
-	case "String":
-		if schema.MinLength == nil || schema.MaxLength == nil {
-			// return true if no settings to check validity
-			return true
-		}
-		return (len(value.String()) >= *schema.MinLength && len(value.String()) <= *schema.MaxLength)
-
-	case "Boolean":
-		return (value.String() == "true" || value.String() == "false")
-
-	case "Password":
-		// Prevent sets of password types
-		return false
-
-	case "":
-		// allow the set as BIOS registry fields may not have been available
-		return true
-
-	default:
-		// Unexpected attribute type
-		return false
-	}
-}
-
-//+kubebuilder:object:root=true
-
-// FirmwareSchemaList contains a list of FirmwareSchema
-type FirmwareSchemaList struct {
-	metav1.TypeMeta `json:",inline"`
-	metav1.ListMeta `json:"metadata,omitempty"`
-	Items           []FirmwareSchema `json:"items"`
-}
-
-func init() {
-	SchemeBuilder.Register(&FirmwareSchema{}, &FirmwareSchemaList{})
-}
diff --git a/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go b/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go
deleted file mode 100644
index 1d955899..00000000
--- a/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1alpha1
-
-import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
-)
-
-// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
-
-type SettingsMap map[string]string
-type DesiredSettingsMap map[string]intstr.IntOrString
-
-type SchemaReference struct {
-	// `namespace` is the namespace of the where the schema is stored.
-	Namespace string `json:"namespace"`
-	// `name` is the reference to the schema.
-	Name string `json:"name"`
-}
-
-// 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"`
-}
-
-// HostFirmwareSettingsStatus defines the observed state of HostFirmwareSettings
-type HostFirmwareSettingsStatus struct {
-	// FirmwareSchema is a reference to the Schema used to describe each
-	// FirmwareSetting. By default, this will be a Schema in the same
-	// Namespace as the settings but it can be overwritten in the Spec
-	FirmwareSchema *SchemaReference `json:"schema,omitempty"`
-
-	// Settings are the actual firmware settings stored as name/value pairs
-	Settings SettingsMap `json:"settings" required:"true"`
-}
-
-//+kubebuilder:object:root=true
-//+kubebuilder:subresource:status
-
-// HostFirmwareSettings is the Schema for the hostfirmwaresettings API
-type HostFirmwareSettings struct {
-	metav1.TypeMeta   `json:",inline"`
-	metav1.ObjectMeta `json:"metadata,omitempty"`
-
-	Spec   HostFirmwareSettingsSpec   `json:"spec,omitempty"`
-	Status HostFirmwareSettingsStatus `json:"status,omitempty"`
-}
-
-//+kubebuilder:object:root=true
-
-// HostFirmwareSettingsList contains a list of HostFirmwareSettings
-type HostFirmwareSettingsList struct {
-	metav1.TypeMeta `json:",inline"`
-	metav1.ListMeta `json:"metadata,omitempty"`
-	Items           []HostFirmwareSettings `json:"items"`
-}
-
-func init() {
-	SchemeBuilder.Register(&HostFirmwareSettings{}, &HostFirmwareSettingsList{})
-}
diff --git a/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go b/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go
index 44ab715e..c0d9bbf8 100644
--- a/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go
@@ -265,27 +265,6 @@ func (in *CustomDeploy) DeepCopy() *CustomDeploy {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in DesiredSettingsMap) DeepCopyInto(out *DesiredSettingsMap) {
-	{
-		in := &in
-		*out = make(DesiredSettingsMap, len(*in))
-		for key, val := range *in {
-			(*out)[key] = val
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DesiredSettingsMap.
-func (in DesiredSettingsMap) DeepCopy() DesiredSettingsMap {
-	if in == nil {
-		return nil
-	}
-	out := new(DesiredSettingsMap)
-	in.DeepCopyInto(out)
-	return *out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Firmware) DeepCopyInto(out *Firmware) {
 	*out = *in
@@ -332,86 +311,6 @@ func (in *FirmwareConfig) DeepCopy() *FirmwareConfig {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FirmwareSchema) DeepCopyInto(out *FirmwareSchema) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	in.Spec.DeepCopyInto(&out.Spec)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirmwareSchema.
-func (in *FirmwareSchema) DeepCopy() *FirmwareSchema {
-	if in == nil {
-		return nil
-	}
-	out := new(FirmwareSchema)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *FirmwareSchema) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FirmwareSchemaList) DeepCopyInto(out *FirmwareSchemaList) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ListMeta.DeepCopyInto(&out.ListMeta)
-	if in.Items != nil {
-		in, out := &in.Items, &out.Items
-		*out = make([]FirmwareSchema, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirmwareSchemaList.
-func (in *FirmwareSchemaList) DeepCopy() *FirmwareSchemaList {
-	if in == nil {
-		return nil
-	}
-	out := new(FirmwareSchemaList)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *FirmwareSchemaList) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FirmwareSchemaSpec) DeepCopyInto(out *FirmwareSchemaSpec) {
-	*out = *in
-	if in.Schema != nil {
-		in, out := &in.Schema, &out.Schema
-		*out = make(map[string]SettingSchema, len(*in))
-		for key, val := range *in {
-			(*out)[key] = *val.DeepCopy()
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirmwareSchemaSpec.
-func (in *FirmwareSchemaSpec) DeepCopy() *FirmwareSchemaSpec {
-	if in == nil {
-		return nil
-	}
-	out := new(FirmwareSchemaSpec)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *HardwareDetails) DeepCopyInto(out *HardwareDetails) {
 	*out = *in
@@ -487,114 +386,6 @@ func (in *HardwareSystemVendor) DeepCopy() *HardwareSystemVendor {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HostFirmwareSettings) DeepCopyInto(out *HostFirmwareSettings) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	in.Spec.DeepCopyInto(&out.Spec)
-	in.Status.DeepCopyInto(&out.Status)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostFirmwareSettings.
-func (in *HostFirmwareSettings) DeepCopy() *HostFirmwareSettings {
-	if in == nil {
-		return nil
-	}
-	out := new(HostFirmwareSettings)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *HostFirmwareSettings) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HostFirmwareSettingsList) DeepCopyInto(out *HostFirmwareSettingsList) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ListMeta.DeepCopyInto(&out.ListMeta)
-	if in.Items != nil {
-		in, out := &in.Items, &out.Items
-		*out = make([]HostFirmwareSettings, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostFirmwareSettingsList.
-func (in *HostFirmwareSettingsList) DeepCopy() *HostFirmwareSettingsList {
-	if in == nil {
-		return nil
-	}
-	out := new(HostFirmwareSettingsList)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *HostFirmwareSettingsList) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HostFirmwareSettingsSpec) DeepCopyInto(out *HostFirmwareSettingsSpec) {
-	*out = *in
-	if in.Settings != nil {
-		in, out := &in.Settings, &out.Settings
-		*out = make(DesiredSettingsMap, len(*in))
-		for key, val := range *in {
-			(*out)[key] = val
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostFirmwareSettingsSpec.
-func (in *HostFirmwareSettingsSpec) DeepCopy() *HostFirmwareSettingsSpec {
-	if in == nil {
-		return nil
-	}
-	out := new(HostFirmwareSettingsSpec)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *HostFirmwareSettingsStatus) DeepCopyInto(out *HostFirmwareSettingsStatus) {
-	*out = *in
-	if in.FirmwareSchema != nil {
-		in, out := &in.FirmwareSchema, &out.FirmwareSchema
-		*out = new(SchemaReference)
-		**out = **in
-	}
-	if in.Settings != nil {
-		in, out := &in.Settings, &out.Settings
-		*out = make(SettingsMap, len(*in))
-		for key, val := range *in {
-			(*out)[key] = val
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostFirmwareSettingsStatus.
-func (in *HostFirmwareSettingsStatus) DeepCopy() *HostFirmwareSettingsStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(HostFirmwareSettingsStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Image) DeepCopyInto(out *Image) {
 	*out = *in
@@ -771,97 +562,6 @@ func (in *RootDeviceHints) DeepCopy() *RootDeviceHints {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SchemaReference) DeepCopyInto(out *SchemaReference) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchemaReference.
-func (in *SchemaReference) DeepCopy() *SchemaReference {
-	if in == nil {
-		return nil
-	}
-	out := new(SchemaReference)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SettingSchema) DeepCopyInto(out *SettingSchema) {
-	*out = *in
-	if in.AllowableValues != nil {
-		in, out := &in.AllowableValues, &out.AllowableValues
-		*out = make([]string, len(*in))
-		copy(*out, *in)
-	}
-	if in.LowerBound != nil {
-		in, out := &in.LowerBound, &out.LowerBound
-		*out = new(int)
-		**out = **in
-	}
-	if in.UpperBound != nil {
-		in, out := &in.UpperBound, &out.UpperBound
-		*out = new(int)
-		**out = **in
-	}
-	if in.MinLength != nil {
-		in, out := &in.MinLength, &out.MinLength
-		*out = new(int)
-		**out = **in
-	}
-	if in.MaxLength != nil {
-		in, out := &in.MaxLength, &out.MaxLength
-		*out = new(int)
-		**out = **in
-	}
-	if in.ReadOnly != nil {
-		in, out := &in.ReadOnly, &out.ReadOnly
-		*out = new(bool)
-		**out = **in
-	}
-	if in.ResetRequired != nil {
-		in, out := &in.ResetRequired, &out.ResetRequired
-		*out = new(bool)
-		**out = **in
-	}
-	if in.Unique != nil {
-		in, out := &in.Unique, &out.Unique
-		*out = new(bool)
-		**out = **in
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SettingSchema.
-func (in *SettingSchema) DeepCopy() *SettingSchema {
-	if in == nil {
-		return nil
-	}
-	out := new(SettingSchema)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in SettingsMap) DeepCopyInto(out *SettingsMap) {
-	{
-		in := &in
-		*out = make(SettingsMap, len(*in))
-		for key, val := range *in {
-			(*out)[key] = val
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SettingsMap.
-func (in SettingsMap) DeepCopy() SettingsMap {
-	if in == nil {
-		return nil
-	}
-	out := new(SettingsMap)
-	in.DeepCopyInto(out)
-	return *out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SoftwareRAIDVolume) DeepCopyInto(out *SoftwareRAIDVolume) {
 	*out = *in
diff --git a/config/crd/bases/metal3.io_firmwareschemas.yaml b/config/crd/bases/metal3.io_firmwareschemas.yaml
deleted file mode 100644
index 02030c87..00000000
--- a/config/crd/bases/metal3.io_firmwareschemas.yaml
+++ /dev/null
@@ -1,100 +0,0 @@
-
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.4.1
-  creationTimestamp: null
-  name: firmwareschemas.metal3.io
-spec:
-  group: metal3.io
-  names:
-    kind: FirmwareSchema
-    listKind: FirmwareSchemaList
-    plural: firmwareschemas
-    singular: firmwareschema
-  scope: Namespaced
-  versions:
-  - name: v1alpha1
-    schema:
-      openAPIV3Schema:
-        description: FirmwareSchema is the Schema for the firmwareschemas API
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: FirmwareSchemaSpec defines the desired state of FirmwareSchema
-            properties:
-              hardwareModel:
-                description: The hardware model associated with this schema
-                type: string
-              hardwareVendor:
-                description: The hardware vendor associated with this schema
-                type: string
-              schema:
-                additionalProperties:
-                  description: Additional data describing the firmware setting
-                  properties:
-                    allowable_values:
-                      description: The allowable value for an Enumeration type setting.
-                      items:
-                        type: string
-                      type: array
-                    attribute_type:
-                      description: The type of setting.
-                      enum:
-                      - Enumeration
-                      - String
-                      - Integer
-                      - Boolean
-                      - Password
-                      type: string
-                    lower_bound:
-                      description: The lowest value for an Integer type setting.
-                      type: integer
-                    max_length:
-                      description: Maximum length for a String type setting.
-                      type: integer
-                    min_length:
-                      description: Minimum length for a String type setting.
-                      type: integer
-                    read_only:
-                      description: Whether or not this setting is read only.
-                      type: boolean
-                    reset_required:
-                      description: Whether or not a reset is required after changing
-                        this setting.
-                      type: boolean
-                    unique:
-                      description: Whether or not this setting's value is unique to
-                        this node, e.g. a serial number.
-                      type: boolean
-                    upper_bound:
-                      description: The highest value for an Integer type setting.
-                      type: integer
-                  type: object
-                description: Map of firmware name to schema
-                type: object
-            required:
-            - schema
-            type: object
-        type: object
-    served: true
-    storage: true
-status:
-  acceptedNames:
-    kind: ""
-    plural: ""
-  conditions: []
-  storedVersions: []
diff --git a/config/crd/bases/metal3.io_hostfirmwaresettings.yaml b/config/crd/bases/metal3.io_hostfirmwaresettings.yaml
deleted file mode 100644
index e8dea176..00000000
--- a/config/crd/bases/metal3.io_hostfirmwaresettings.yaml
+++ /dev/null
@@ -1,93 +0,0 @@
-
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.4.1
-  creationTimestamp: null
-  name: hostfirmwaresettings.metal3.io
-spec:
-  group: metal3.io
-  names:
-    kind: HostFirmwareSettings
-    listKind: HostFirmwareSettingsList
-    plural: hostfirmwaresettings
-    singular: hostfirmwaresettings
-  scope: Namespaced
-  versions:
-  - name: v1alpha1
-    schema:
-      openAPIV3Schema:
-        description: HostFirmwareSettings is the Schema for the hostfirmwaresettings
-          API
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: HostFirmwareSettingsSpec defines the desired state of HostFirmwareSettings
-            properties:
-              settings:
-                additionalProperties:
-                  anyOf:
-                  - type: integer
-                  - type: string
-                  x-kubernetes-int-or-string: true
-                description: 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.
-                type: object
-            required:
-            - settings
-            type: object
-          status:
-            description: HostFirmwareSettingsStatus defines the observed state of
-              HostFirmwareSettings
-            properties:
-              schema:
-                description: FirmwareSchema is a reference to the Schema used to describe
-                  each FirmwareSetting. By default, this will be a Schema in the same
-                  Namespace as the settings but it can be overwritten in the Spec
-                properties:
-                  name:
-                    description: '`name` is the reference to the schema.'
-                    type: string
-                  namespace:
-                    description: '`namespace` is the namespace of the where the schema
-                      is stored.'
-                    type: string
-                required:
-                - name
-                - namespace
-                type: object
-              settings:
-                additionalProperties:
-                  type: string
-                description: Settings are the actual firmware settings stored as name/value
-                  pairs
-                type: object
-            required:
-            - settings
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
-status:
-  acceptedNames:
-    kind: ""
-    plural: ""
-  conditions: []
-  storedVersions: []
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index 29db00a2..d6d78cc5 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -3,23 +3,17 @@
 # It should be run by config/default
 resources:
 - bases/metal3.io_baremetalhosts.yaml
-- bases/metal3.io_hostfirmwaresettings.yaml
-- bases/metal3.io_firmwareschemas.yaml
 # +kubebuilder:scaffold:crdkustomizeresource
 
 patchesStrategicMerge:
 # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
 # patches here are for enabling the conversion webhook for each CRD
 #- patches/webhook_in_baremetalhosts.yaml
-#- patches/webhook_in_hostfirmwaresettings.yaml
-#- patches/webhook_in_firmwareschemas.yaml
 # +kubebuilder:scaffold:crdkustomizewebhookpatch
 
 # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
 # patches here are for enabling the CA injection for each CRD
 #- patches/cainjection_in_baremetalhosts.yaml
-#- patches/cainjection_in_hostfirmwaresettings.yaml
-#- patches/cainjection_in_firmwareschemas.yaml
 # +kubebuilder:scaffold:crdkustomizecainjectionpatch
 
 # the following config is for teaching kustomize how to do kustomization for CRDs.
diff --git a/config/crd/patches/cainjection_in_firmwareschemas.yaml b/config/crd/patches/cainjection_in_firmwareschemas.yaml
deleted file mode 100644
index dd50dd1a..00000000
--- a/config/crd/patches/cainjection_in_firmwareschemas.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-# The following patch adds a directive for certmanager to inject CA into the CRD
-# CRD conversion requires k8s 1.13 or later.
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
-  name: firmwareschemas.metal3.io
diff --git a/config/crd/patches/cainjection_in_hostfirmwaresettings.yaml b/config/crd/patches/cainjection_in_hostfirmwaresettings.yaml
deleted file mode 100644
index 4d81f6e4..00000000
--- a/config/crd/patches/cainjection_in_hostfirmwaresettings.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-# The following patch adds a directive for certmanager to inject CA into the CRD
-# CRD conversion requires k8s 1.13 or later.
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
-  name: hostfirmwaresettings.metal3.io
diff --git a/config/crd/patches/webhook_in_firmwareschemas.yaml b/config/crd/patches/webhook_in_firmwareschemas.yaml
deleted file mode 100644
index f65cf2fb..00000000
--- a/config/crd/patches/webhook_in_firmwareschemas.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-# The following patch enables conversion webhook for CRD
-# CRD conversion requires k8s 1.13 or later.
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: firmwareschemas.metal3.io
-spec:
-  conversion:
-    strategy: Webhook
-    webhookClientConfig:
-      # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
-      # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
-      caBundle: Cg==
-      service:
-        namespace: system
-        name: webhook-service
-        path: /convert
diff --git a/config/crd/patches/webhook_in_hostfirmwaresettings.yaml b/config/crd/patches/webhook_in_hostfirmwaresettings.yaml
deleted file mode 100644
index 2e32829d..00000000
--- a/config/crd/patches/webhook_in_hostfirmwaresettings.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-# The following patch enables conversion webhook for CRD
-# CRD conversion requires k8s 1.13 or later.
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: hostfirmwaresettings.metal3.io
-spec:
-  conversion:
-    strategy: Webhook
-    webhookClientConfig:
-      # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
-      # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
-      caBundle: Cg==
-      service:
-        namespace: system
-        name: webhook-service
-        path: /convert
diff --git a/config/rbac/firmwareschema_editor_role.yaml b/config/rbac/firmwareschema_editor_role.yaml
deleted file mode 100644
index be313f63..00000000
--- a/config/rbac/firmwareschema_editor_role.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-# permissions for end users to edit firmwareschemas.
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
-  name: firmwareschema-editor-role
-rules:
-- apiGroups:
-  - metal3.io
-  resources:
-  - firmwareschemas
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
-- apiGroups:
-  - metal3.io
-  resources:
-  - firmwareschemas/status
-  verbs:
-  - get
diff --git a/config/rbac/firmwareschema_viewer_role.yaml b/config/rbac/firmwareschema_viewer_role.yaml
deleted file mode 100644
index 90691038..00000000
--- a/config/rbac/firmwareschema_viewer_role.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# permissions for end users to view firmwareschemas.
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
-  name: firmwareschema-viewer-role
-rules:
-- apiGroups:
-  - metal3.io
-  resources:
-  - firmwareschemas
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metal3.io
-  resources:
-  - firmwareschemas/status
-  verbs:
-  - get
diff --git a/config/rbac/hostfirmwaresettings_editor_role.yaml b/config/rbac/hostfirmwaresettings_editor_role.yaml
deleted file mode 100644
index 64b1d5da..00000000
--- a/config/rbac/hostfirmwaresettings_editor_role.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-# permissions for end users to edit hostfirmwaresettings.
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
-  name: hostfirmwaresettings-editor-role
-rules:
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwaresettings
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwaresettings/status
-  verbs:
-  - get
diff --git a/config/rbac/hostfirmwaresettings_viewer_role.yaml b/config/rbac/hostfirmwaresettings_viewer_role.yaml
deleted file mode 100644
index 5235eb6b..00000000
--- a/config/rbac/hostfirmwaresettings_viewer_role.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# permissions for end users to view hostfirmwaresettings.
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
-  name: hostfirmwaresettings-viewer-role
-rules:
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwaresettings
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwaresettings/status
-  verbs:
-  - get
diff --git a/config/render/capm3.yaml b/config/render/capm3.yaml
index 50b654dd..d344303b 100644
--- a/config/render/capm3.yaml
+++ b/config/render/capm3.yaml
@@ -1083,197 +1083,6 @@ status:
   conditions: []
   storedVersions: []
 ---
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.4.1
-  creationTimestamp: null
-  name: firmwareschemas.metal3.io
-spec:
-  group: metal3.io
-  names:
-    kind: FirmwareSchema
-    listKind: FirmwareSchemaList
-    plural: firmwareschemas
-    singular: firmwareschema
-  scope: Namespaced
-  versions:
-  - name: v1alpha1
-    schema:
-      openAPIV3Schema:
-        description: FirmwareSchema is the Schema for the firmwareschemas API
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: FirmwareSchemaSpec defines the desired state of FirmwareSchema
-            properties:
-              hardwareModel:
-                description: The hardware model associated with this schema
-                type: string
-              hardwareVendor:
-                description: The hardware vendor associated with this schema
-                type: string
-              schema:
-                additionalProperties:
-                  description: Additional data describing the firmware setting
-                  properties:
-                    allowable_values:
-                      description: The allowable value for an Enumeration type setting.
-                      items:
-                        type: string
-                      type: array
-                    attribute_type:
-                      description: The type of setting.
-                      enum:
-                      - Enumeration
-                      - String
-                      - Integer
-                      - Boolean
-                      - Password
-                      type: string
-                    lower_bound:
-                      description: The lowest value for an Integer type setting.
-                      type: integer
-                    max_length:
-                      description: Maximum length for a String type setting.
-                      type: integer
-                    min_length:
-                      description: Minimum length for a String type setting.
-                      type: integer
-                    read_only:
-                      description: Whether or not this setting is read only.
-                      type: boolean
-                    reset_required:
-                      description: Whether or not a reset is required after changing
-                        this setting.
-                      type: boolean
-                    unique:
-                      description: Whether or not this setting's value is unique to
-                        this node, e.g. a serial number.
-                      type: boolean
-                    upper_bound:
-                      description: The highest value for an Integer type setting.
-                      type: integer
-                  type: object
-                description: Map of firmware name to schema
-                type: object
-            required:
-            - schema
-            type: object
-        type: object
-    served: true
-    storage: true
-status:
-  acceptedNames:
-    kind: ""
-    plural: ""
-  conditions: []
-  storedVersions: []
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.4.1
-  creationTimestamp: null
-  name: hostfirmwaresettings.metal3.io
-spec:
-  group: metal3.io
-  names:
-    kind: HostFirmwareSettings
-    listKind: HostFirmwareSettingsList
-    plural: hostfirmwaresettings
-    singular: hostfirmwaresettings
-  scope: Namespaced
-  versions:
-  - name: v1alpha1
-    schema:
-      openAPIV3Schema:
-        description: HostFirmwareSettings is the Schema for the hostfirmwaresettings
-          API
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: HostFirmwareSettingsSpec defines the desired state of HostFirmwareSettings
-            properties:
-              settings:
-                additionalProperties:
-                  anyOf:
-                  - type: integer
-                  - type: string
-                  x-kubernetes-int-or-string: true
-                description: 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.
-                type: object
-            required:
-            - settings
-            type: object
-          status:
-            description: HostFirmwareSettingsStatus defines the observed state of
-              HostFirmwareSettings
-            properties:
-              schema:
-                description: FirmwareSchema is a reference to the Schema used to describe
-                  each FirmwareSetting. By default, this will be a Schema in the same
-                  Namespace as the settings but it can be overwritten in the Spec
-                properties:
-                  name:
-                    description: '`name` is the reference to the schema.'
-                    type: string
-                  namespace:
-                    description: '`namespace` is the namespace of the where the schema
-                      is stored.'
-                    type: string
-                required:
-                - name
-                - namespace
-                type: object
-              settings:
-                additionalProperties:
-                  type: string
-                description: Settings are the actual firmware settings stored as name/value
-                  pairs
-                type: object
-            required:
-            - settings
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
-status:
-  acceptedNames:
-    kind: ""
-    plural: ""
-  conditions: []
-  storedVersions: []
----
 apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
diff --git a/config/samples/metal3.io_v1alpha1_firmwareschema.yaml b/config/samples/metal3.io_v1alpha1_firmwareschema.yaml
deleted file mode 100644
index f5777284..00000000
--- a/config/samples/metal3.io_v1alpha1_firmwareschema.yaml
+++ /dev/null
@@ -1,34 +0,0 @@
-apiVersion: metal3.io/v1alpha1
-kind: FirmwareSchema
-metadata:
-  name: firmwareschema-sample
-spec:
-status:
-  referenceCount: 2
-  hardwareVendor: "VendorA"
-  hardwareModel: "ModelT"
-  schema:
-    - "ProcVirtualization":
-         attribute_type: "Enumeration"
-         allowable_values:
-           - "Enabled"
-           - "Disabled"
-         read_only: false
-    - "ProcCPUCores":
-         attribute_type: "Integer"
-         lower_bound: 1
-         read_only: true
-         upper_bound: 100
-    - "SRIOV":
-         allowable_values:
-           - "Enabled"
-           - "Disabled"
-    - "SystemModelName":
-         attribute_type: "String"
-         max_length: 40
-         min_length: 0
-         read_only: true
-    - "SerialNumber":
-         attribute_type: "String"
-         max_length: 16
-         min_length: 0
diff --git a/config/samples/metal3.io_v1alpha1_hostfirmwaresettings.yaml b/config/samples/metal3.io_v1alpha1_hostfirmwaresettings.yaml
deleted file mode 100644
index 268335bf..00000000
--- a/config/samples/metal3.io_v1alpha1_hostfirmwaresettings.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-apiVersion: metal3.io/v1alpha1
-kind: HostFirmwareSettings
-metadata:
-  name: hostfirmwaresettings-sample
-spec:
-  settings:
-    - "ProcVirtualization": "Enabled"
-    - "SRIOV": "Enabled"
-    - "NetworkBootRetryCount": "20"
-status:
-  settings:
-    - "ProcVirtualization": "Enabled"
-    - "ProcCPUCores": "100"
-    - "SRIOV": "Enabled"
-    - "SystemModelName":  "QYZ12345"
-    - "SerialNumber": "22654891"
-    - "NetworkBootRetryCount": "10"
diff --git a/config/tls/kustomization.yaml b/config/tls/kustomization.yaml
index cdafae35..0af5f2e1 100644
--- a/config/tls/kustomization.yaml
+++ b/config/tls/kustomization.yaml
@@ -5,5 +5,10 @@ resources:
 - ../default
 - ../namespace
 
+secretGenerator:
+  - name: ironic-cacert
+    files:
+    - crt=ca.crt
+
 patchesStrategicMerge:
 - tls_ca_patch.yaml
diff --git a/controllers/metal3.io/baremetalhost_controller.go b/controllers/metal3.io/baremetalhost_controller.go
index 51e8447d..8f5e4f3a 100644
--- a/controllers/metal3.io/baremetalhost_controller.go
+++ b/controllers/metal3.io/baremetalhost_controller.go
@@ -1014,12 +1014,9 @@ func (r *BareMetalHostReconciler) manageHostPower(prov provisioner.Provisioner,
 		"reboot process", desiredPowerOnState != info.host.Spec.Online)
 
 	if desiredPowerOnState {
-		provResult, err = prov.PowerOn(info.host.Status.ErrorType == metal3v1alpha1.PowerManagementError)
+		provResult, err = prov.PowerOn()
 	} else {
-		if info.host.Status.ErrorCount > 0 {
-			desiredRebootMode = metal3v1alpha1.RebootModeHard
-		}
-		provResult, err = prov.PowerOff(desiredRebootMode, info.host.Status.ErrorType == metal3v1alpha1.PowerManagementError)
+		provResult, err = prov.PowerOff(desiredRebootMode)
 	}
 	if err != nil {
 		return actionError{errors.Wrap(err, "failed to manage power state of host")}
diff --git a/ironic-deployment/basic-auth/default/auth.yaml b/ironic-deployment/basic-auth/default/auth.yaml
index 98550cff..356ea2f6 100644
--- a/ironic-deployment/basic-auth/default/auth.yaml
+++ b/ironic-deployment/basic-auth/default/auth.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: ${NAMEPREFIX}-ironic
+  name: capm3-ironic
 spec:
   template:
     spec:
diff --git a/ironic-deployment/basic-auth/default/kustomization.yaml b/ironic-deployment/basic-auth/default/kustomization.yaml
index 1e6cceba..36370e8a 100644
--- a/ironic-deployment/basic-auth/default/kustomization.yaml
+++ b/ironic-deployment/basic-auth/default/kustomization.yaml
@@ -1,6 +1,6 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
-namespace: ${NAMEPREFIX}-system
+namespace: capm3-system
 resources:
 - ../../default
 
diff --git a/ironic-deployment/basic-auth/keepalived/auth.yaml b/ironic-deployment/basic-auth/keepalived/auth.yaml
index 98550cff..356ea2f6 100644
--- a/ironic-deployment/basic-auth/keepalived/auth.yaml
+++ b/ironic-deployment/basic-auth/keepalived/auth.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: ${NAMEPREFIX}-ironic
+  name: capm3-ironic
 spec:
   template:
     spec:
diff --git a/ironic-deployment/basic-auth/keepalived/kustomization.yaml b/ironic-deployment/basic-auth/keepalived/kustomization.yaml
index 34061bde..c2514726 100644
--- a/ironic-deployment/basic-auth/keepalived/kustomization.yaml
+++ b/ironic-deployment/basic-auth/keepalived/kustomization.yaml
@@ -1,6 +1,6 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
-namespace: ${NAMEPREFIX}-system
+namespace: capm3-system
 resources:
 - ../../keepalived
 
diff --git a/ironic-deployment/basic-auth/tls/default/auth.yaml b/ironic-deployment/basic-auth/tls/default/auth.yaml
index 98550cff..356ea2f6 100644
--- a/ironic-deployment/basic-auth/tls/default/auth.yaml
+++ b/ironic-deployment/basic-auth/tls/default/auth.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: ${NAMEPREFIX}-ironic
+  name: capm3-ironic
 spec:
   template:
     spec:
diff --git a/ironic-deployment/basic-auth/tls/default/kustomization.yaml b/ironic-deployment/basic-auth/tls/default/kustomization.yaml
index a750b9ac..ff711f7e 100644
--- a/ironic-deployment/basic-auth/tls/default/kustomization.yaml
+++ b/ironic-deployment/basic-auth/tls/default/kustomization.yaml
@@ -1,6 +1,6 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
-namespace: ${NAMEPREFIX}-system
+namespace: capm3-system
 resources:
 - ../../../tls/default
 
diff --git a/ironic-deployment/basic-auth/tls/keepalived/auth.yaml b/ironic-deployment/basic-auth/tls/keepalived/auth.yaml
index 98550cff..356ea2f6 100644
--- a/ironic-deployment/basic-auth/tls/keepalived/auth.yaml
+++ b/ironic-deployment/basic-auth/tls/keepalived/auth.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: ${NAMEPREFIX}-ironic
+  name: capm3-ironic
 spec:
   template:
     spec:
diff --git a/ironic-deployment/basic-auth/tls/keepalived/kustomization.yaml b/ironic-deployment/basic-auth/tls/keepalived/kustomization.yaml
index fa1188c9..06751477 100644
--- a/ironic-deployment/basic-auth/tls/keepalived/kustomization.yaml
+++ b/ironic-deployment/basic-auth/tls/keepalived/kustomization.yaml
@@ -1,6 +1,6 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
-namespace: ${NAMEPREFIX}-system
+namespace: capm3-system
 resources:
 - ../../../tls/keepalived
 
diff --git a/ironic-deployment/certmanager/certificate.yaml b/ironic-deployment/certmanager/certificate.yaml
index 6a9cea6b..476cd135 100644
--- a/ironic-deployment/certmanager/certificate.yaml
+++ b/ironic-deployment/certmanager/certificate.yaml
@@ -2,7 +2,7 @@ apiVersion: cert-manager.io/v1
 kind: Issuer
 metadata:
   name: selfsigned-issuer
-  namespace: ${NAMEPREFIX}-system
+  namespace: capm3-system
 spec:
   selfSigned: {}
 ---
@@ -10,7 +10,7 @@ apiVersion: cert-manager.io/v1
 kind: Certificate
 metadata:
   name: ironic-cacert
-  namespace: ${NAMEPREFIX}-system
+  namespace: capm3-system
 spec:
   isCA: true
   ipAddresses:
@@ -24,7 +24,7 @@ apiVersion: cert-manager.io/v1
 kind: Issuer
 metadata:
   name: ca-issuer
-  namespace: ${NAMEPREFIX}-system
+  namespace: capm3-system
 spec:
   ca:
     secretName: ironic-cacert
@@ -33,7 +33,7 @@ apiVersion: cert-manager.io/v1
 kind: Certificate
 metadata:
   name: ironic-cert
-  namespace: ${NAMEPREFIX}-system
+  namespace: capm3-system
 spec:
   ipAddresses:
   - IRONIC_HOST_IP
@@ -46,7 +46,7 @@ apiVersion: cert-manager.io/v1
 kind: Certificate
 metadata:
   name: ironic-inspector-cert
-  namespace: ${NAMEPREFIX}-system
+  namespace: capm3-system
 spec:
   ipAddresses:
   - IRONIC_HOST_IP
@@ -59,7 +59,7 @@ apiVersion: cert-manager.io/v1
 kind: Certificate
 metadata:
   name: mariadb-cert
-  namespace: ${NAMEPREFIX}-system
+  namespace: capm3-system
 spec:
   ipAddresses:
   - MARIADB_HOST_IP
diff --git a/ironic-deployment/default/kustomization.yaml b/ironic-deployment/default/kustomization.yaml
index 48c0842f..b0f162b5 100644
--- a/ironic-deployment/default/kustomization.yaml
+++ b/ironic-deployment/default/kustomization.yaml
@@ -1,6 +1,6 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
-namespace: ${NAMEPREFIX}-system
+namespace: capm3-system
 resources:
 - ../ironic
 configMapGenerator:
diff --git a/ironic-deployment/ironic/ironic.yaml b/ironic-deployment/ironic/ironic.yaml
index e6cc3651..788646a9 100644
--- a/ironic-deployment/ironic/ironic.yaml
+++ b/ironic-deployment/ironic/ironic.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: ${NAMEPREFIX}-ironic
+  name: capm3-ironic
 spec:
   replicas: 1
   strategy:
@@ -10,11 +10,11 @@ spec:
     type: Recreate
   selector:
     matchLabels:
-      name: ${NAMEPREFIX}-ironic
+      name: capm3-ironic
   template:
     metadata:
       labels:
-        name: ${NAMEPREFIX}-ironic
+        name: capm3-ironic
     spec:
       hostNetwork: true
       containers:
diff --git a/ironic-deployment/keepalived/keepalived_patch.yaml b/ironic-deployment/keepalived/keepalived_patch.yaml
index 95552903..23614ac9 100644
--- a/ironic-deployment/keepalived/keepalived_patch.yaml
+++ b/ironic-deployment/keepalived/keepalived_patch.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: ${NAMEPREFIX}-ironic
+  name: capm3-ironic
 spec:
   template:
     spec:
diff --git a/ironic-deployment/keepalived/kustomization.yaml b/ironic-deployment/keepalived/kustomization.yaml
index 847439b1..daedb24e 100644
--- a/ironic-deployment/keepalived/kustomization.yaml
+++ b/ironic-deployment/keepalived/kustomization.yaml
@@ -1,6 +1,6 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
-namespace: ${NAMEPREFIX}-system
+namespace: capm3-system
 resources:
 - ../../config/namespace
 - ../ironic
diff --git a/ironic-deployment/tls/default/kustomization.yaml b/ironic-deployment/tls/default/kustomization.yaml
index 44ac055f..a84fe668 100644
--- a/ironic-deployment/tls/default/kustomization.yaml
+++ b/ironic-deployment/tls/default/kustomization.yaml
@@ -1,6 +1,6 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
-namespace: ${NAMEPREFIX}-system
+namespace: capm3-system
 resources:
 - ../../default
 - ../../certmanager
diff --git a/ironic-deployment/tls/default/tls.yaml b/ironic-deployment/tls/default/tls.yaml
index 4a0bf9c1..107ec414 100644
--- a/ironic-deployment/tls/default/tls.yaml
+++ b/ironic-deployment/tls/default/tls.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: ${NAMEPREFIX}-ironic
+  name: capm3-ironic
 spec:
   template:
     spec:
diff --git a/ironic-deployment/tls/keepalived/kustomization.yaml b/ironic-deployment/tls/keepalived/kustomization.yaml
index ce39a6d1..0ff81618 100644
--- a/ironic-deployment/tls/keepalived/kustomization.yaml
+++ b/ironic-deployment/tls/keepalived/kustomization.yaml
@@ -1,6 +1,6 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
-namespace: ${NAMEPREFIX}-system
+namespace: capm3-system
 resources:
 - ../../keepalived
 - ../../certmanager
diff --git a/ironic-deployment/tls/keepalived/tls.yaml b/ironic-deployment/tls/keepalived/tls.yaml
index 818d3436..718ec054 100644
--- a/ironic-deployment/tls/keepalived/tls.yaml
+++ b/ironic-deployment/tls/keepalived/tls.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: ${NAMEPREFIX}-ironic
+  name: capm3-ironic
 spec:
   template:
     spec:
diff --git a/pkg/bmc/irmc.go b/pkg/bmc/irmc.go
index 9d9380f0..f6c45c9b 100644
--- a/pkg/bmc/irmc.go
+++ b/pkg/bmc/irmc.go
@@ -99,6 +99,10 @@ func (a *iRMCAccessDetails) BuildBIOSSettings(firmwareConfig *metal3v1alpha1.Fir
 		return nil, nil
 	}
 
+	if firmwareConfig == nil {
+		return nil, nil
+	}
+
 	var value string
 
 	if firmwareConfig.VirtualizationEnabled != nil {
diff --git a/pkg/provisioner/demo/demo.go b/pkg/provisioner/demo/demo.go
index be79a6f4..00741b33 100644
--- a/pkg/provisioner/demo/demo.go
+++ b/pkg/provisioner/demo/demo.go
@@ -305,7 +305,7 @@ func (p *demoProvisioner) Detach() (result provisioner.Result, err error) {
 
 // PowerOn ensures the server is powered on independently of any image
 // provisioning operation.
-func (p *demoProvisioner) PowerOn(force bool) (result provisioner.Result, err error) {
+func (p *demoProvisioner) PowerOn() (result provisioner.Result, err error) {
 
 	hostName := p.objectMeta.Name
 	switch hostName {
@@ -326,7 +326,7 @@ func (p *demoProvisioner) PowerOn(force bool) (result provisioner.Result, err er
 
 // PowerOff ensures the server is powered off independently of any image
 // provisioning operation.
-func (p *demoProvisioner) PowerOff(rebootMode metal3v1alpha1.RebootMode, force bool) (result provisioner.Result, err error) {
+func (p *demoProvisioner) PowerOff(rebootMode metal3v1alpha1.RebootMode) (result provisioner.Result, err error) {
 
 	hostName := p.objectMeta.Name
 	switch hostName {
diff --git a/pkg/provisioner/fixture/fixture.go b/pkg/provisioner/fixture/fixture.go
index b3eee1cf..ab0b2e21 100644
--- a/pkg/provisioner/fixture/fixture.go
+++ b/pkg/provisioner/fixture/fixture.go
@@ -291,7 +291,7 @@ func (p *fixtureProvisioner) Detach() (result provisioner.Result, err error) {
 
 // PowerOn ensures the server is powered on independently of any image
 // provisioning operation.
-func (p *fixtureProvisioner) PowerOn(force bool) (result provisioner.Result, err error) {
+func (p *fixtureProvisioner) PowerOn() (result provisioner.Result, err error) {
 	p.log.Info("ensuring host is powered on")
 
 	if !p.state.poweredOn {
@@ -307,7 +307,7 @@ func (p *fixtureProvisioner) PowerOn(force bool) (result provisioner.Result, err
 
 // PowerOff ensures the server is powered off independently of any image
 // provisioning operation.
-func (p *fixtureProvisioner) PowerOff(rebootMode metal3v1alpha1.RebootMode, force bool) (result provisioner.Result, err error) {
+func (p *fixtureProvisioner) PowerOff(rebootMode metal3v1alpha1.RebootMode) (result provisioner.Result, err error) {
 	p.log.Info("ensuring host is powered off")
 
 	if p.state.poweredOn {
diff --git a/pkg/provisioner/ironic/errors.go b/pkg/provisioner/ironic/errors.go
index 8a69c0cb..c3384bcd 100644
--- a/pkg/provisioner/ironic/errors.go
+++ b/pkg/provisioner/ironic/errors.go
@@ -9,6 +9,15 @@ func (e SoftPowerOffUnsupportedError) Error() string {
 	return "soft power off is unsupported on BMC"
 }
 
+// SoftPowerOffFailed is returned when the soft power off command
+// finishes with failure.
+type SoftPowerOffFailed struct {
+}
+
+func (e SoftPowerOffFailed) Error() string {
+	return "Soft power off has failed on BMC"
+}
+
 // HostLockedError is returned when the BMC host is
 // locked.
 type HostLockedError struct {
diff --git a/pkg/provisioner/ironic/ironic.go b/pkg/provisioner/ironic/ironic.go
index cad96973..95294c15 100644
--- a/pkg/provisioner/ironic/ironic.go
+++ b/pkg/provisioner/ironic/ironic.go
@@ -1517,7 +1517,7 @@ func (p *ironicProvisioner) changePower(ironicNode *nodes.Node, target nodes.Tar
 
 // PowerOn ensures the server is powered on independently of any image
 // provisioning operation.
-func (p *ironicProvisioner) PowerOn(force bool) (result provisioner.Result, err error) {
+func (p *ironicProvisioner) PowerOn() (result provisioner.Result, err error) {
 	p.log.Info("ensuring host is powered on")
 
 	ironicNode, err := p.getNode()
@@ -1533,39 +1533,46 @@ func (p *ironicProvisioner) PowerOn(force bool) (result provisioner.Result, err
 			p.log.Info("waiting for power status to change")
 			return operationContinuing(powerRequeueDelay)
 		}
-		if ironicNode.LastError != "" && !force {
-			p.log.Info("PowerOn operation failed", "msg", ironicNode.LastError)
-			return operationFailed(fmt.Sprintf("PowerOn operation failed: %s",
-				ironicNode.LastError))
-		}
-		if result, err = p.changePower(ironicNode, nodes.PowerOn); err == nil {
-			p.publisher("PowerOn", "Host powered on")
-			return result, nil
-		}
+		result, err = p.changePower(ironicNode, nodes.PowerOn)
 		switch err.(type) {
+		case nil:
 		case HostLockedError:
-			return retryAfterDelay(powerRequeueDelay)
 		default:
-			return transientError(errors.Wrap(err, "failed to PowerOn node"))
+			return transientError(errors.Wrap(err, "failed to power on host"))
 		}
+		p.publisher("PowerOn", "Host powered on")
 	}
+
 	return result, nil
 }
 
 // PowerOff ensures the server is powered off independently of any image
 // provisioning operation.
-func (p *ironicProvisioner) PowerOff(rebootMode metal3v1alpha1.RebootMode, force bool) (result provisioner.Result, err error) {
+func (p *ironicProvisioner) PowerOff(rebootMode metal3v1alpha1.RebootMode) (result provisioner.Result, err error) {
 	p.log.Info(fmt.Sprintf("ensuring host is powered off (mode: %s)", rebootMode))
 
-	if rebootMode == metal3v1alpha1.RebootModeSoft {
-		return p.softPowerOff()
+	if rebootMode == metal3v1alpha1.RebootModeHard {
+		result, err = p.hardPowerOff()
+	} else {
+		result, err = p.softPowerOff()
 	}
-	// Reboot mode is hard or force flag is set
-	return p.hardPowerOff(force)
+	if err != nil {
+		switch err.(type) {
+		// In case of soft power off is unsupported or has failed,
+		// we activate hard power off.
+		case SoftPowerOffUnsupportedError, SoftPowerOffFailed:
+			return p.hardPowerOff()
+		case HostLockedError:
+			return retryAfterDelay(powerRequeueDelay)
+		default:
+			return transientError(err)
+		}
+	}
+	return result, nil
 }
 
 // hardPowerOff sends 'power off' request to BM node and waits for the result
-func (p *ironicProvisioner) hardPowerOff(force bool) (result provisioner.Result, err error) {
+func (p *ironicProvisioner) hardPowerOff() (result provisioner.Result, err error) {
 	p.log.Info("ensuring host is powered off by \"hard power off\" command")
 
 	ironicNode, err := p.getNode()
@@ -1574,22 +1581,13 @@ func (p *ironicProvisioner) hardPowerOff(force bool) (result provisioner.Result,
 	}
 
 	if ironicNode.PowerState != powerOff {
-		if ironicNode.LastError != "" && !force {
-			p.log.Info("hard power off error", "msg", ironicNode.LastError)
-			return operationFailed(ironicNode.LastError)
-		}
 		if ironicNode.TargetPowerState == powerOff {
 			p.log.Info("waiting for power status to change")
 			return operationContinuing(powerRequeueDelay)
 		}
 		result, err = p.changePower(ironicNode, nodes.PowerOff)
 		if err != nil {
-			switch err.(type) {
-			case HostLockedError:
-				return retryAfterDelay(powerRequeueDelay)
-			default:
-				return transientError(errors.Wrap(err, "failed to power off host"))
-			}
+			return transientError(errors.Wrap(err, "failed to power off host"))
 		}
 		p.publisher("PowerOff", "Host powered off")
 		return result, err
@@ -1621,17 +1619,11 @@ func (p *ironicProvisioner) softPowerOff() (result provisioner.Result, err error
 		// If the target state is unset while the last error is set,
 		// then the last execution of soft power off has failed.
 		if targetState == "" && ironicNode.LastError != "" {
-			p.log.Info("soft power off error", "msg", ironicNode.LastError)
-			return operationFailed(ironicNode.LastError)
+			return result, SoftPowerOffFailed{}
 		}
 		result, err = p.changePower(ironicNode, nodes.SoftPowerOff)
 		if err != nil {
-			switch err.(type) {
-			case HostLockedError:
-				return retryAfterDelay(powerRequeueDelay)
-			default:
-				return transientError(errors.Wrap(err, "failed to power off host"))
-			}
+			return transientError(err)
 		}
 		p.publisher("PowerOff", "Host soft powered off")
 	}
diff --git a/pkg/provisioner/ironic/raid.go b/pkg/provisioner/ironic/raid.go
index 5daadbe5..f5293057 100644
--- a/pkg/provisioner/ironic/raid.go
+++ b/pkg/provisioner/ironic/raid.go
@@ -210,10 +210,14 @@ func BuildRAIDCleanSteps(raidInterface string, target *metal3v1alpha1.RAIDConfig
 	}
 
 	// Hardware RAID
-	// Ignore SoftwareRAIDVolumes
-	if target != nil {
-		target.SoftwareRAIDVolumes = nil
+	// If hardware RAID configuration is nil,
+	// keep old hardware RAID configuration
+	if target == nil || target.HardwareRAIDVolumes == nil {
+		return
 	}
+
+	// Ignore SoftwareRAIDVolumes
+	target.SoftwareRAIDVolumes = nil
 	if actual != nil {
 		actual.SoftwareRAIDVolumes = nil
 	}
@@ -232,7 +236,7 @@ func BuildRAIDCleanSteps(raidInterface string, target *metal3v1alpha1.RAIDConfig
 	)
 
 	// If hardware raid configuration is empty, only need to clear old configuration
-	if target == nil || len(target.HardwareRAIDVolumes) == 0 {
+	if len(target.HardwareRAIDVolumes) == 0 {
 		return
 	}
 
diff --git a/pkg/provisioner/provisioner.go b/pkg/provisioner/provisioner.go
index 2c209e12..f23d308a 100644
--- a/pkg/provisioner/provisioner.go
+++ b/pkg/provisioner/provisioner.go
@@ -145,12 +145,12 @@ type Provisioner interface {
 
 	// PowerOn ensures the server is powered on independently of any image
 	// provisioning operation.
-	PowerOn(force bool) (result Result, err error)
+	PowerOn() (result Result, err error)
 
 	// PowerOff ensures the server is powered off independently of any image
 	// provisioning operation. The boolean argument may be used to specify
 	// if a hard reboot (force power off) is required - true if so.
-	PowerOff(rebootMode metal3v1alpha1.RebootMode, force bool) (result Result, err error)
+	PowerOff(rebootMode metal3v1alpha1.RebootMode) (result Result, err error)
 
 	// IsReady checks if the provisioning backend is available to accept
 	// all the incoming requests.
diff --git a/tools/deploy.sh b/tools/deploy.sh
index 9f9bb3e1..d7fbd8be 100755
--- a/tools/deploy.sh
+++ b/tools/deploy.sh
@@ -22,34 +22,9 @@ MARIADB_HOST_IP="${MARIADB_HOST_IP:-"127.0.0.1"}"
 KUBECTL_ARGS="${KUBECTL_ARGS:-""}"
 KUSTOMIZE="go run sigs.k8s.io/kustomize/kustomize/v3"
 RESTART_CONTAINER_CERTIFICATE_UPDATED=${RESTART_CONTAINER_CERTIFICATE_UPDATED:-"false"}
-export NAMEPREFIX=${NAMEPREFIX:-"capm3"}
 
 SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
 
-IRONIC_DEPLOY_FILES="${SCRIPTDIR}/ironic-deployment/basic-auth/default/auth.yaml \
-	${SCRIPTDIR}/ironic-deployment/basic-auth/default/kustomization.yaml \
-	${SCRIPTDIR}/ironic-deployment/basic-auth/keepalived/auth.yaml \
-	${SCRIPTDIR}/ironic-deployment/basic-auth/keepalived/kustomization.yaml \
-	${SCRIPTDIR}/ironic-deployment/basic-auth/tls/default/auth.yaml \
-	${SCRIPTDIR}/ironic-deployment/basic-auth/tls/default/kustomization.yaml \
-	${SCRIPTDIR}/ironic-deployment/basic-auth/tls/keepalived/auth.yaml \
-	${SCRIPTDIR}/ironic-deployment/basic-auth/tls/keepalived/kustomization.yaml \
-	${SCRIPTDIR}/ironic-deployment/certmanager/certificate.yaml \
-	${SCRIPTDIR}/ironic-deployment/default/kustomization.yaml \
-	${SCRIPTDIR}/ironic-deployment/ironic/ironic.yaml \
-	${SCRIPTDIR}/ironic-deployment/keepalived/keepalived_patch.yaml \
-	${SCRIPTDIR}/ironic-deployment/keepalived/kustomization.yaml \
-	${SCRIPTDIR}/ironic-deployment/tls/default/kustomization.yaml \
-	${SCRIPTDIR}/ironic-deployment/tls/default/tls.yaml \
-	${SCRIPTDIR}/ironic-deployment/tls/keepalived/kustomization.yaml \
-	${SCRIPTDIR}/ironic-deployment/tls/keepalived/tls.yaml"
-
-for DEPLOY_FILE in ${IRONIC_DEPLOY_FILES}; do
-  cp "$DEPLOY_FILE" "$DEPLOY_FILE".bak
-  # shellcheck disable=SC2094
-  envsubst <"$DEPLOY_FILE".bak> "$DEPLOY_FILE"
-done
-
 if [ "${DEPLOY_BASIC_AUTH}" == "true" ]; then
     BMO_SCENARIO="${SCRIPTDIR}/config/basic-auth"
     IRONIC_SCENARIO="${SCRIPTDIR}/ironic-deployment/basic-auth"
@@ -169,11 +144,6 @@ if [ "${DEPLOY_IRONIC}" == "true" ]; then
     popd
 fi
 
-# Move back the original IRONIC_DEPLOY_FILES
- for DEPLOY_FILE in ${IRONIC_DEPLOY_FILES}; do
-    mv "$DEPLOY_FILE".bak "$DEPLOY_FILE"
- done
-
 if [ "${DEPLOY_BASIC_AUTH}" == "true" ]; then
     if [ "${DEPLOY_BMO}" == "true" ]; then
         rm "${BMO_SCENARIO}/ironic-username"
diff --git a/tools/run_local_ironic.sh b/tools/run_local_ironic.sh
index 7642c364..4c97f2c1 100755
--- a/tools/run_local_ironic.sh
+++ b/tools/run_local_ironic.sh
@@ -18,7 +18,7 @@ PROVISIONING_INTERFACE="${PROVISIONING_INTERFACE:-"ironicendpoint"}"
 CLUSTER_DHCP_RANGE="${CLUSTER_DHCP_RANGE:-"172.22.0.10,172.22.0.100"}"
 IRONIC_KERNEL_PARAMS="${IRONIC_KERNEL_PARAMS:-"console=ttyS0"}"
 IRONIC_BOOT_ISO_SOURCE="${IRONIC_BOOT_ISO_SOURCE:-"local"}"
-export NAMEPREFIX=${NAMEPREFIX:-"capm3"}
+
 
 IRONIC_CACERT_FILE="${IRONIC_CACERT_FILE:-}"
 IRONIC_CERT_FILE="${IRONIC_CERT_FILE:-}"
@@ -93,7 +93,7 @@ data:
 kind: Secret
 metadata:
    name: ironic-cacert
-   namespace: ${NAMEPREFIX}-system
+   namespace: capm3-system
 type: Opaque
 EOF
 fi


Test patch:
diff --git a/apis/metal3.io/v1alpha1/hostfirmwaresettings_types_test.go b/apis/metal3.io/v1alpha1/hostfirmwaresettings_types_test.go
deleted file mode 100644
index 6d743f1a..00000000
--- a/apis/metal3.io/v1alpha1/hostfirmwaresettings_types_test.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package v1alpha1
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
-)
-
-func TestCheckSettingIsValid(t *testing.T) {
-
-	lower_bound := 1
-	upper_bound := 20
-	min_length := 1
-	max_length := 16
-	read_only := true
-
-	fwSchema := &FirmwareSchema{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      "myfwschema",
-			Namespace: "myns",
-		},
-		Spec: FirmwareSchemaSpec{
-			Schema: make(map[string]SettingSchema),
-		},
-	}
-
-	fwSchema.Spec.Schema["AssetTag"] = SettingSchema{AttributeType: "String",
-		MinLength: &min_length, MaxLength: &max_length}
-	fwSchema.Spec.Schema["ProcVirtualization"] = SettingSchema{AttributeType: "Enumeration",
-		AllowableValues: []string{"Enabled", "Disabled"}}
-	fwSchema.Spec.Schema["NetworkBootRetryCount"] = SettingSchema{AttributeType: "Integer",
-		LowerBound: &lower_bound, UpperBound: &upper_bound}
-	fwSchema.Spec.Schema["SerialNumber"] = SettingSchema{AttributeType: "String",
-		MinLength: &min_length, MaxLength: &max_length, ReadOnly: &read_only}
-	fwSchema.Spec.Schema["QuietBoot"] = SettingSchema{AttributeType: "Boolean"}
-	fwSchema.Spec.Schema["SriovEnable"] = SettingSchema{} // fields intentionally excluded
-
-	for _, tc := range []struct {
-		Scenario string
-		Name     string
-		Value    intstr.IntOrString
-		Expected bool
-	}{
-		{
-			Scenario: "StringTypePass",
-			Name:     "AssetTag",
-			Value:    intstr.FromString("NewServer"),
-			Expected: true,
-		},
-		{
-			Scenario: "StringTypeFailUpper",
-			Name:     "AssetTag",
-			Value:    intstr.FromString("NewServerPutInServiceIn2021"),
-			Expected: false,
-		},
-		{
-			Scenario: "StringTypeFailLower",
-			Name:     "AssetTag",
-			Value:    intstr.FromString(""),
-			Expected: false,
-		},
-		{
-			Scenario: "EnumerationTypePass",
-			Name:     "ProcVirtualization",
-			Value:    intstr.FromString("Disabled"),
-			Expected: true,
-		},
-		{
-			Scenario: "EnumerationTypeFail",
-			Name:     "ProcVirtualization",
-			Value:    intstr.FromString("Foo"),
-			Expected: false,
-		},
-		{
-			Scenario: "IntegerTypePassAsString",
-			Name:     "NetworkBootRetryCount",
-			Value:    intstr.FromString("10"),
-			Expected: true,
-		},
-		{
-			Scenario: "IntegerTypePassAsInt",
-			Name:     "NetworkBootRetryCount",
-			Value:    intstr.FromInt(10),
-			Expected: true,
-		},
-		{
-			Scenario: "IntegerTypeFailUpper",
-			Name:     "NetworkBootRetryCount",
-			Value:    intstr.FromString("42"),
-			Expected: false,
-		},
-		{
-			Scenario: "IntegerTypeFailLower",
-			Name:     "NetworkBootRetryCount",
-			Value:    intstr.FromInt(0),
-			Expected: false,
-		},
-		{
-			Scenario: "BooleanTypePass",
-			Name:     "QuietBoot",
-			Value:    intstr.FromString("true"),
-			Expected: true,
-		},
-		{
-			Scenario: "BooleanTypeFail",
-			Name:     "QuietBoot",
-			Value:    intstr.FromString("Enabled"),
-			Expected: false,
-		},
-		{
-			Scenario: "ReadOnlyTypeFail",
-			Name:     "SerialNumber",
-			Value:    intstr.FromString("42"),
-			Expected: false,
-		},
-		{
-			Scenario: "MissingEnumerationField",
-			Name:     "SriovEnable",
-			Value:    intstr.FromString("Disabled"),
-			Expected: true,
-		},
-		{
-			Scenario: "UnknownSettingFail",
-			Name:     "IceCream",
-			Value:    intstr.FromString("Vanilla"),
-			Expected: false,
-		},
-	} {
-		t.Run(tc.Scenario, func(t *testing.T) {
-			actual := fwSchema.CheckSettingIsValid(tc.Name, tc.Value, fwSchema.Spec.Schema)
-			assert.Equal(t, tc.Expected, actual)
-		})
-	}
-}
diff --git a/controllers/metal3.io/host_state_machine_test.go b/controllers/metal3.io/host_state_machine_test.go
index 70ac5a90..b76118ea 100644
--- a/controllers/metal3.io/host_state_machine_test.go
+++ b/controllers/metal3.io/host_state_machine_test.go
@@ -1175,11 +1175,11 @@ func (m *mockProvisioner) Detach() (result provisioner.Result, err error) {
 	return res, err
 }
 
-func (m *mockProvisioner) PowerOn(force bool) (result provisioner.Result, err error) {
+func (m *mockProvisioner) PowerOn() (result provisioner.Result, err error) {
 	return m.getNextResultByMethod("PowerOn"), err
 }
 
-func (m *mockProvisioner) PowerOff(rebootMode metal3v1alpha1.RebootMode, force bool) (result provisioner.Result, err error) {
+func (m *mockProvisioner) PowerOff(rebootMode metal3v1alpha1.RebootMode) (result provisioner.Result, err error) {
 	return m.getNextResultByMethod("PowerOff"), err
 }
 
diff --git a/pkg/provisioner/ironic/power_test.go b/pkg/provisioner/ironic/power_test.go
index 0a899d5f..2db33570 100644
--- a/pkg/provisioner/ironic/power_test.go
+++ b/pkg/provisioner/ironic/power_test.go
@@ -20,13 +20,11 @@ func TestPowerOn(t *testing.T) {
 	nodeUUID := "33ce8659-7400-4c68-9535-d10766f07a58"
 	cases := []struct {
 		name   string
-		force  bool
 		ironic *testserver.IronicMock
 
 		expectedDirty        bool
 		expectedError        bool
 		expectedRequestAfter int
-		expectedErrorResult  bool
 	}{
 		{
 			name: "node-already-power-on",
@@ -77,30 +75,6 @@ func TestPowerOn(t *testing.T) {
 			expectedRequestAfter: 10,
 			expectedDirty:        true,
 		},
-		{
-			name: "power-on with LastError",
-			ironic: testserver.NewIronic(t).Ready().Node(nodes.Node{
-				PowerState:       powerOff,
-				TargetPowerState: powerOff,
-				UUID:             nodeUUID,
-				LastError:        "power on failed",
-			}),
-			expectedRequestAfter: 0,
-			expectedDirty:        false,
-			expectedErrorResult:  true,
-		},
-		{
-			name:  "power-on with LastError",
-			force: true,
-			ironic: testserver.NewIronic(t).Ready().Node(nodes.Node{
-				PowerState:       powerOff,
-				TargetPowerState: powerOff,
-				UUID:             nodeUUID,
-				LastError:        "power on failed",
-			}),
-			expectedError:       true,
-			expectedErrorResult: false,
-		},
 	}
 
 	for _, tc := range cases {
@@ -127,7 +101,7 @@ func TestPowerOn(t *testing.T) {
 				t.Fatalf("could not create provisioner: %s", err)
 			}
 
-			result, err := prov.PowerOn(tc.force)
+			result, err := prov.PowerOn()
 
 			assert.Equal(t, tc.expectedDirty, result.Dirty)
 			assert.Equal(t, time.Second*time.Duration(tc.expectedRequestAfter), result.RequeueAfter)
@@ -136,9 +110,6 @@ func TestPowerOn(t *testing.T) {
 			} else {
 				assert.Error(t, err)
 			}
-			if tc.expectedErrorResult {
-				assert.Contains(t, result.ErrorMessage, "PowerOn operation failed")
-			}
 		})
 	}
 }
@@ -149,12 +120,10 @@ func TestPowerOff(t *testing.T) {
 	cases := []struct {
 		name   string
 		ironic *testserver.IronicMock
-		force  bool
 
 		expectedDirty        bool
 		expectedError        bool
 		expectedRequestAfter int
-		expectedErrorResult  bool
 		rebootMode           metal3v1alpha1.RebootMode
 	}{
 		{
@@ -218,44 +187,6 @@ func TestPowerOff(t *testing.T) {
 			expectedRequestAfter: 10,
 			expectedDirty:        true,
 		},
-		{
-			name: "power-off soft with force",
-			ironic: testserver.NewIronic(t).WithDefaultResponses().Node(nodes.Node{
-				PowerState:           powerOn,
-				TargetPowerState:     powerOn,
-				TargetProvisionState: "",
-				UUID:                 nodeUUID,
-			}),
-			rebootMode:    metal3v1alpha1.RebootModeSoft,
-			force:         true,
-			expectedDirty: true,
-		},
-		{
-			name: "power-off hard with LastError",
-			ironic: testserver.NewIronic(t).WithDefaultResponses().Node(nodes.Node{
-				PowerState:           powerOn,
-				TargetPowerState:     powerOn,
-				TargetProvisionState: "",
-				UUID:                 nodeUUID,
-				LastError:            "hard power off failed",
-			}),
-			rebootMode:          metal3v1alpha1.RebootModeHard,
-			expectedDirty:       false,
-			expectedErrorResult: true,
-		},
-		{
-			name: "power-off hard with force",
-			ironic: testserver.NewIronic(t).WithDefaultResponses().Node(nodes.Node{
-				PowerState:           powerOn,
-				TargetPowerState:     powerOn,
-				TargetProvisionState: "",
-				UUID:                 nodeUUID,
-				LastError:            "hard power off failed",
-			}),
-			rebootMode:    metal3v1alpha1.RebootModeHard,
-			force:         true,
-			expectedDirty: true,
-		},
 	}
 
 	for _, tc := range cases {
@@ -283,7 +214,7 @@ func TestPowerOff(t *testing.T) {
 			}
 
 			// We pass the RebootMode type here to define the reboot action
-			result, err := prov.PowerOff(tc.rebootMode, tc.force)
+			result, err := prov.PowerOff(tc.rebootMode)
 
 			assert.Equal(t, tc.expectedDirty, result.Dirty)
 			assert.Equal(t, time.Second*time.Duration(tc.expectedRequestAfter), result.RequeueAfter)
@@ -292,10 +223,6 @@ func TestPowerOff(t *testing.T) {
 			} else {
 				assert.Error(t, err)
 			}
-			if tc.expectedErrorResult {
-				assert.Contains(t, result.ErrorMessage, "hard power off failed")
-			}
-
 		})
 	}
 }
diff --git a/pkg/provisioner/ironic/raid_test.go b/pkg/provisioner/ironic/raid_test.go
index c73651a2..6fbeeed4 100644
--- a/pkg/provisioner/ironic/raid_test.go
+++ b/pkg/provisioner/ironic/raid_test.go
@@ -197,6 +197,16 @@ func TestBuildRAIDCleanSteps(t *testing.T) {
 		expected      []nodes.CleanStep
 		expectedError bool
 	}{
+		{
+			name:          "keep hardware RAID",
+			raidInterface: "irmc",
+			target:        nil,
+		},
+		{
+			name:          "keep hardware RAID",
+			raidInterface: "irmc",
+			target:        &metal3v1alpha1.RAIDConfig{},
+		},
 		{
 			name:          "configure hardware RAID",
 			raidInterface: "irmc",