Repository: metal3-io/baremetal-operator
Pull request #995 (2021-10-14 00:26:21)

Change hfs controller to be level-triggered when handling bmh updates
Change to use a poll cycle in the hfs reconciler to get data from Ironic instead of relying on state difference. In addition, the following changes were made to address follow-on comments in 
https://github.com/metal3-io/baremetal-operator/pull/938/.

- changed name of condition `UpdateRequested` to `FirmwareSettingsChangeDetected`
- add each hostFirmwareSettings as owner of its FirmwareSchema so that garbage collection will only be done when all removed
- Change the SetOwnerReference/SetControllerReference calls to before Create so the Update can be removed
- When building BIOS settings for cleaning make sure the hfs settings don't overwrite the vendor-agnostic settings
- When generating the hash for the firmwareSchema include the schema values in addition to the names

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"]} -->
bfournie: /test-integration
elfosardo: /lgtm
bfournie: /cc @zaneb
/cc @andfasano 
bfournie: /test e2e-metal-ipi
/test e2e-metal-ipi-ovn-ipv6
metal3-io-bot: @bfournie: The specified target(s) for `/test` were not found.
The following commands are available to trigger required jobs:
* `/test generate`
* `/test gofmt`
* `/test golint`
* `/test gomod`
* `/test gosec`
* `/test manifestlint`
* `/test markdownlint`
* `/test shellcheck`
* `/test unit`

Use `/test all` to run the following jobs that were automatically triggered:
* `generate`
* `gofmt`
* `golint`
* `gomod`
* `gosec`
* `manifestlint`
* `unit`



<details>

In response to [this](https://github.com/metal3-io/baremetal-operator/pull/995#issuecomment-970710580):

>/test e2e-metal-ipi
>/test e2e-metal-ipi-ovn-ipv6


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
andfasano: After reviewing all the changes, on a second thought I'm getting convinced that probably the relationships between BMH and HFS could be relaxed a little bit, possibly leading to a simplified approach that will honor all the points previously discussed. Following the main general points:

1. BMH needs only to wait, in the Preparing state, for the related HFS resource to be ready (and here using the conditions looks fine). If the HFS is not ready, it will re-enqueue a reconciliation request before proceeding. If it is, the cleaning steps could be taken as usual.
2. HFS controller will stop listening BMH events, and it should take care only of filling (and validating) the HFS resource by fetching the hw settings at every reconcile loop, ensuring that its Conditions properly reflect the current situation. The reconciliation will be by default reenqueued on a reasonable time basis (ie 5 minutes, to be decided), to ensure that any external changes to the hw settings will be captured (for example, if any setting will be changed after the cleaning step in the Preparing state).
3. Given that, the responsibility to create an (empty) HFS resource if not present will come back under the BMH controller (something to be performed at every reconcile loop, if not under deletion)

I understand that this means a significant change to the current design, but the overall idea is to look for a simplified approach that maybe could be reused also in future for other similar situations.

Wdyt? 
bfournie: > After reviewing all the changes, on a second thought I'm getting convinced that probably the relationships between BMH and HFS could be relaxed a little bit, possibly leading to a simplified approach that will honor all the points previously discussed. Following the main general points:
> 
> 1. BMH needs only to wait, in the Preparing state, for the related HFS resource to be ready (and here using the conditions looks fine). If the HFS is not ready, it will re-enqueue a reconciliation request before proceeding. If it is, the cleaning steps could be taken as usual.
> 2. HFS controller will stop listening BMH events, and it should take care only of filling (and validating) the HFS resource by fetching the hw settings at every reconcile loop, ensuring that its Conditions properly reflect the current situation. The reconciliation will be by default reenqueued on a reasonable time basis (ie 5 minutes, to be decided), to ensure that any external changes to the hw settings will be captured (for example, if any setting will be changed after the cleaning step in the Preparing state).
> 3. Given that, the responsibility to create an (empty) HFS resource if not present will come back under the BMH controller (something to be performed at every reconcile loop, if not under deletion)
> 
> I understand that this means a significant change to the current design, but the overall idea is to look for a simplified approach that maybe could be reused also in future for other similar situations.
> 
> Wdyt?

I think its a good idea and will simplify the hfs controller. I've updated the PR to:
1. Remove the watch of bmh resource in hfs controller 
2. Remove the hfs EventUpdate handler filtering
3. Create the hfs resource in bmh controller when registering
4. Add a requeue to the hfs reconciler to poll the data from Ironic and pick up any changes as a result of cleaning (or other events)
5. In bmh controller, before entering the preparing state check that the hfs is ready
bfournie: /test-v1b1-centos-integration
bfournie: /test-v1b1-integration 
andfasano: /test-v1b1-integration
metal3-io-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/metal3-io/baremetal-operator/pull/995#pullrequestreview-812818365" title="Approved">andfasano</a>*

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

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

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

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

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":[]} -->
bfournie: /test-v1b1-centos-integration
/test-v1b1-integration
bfournie: /test-v1b1-centos-integration
bfournie: /test-v1b1-centos-integration
/test-v1b1-integration
bfournie: /test-v1b1-centos-integration
/test-v1b1-integration

Patch:
diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index 243f81a5..00000000
--- a/.dockerignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
-# Ignore all files which are not go type
-!**/*.go
-!**/*.mod
-!**/*.sum
diff --git a/.golangci.yml b/.golangci.yml
index 9b2c6d9a..43ee4792 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -4,7 +4,7 @@ run:
 linters:
   disable-all: true
   enable: [
-    "revive",
+    "golint",
     "govet",
     "goimports",
     "gofmt",
diff --git a/Dockerfile b/Dockerfile
index 947da744..83ef8f2b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -11,8 +11,8 @@ COPY apis/go.mod apis/go.mod
 COPY apis/go.sum apis/go.sum
 COPY hack/tools/go.mod hack/tools/go.mod
 COPY hack/tools/go.sum hack/tools/go.sum
-COPY pkg/hardwareutils/go.mod pkg/hardwareutils/go.mod
-COPY pkg/hardwareutils/go.sum pkg/hardwareutils/go.sum
+COPY pkg/ironic/go.mod pkg/ironic/go.mod
+COPY pkg/ironic/go.sum pkg/ironic/go.sum
 RUN go mod download
 
 COPY . .
diff --git a/Makefile b/Makefile
index 732832ad..8391bab7 100644
--- a/Makefile
+++ b/Makefile
@@ -64,7 +64,7 @@ test: generate lint manifests unit ## Run common developer tests
 unit: ## Run unit tests
 	go test ./... $(GO_TEST_FLAGS) -coverprofile $(COVER_PROFILE)
 	cd apis/ && go test ./... $(GO_TEST_FLAGS) -coverprofile $(COVER_PROFILE)
-	cd pkg/hardwareutils && go test ./... $(GO_TEST_FLAGS) -coverprofile $(COVER_PROFILE)
+	cd pkg/ironic && go test ./... $(GO_TEST_FLAGS) -coverprofile $(COVER_PROFILE)
 
 .PHONY: unit-cover
 unit-cover: ## Run unit tests with code coverage
@@ -72,8 +72,8 @@ unit-cover: ## Run unit tests with code coverage
 	go tool cover -func=$(COVER_PROFILE)
 	cd apis/ && go test -coverprofile=$(COVER_PROFILE) $(GO_TEST_FLAGS) ./...
 	cd apis/ && go tool cover -func=$(COVER_PROFILE)
-	cd pkg/hardwareutils/ && go test -coverprofile=$(COVER_PROFILE) $(GO_TEST_FLAGS) ./...
-	cd pkg/hardwareutils/ && go tool cover -func=$(COVER_PROFILE)
+	cd pkg/ironic/ && go test -coverprofile=$(COVER_PROFILE) $(GO_TEST_FLAGS) ./...
+	cd pkg/ironic/ && go tool cover -func=$(COVER_PROFILE)
 
 .PHONY: unit-verbose
 unit-verbose: ## Run unit tests with verbose output
@@ -235,7 +235,5 @@ mod: ## Clean up go module settings
 	go mod verify
 	cd apis; go mod tidy
 	cd apis; go mod verify
-	cd pkg/hardwareutils; go mod tidy
-	cd pkg/hardwareutils; go mod verify
 	cd hack/tools; go mod tidy
 	cd hack/tools; go mod verify
diff --git a/OWNERS b/OWNERS
index 65885238..d9715a52 100644
--- a/OWNERS
+++ b/OWNERS
@@ -6,11 +6,10 @@ approvers:
  - fmuyassarov
  - hardys
  - maelk
+ - stbenjam
  - zaneb
 
 reviewers:
- - ardaguclu
- - bfournie
  - honza
  - dukov
  - furkatgofurov7
diff --git a/PROJECT b/PROJECT
index a76ea4d6..f3e77ea5 100644
--- a/PROJECT
+++ b/PROJECT
@@ -1,47 +1,16 @@
-domain: metal3.io
-layout:
-- go.kubebuilder.io/v3
 multigroup: true
-projectName: baremetal-operator
 repo: github.com/metal3-io/baremetal-operator
 resources:
-- api:
-    crdVersion: v1
-    namespaced: true
-  controller: true
-  domain: metal3.io
-  group: metal3.io
+- group: metal3.io
   kind: BareMetalHost
-  path: github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1
   version: v1alpha1
-  webhooks:
-    validation: true
-    webhookVersion: v1
-- api:
-    crdVersion: v1
-    namespaced: true
-  controller: true
-  domain: metal3.io
-  group: metal3.io
+- group: metal3.io
   kind: HostFirmwareSettings
-  path: github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1
   version: v1alpha1
-- api:
-    crdVersion: v1
-    namespaced: true
-  controller: true
-  domain: metal3.io
-  group: metal3.io
+- group: metal3.io
   kind: FirmwareSchema
-  path: github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1
   version: v1alpha1
-- api:
-    crdVersion: v1
-    namespaced: true
-  controller: true
-  domain: metal3.io
-  group: metal3.io
+- group: metal3.io
   kind: PreprovisioningImage
-  path: github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1
   version: v1alpha1
-version: "3"
+version: "2"
diff --git a/apis/go.mod b/apis/go.mod
index 0eebd751..b217d239 100644
--- a/apis/go.mod
+++ b/apis/go.mod
@@ -7,7 +7,4 @@ require (
 	k8s.io/api v0.21.4
 	k8s.io/apimachinery v0.21.4
 	sigs.k8s.io/controller-runtime v0.9.7
-	github.com/metal3-io/baremetal-operator/pkg/hardwareutils v0.0.0
 )
-
-replace github.com/metal3-io/baremetal-operator/pkg/hardwareutils => ./../pkg/hardwareutils
diff --git a/apis/metal3.io/v1alpha1/baremetalhost_types.go b/apis/metal3.io/v1alpha1/baremetalhost_types.go
index 433a26f8..371b5ebb 100644
--- a/apis/metal3.io/v1alpha1/baremetalhost_types.go
+++ b/apis/metal3.io/v1alpha1/baremetalhost_types.go
@@ -1,5 +1,6 @@
 /*
 
+
 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
diff --git a/apis/metal3.io/v1alpha1/baremetalhost_validation.go b/apis/metal3.io/v1alpha1/baremetalhost_validation.go
index d8eda142..f59ea0d8 100644
--- a/apis/metal3.io/v1alpha1/baremetalhost_validation.go
+++ b/apis/metal3.io/v1alpha1/baremetalhost_validation.go
@@ -4,8 +4,6 @@ import (
 	"fmt"
 
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
-
-	_ "github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 )
 
 // log is for logging in this package.
diff --git a/apis/metal3.io/v1alpha1/firmwareschema_types.go b/apis/metal3.io/v1alpha1/firmwareschema_types.go
index df76ff5d..67620b88 100644
--- a/apis/metal3.io/v1alpha1/firmwareschema_types.go
+++ b/apis/metal3.io/v1alpha1/firmwareschema_types.go
@@ -18,6 +18,7 @@ package v1alpha1
 
 import (
 	"fmt"
+	"strings"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
@@ -71,6 +72,10 @@ 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/groupversion_info.go b/apis/metal3.io/v1alpha1/groupversion_info.go
index eb8116d7..700bd313 100644
--- a/apis/metal3.io/v1alpha1/groupversion_info.go
+++ b/apis/metal3.io/v1alpha1/groupversion_info.go
@@ -1,5 +1,6 @@
 /*
 
+
 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
@@ -14,8 +15,8 @@ limitations under the License.
 */
 
 // Package v1alpha1 contains API Schema definitions for the metal3.io v1alpha1 API group
-//+kubebuilder:object:generate=true
-//+groupName=metal3.io
+// +kubebuilder:object:generate=true
+// +groupName=metal3.io
 package v1alpha1
 
 import (
diff --git a/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go b/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go
index 8bca68d1..c170e967 100644
--- a/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go
+++ b/apis/metal3.io/v1alpha1/hostfirmwaresettings_types.go
@@ -37,19 +37,16 @@ type SettingsConditionType string
 
 const (
 	// Indicates that the settings in the Spec are different than Status
-	UpdateRequested SettingsConditionType = "UpdateRequested"
+	FirmwareSettingsChangeDetected SettingsConditionType = "ChangeDetected"
 
 	// Indicates if the settings are valid and can be configured on the host
-	SettingsValid SettingsConditionType = "Valid"
+	FirmwareSettingsValid 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"`
 }
@@ -61,9 +58,13 @@ type HostFirmwareSettingsStatus struct {
 	// 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 are the 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/preprovisioningimage_types.go b/apis/metal3.io/v1alpha1/preprovisioningimage_types.go
index 8853a5e3..84697a94 100644
--- a/apis/metal3.io/v1alpha1/preprovisioningimage_types.go
+++ b/apis/metal3.io/v1alpha1/preprovisioningimage_types.go
@@ -22,8 +22,6 @@ import (
 // +kubebuilder:validation:Enum=iso;initrd
 type ImageFormat string
 
-const PreprovisioningImageFinalizer = "preprovisioningimage.metal3.io"
-
 const (
 	ImageFormatISO    ImageFormat = "iso"
 	ImageFormatInitRD ImageFormat = "initrd"
@@ -39,10 +37,6 @@ type PreprovisioningImageSpec struct {
 	// architecture is the processor architecture for which to build the image.
 	// +optional
 	Architecture string `json:"architecture,omitempty"`
-
-	// acceptFormats is a list of acceptable image formats.
-	// +optional
-	AcceptFormats []ImageFormat `json:"acceptFormats,omitempty"`
 }
 
 type SecretStatus struct {
diff --git a/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go b/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go
index 0891f4ea..03d546bb 100644
--- a/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/metal3.io/v1alpha1/zz_generated.deepcopy.go
@@ -584,6 +584,10 @@ 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))
@@ -684,7 +688,7 @@ func (in *PreprovisioningImage) DeepCopyInto(out *PreprovisioningImage) {
 	*out = *in
 	out.TypeMeta = in.TypeMeta
 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	in.Spec.DeepCopyInto(&out.Spec)
+	out.Spec = in.Spec
 	in.Status.DeepCopyInto(&out.Status)
 }
 
@@ -741,11 +745,6 @@ func (in *PreprovisioningImageList) DeepCopyObject() runtime.Object {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *PreprovisioningImageSpec) DeepCopyInto(out *PreprovisioningImageSpec) {
 	*out = *in
-	if in.AcceptFormats != nil {
-		in, out := &in.AcceptFormats, &out.AcceptFormats
-		*out = make([]ImageFormat, len(*in))
-		copy(*out, *in)
-	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PreprovisioningImageSpec.
diff --git a/cmd/get-hardware-details/main.go b/cmd/get-hardware-details/main.go
index 5f824a63..62a0576e 100644
--- a/cmd/get-hardware-details/main.go
+++ b/cmd/get-hardware-details/main.go
@@ -10,8 +10,8 @@ import (
 
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/hardwaredetails"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/hardwaredetails"
 )
 
 type options struct {
diff --git a/config/crd/bases/metal3.io_hostfirmwaresettings.yaml b/config/crd/bases/metal3.io_hostfirmwaresettings.yaml
index 62e08404..0c8ab5c3 100644
--- a/config/crd/bases/metal3.io_hostfirmwaresettings.yaml
+++ b/config/crd/bases/metal3.io_hostfirmwaresettings.yaml
@@ -46,9 +46,7 @@ spec:
                   - 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.
+                  name/value pairs.
                 type: object
             required:
             - settings
@@ -131,6 +129,10 @@ 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
@@ -150,7 +152,7 @@ spec:
               settings:
                 additionalProperties:
                   type: string
-                description: Settings are the actual firmware settings stored as name/value
+                description: Settings are the firmware settings stored as name/value
                   pairs
                 type: object
             required:
diff --git a/config/crd/bases/metal3.io_preprovisioningimages.yaml b/config/crd/bases/metal3.io_preprovisioningimages.yaml
index 5447d179..180f1f60 100644
--- a/config/crd/bases/metal3.io_preprovisioningimages.yaml
+++ b/config/crd/bases/metal3.io_preprovisioningimages.yaml
@@ -48,15 +48,6 @@ spec:
           spec:
             description: PreprovisioningImageSpec defines the desired state of PreprovisioningImage
             properties:
-              acceptFormats:
-                description: acceptFormats is a list of acceptable image formats.
-                items:
-                  description: ImageFormat enumerates the allowed image formats
-                  enum:
-                  - iso
-                  - initrd
-                  type: string
-                type: array
               architecture:
                 description: architecture is the processor architecture for which
                   to build the image.
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index 9a31c53b..0160d1a9 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -6,7 +6,7 @@ resources:
 - bases/metal3.io_hostfirmwaresettings.yaml
 - bases/metal3.io_firmwareschemas.yaml
 - bases/metal3.io_preprovisioningimages.yaml
-#+kubebuilder:scaffold:crdkustomizeresource
+# +kubebuilder:scaffold:crdkustomizeresource
 
 patchesStrategicMerge:
 # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
@@ -15,7 +15,7 @@ patchesStrategicMerge:
 #- patches/webhook_in_hostfirmwaresettings.yaml
 #- patches/webhook_in_firmwareschemas.yaml
 #- patches/webhook_in_preprovisioningimages.yaml
-#+kubebuilder:scaffold:crdkustomizewebhookpatch
+# +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
@@ -23,7 +23,7 @@ patchesStrategicMerge:
 #- patches/cainjection_in_hostfirmwaresettings.yaml
 #- patches/cainjection_in_firmwareschemas.yaml
 #- patches/cainjection_in_preprovisioningimages.yaml
-#+kubebuilder:scaffold:crdkustomizecainjectionpatch
+# +kubebuilder:scaffold:crdkustomizecainjectionpatch
 
 # the following config is for teaching kustomize how to do kustomization for CRDs.
 configurations:
diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml
index ec5c150a..6f83d9a9 100644
--- a/config/crd/kustomizeconfig.yaml
+++ b/config/crd/kustomizeconfig.yaml
@@ -4,15 +4,13 @@ nameReference:
   version: v1
   fieldSpecs:
   - kind: CustomResourceDefinition
-    version: v1
     group: apiextensions.k8s.io
-    path: spec/conversion/webhook/clientConfig/service/name
+    path: spec/conversion/webhookClientConfig/service/name
 
 namespace:
 - kind: CustomResourceDefinition
-  version: v1
   group: apiextensions.k8s.io
-  path: spec/conversion/webhook/clientConfig/service/namespace
+  path: spec/conversion/webhookClientConfig/service/namespace
   create: false
 
 varReference:
diff --git a/config/crd/patches/cainjection_in_baremetalhosts.yaml b/config/crd/patches/cainjection_in_baremetalhosts.yaml
index 74f1a27f..6c3666e7 100644
--- a/config/crd/patches/cainjection_in_baremetalhosts.yaml
+++ b/config/crd/patches/cainjection_in_baremetalhosts.yaml
@@ -1,4 +1,5 @@
 # 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/v1
 kind: CustomResourceDefinition
 metadata:
diff --git a/config/crd/patches/webhook_in_baremetalhosts.yaml b/config/crd/patches/webhook_in_baremetalhosts.yaml
index fdf4a74e..d99d8f13 100644
--- a/config/crd/patches/webhook_in_baremetalhosts.yaml
+++ b/config/crd/patches/webhook_in_baremetalhosts.yaml
@@ -1,4 +1,5 @@
-# The following patch enables a conversion webhook for the CRD
+# The following patch enables conversion webhook for CRD
+# CRD conversion requires k8s 1.13 or later.
 apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
@@ -6,12 +7,11 @@ metadata:
 spec:
   conversion:
     strategy: Webhook
-    webhook:
-      clientConfig:
-        service:
-          namespace: system
-          name: webhook-service
-          path: /convert
-        caBundle: Cg==
-      conversionReviewVersions:
-      - v1
+    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_firmwareschemas.yaml b/config/crd/patches/webhook_in_firmwareschemas.yaml
index e221c848..2744739c 100644
--- a/config/crd/patches/webhook_in_firmwareschemas.yaml
+++ b/config/crd/patches/webhook_in_firmwareschemas.yaml
@@ -7,12 +7,11 @@ metadata:
 spec:
   conversion:
     strategy: Webhook
-    webhook:
-      clientConfig:
-        service:      
-          namespace: system
-          name: webhook-service
-          path: /convert
-        caBundle: Cg==
-      conversionReviewVersions:
-      - v1
+    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
index 24da15b8..73870848 100644
--- a/config/crd/patches/webhook_in_hostfirmwaresettings.yaml
+++ b/config/crd/patches/webhook_in_hostfirmwaresettings.yaml
@@ -7,13 +7,11 @@ metadata:
 spec:
   conversion:
     strategy: Webhook
-    webhook:
-      clientConfig:
-        service:
-          namespace: system
-          name: webhook-service
-          path: /convert
-        caBundle: Cg==
-      conversionReviewVersions:
-      - v1
-      
+    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_preprovisioningimages.yaml b/config/crd/patches/webhook_in_preprovisioningimages.yaml
index 33a66ce7..2773ae6f 100644
--- a/config/crd/patches/webhook_in_preprovisioningimages.yaml
+++ b/config/crd/patches/webhook_in_preprovisioningimages.yaml
@@ -7,12 +7,11 @@ metadata:
 spec:
   conversion:
     strategy: Webhook
-    webhook:
-      clientConfig:
-        service:
-          namespace: system
-          name: webhook-service
-          path: /convert
-        caBundle: Cg==
-      conversionReviewVersions:
-      - v1
+    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/default/kustomization.yaml b/config/default/kustomization.yaml
index 2e88f2fa..c151099e 100644
--- a/config/default/kustomization.yaml
+++ b/config/default/kustomization.yaml
@@ -16,25 +16,21 @@ bases:
 - ../crd
 - ../rbac
 - ../manager
-# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
+# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in 
 # crd/kustomization.yaml
 - ../webhook
 # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
 - ../certmanager
-# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
+# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. 
 #- ../prometheus
 
 patchesStrategicMerge:
-# Protect the /metrics endpoint by putting it behind auth.
-# If you want your controller-manager to expose the /metrics
-# endpoint w/o any authn/z, please comment the following line.
+  # Protect the /metrics endpoint by putting it behind auth.
+  # If you want your controller-manager to expose the /metrics
+  # endpoint w/o any authn/z, please comment the following line.
 - manager_auth_proxy_patch.yaml
 
-# Mount the controller config file for loading manager configurations
-# through a ComponentConfig type
-#- manager_config_patch.yaml
-
-# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
+# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in 
 # crd/kustomization.yaml
 - manager_webhook_patch.yaml
 
diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml
index 9ace727e..4161fd4c 100644
--- a/config/default/manager_auth_proxy_patch.yaml
+++ b/config/default/manager_auth_proxy_patch.yaml
@@ -1,4 +1,4 @@
-# This patch inject a sidecar container which is a HTTP proxy for the
+# This patch inject a sidecar container which is a HTTP proxy for the 
 # controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
 apiVersion: apps/v1
 kind: Deployment
diff --git a/config/default/manager_config_patch.yaml b/config/default/manager_config_patch.yaml
deleted file mode 100644
index 6c400155..00000000
--- a/config/default/manager_config_patch.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: controller-manager
-  namespace: system
-spec:
-  template:
-    spec:
-      containers:
-      - name: manager
-        args:
-        - "--config=controller_manager_config.yaml"
-        volumeMounts:
-        - name: manager-config
-          mountPath: /controller_manager_config.yaml
-          subPath: controller_manager_config.yaml
-      volumes:
-      - name: manager-config
-        configMap:
-          name: manager-config
diff --git a/config/manager/controller_manager_config.yaml b/config/manager/controller_manager_config.yaml
deleted file mode 100644
index 43be9366..00000000
--- a/config/manager/controller_manager_config.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
-kind: ControllerManagerConfig
-health:
-  healthProbeBindAddress: :9440
-metrics:
-  bindAddress: 127.0.0.1:8085
-webhook:
-  port: 9443
-leaderElection:
-  leaderElect: true
-  resourceName: a9498140.metal3.io
diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml
index 2bcd3eea..5c5f0b84 100644
--- a/config/manager/kustomization.yaml
+++ b/config/manager/kustomization.yaml
@@ -1,10 +1,2 @@
 resources:
 - manager.yaml
-
-generatorOptions:
-  disableNameSuffixHash: true
-
-configMapGenerator:
-- name: manager-config
-  files:
-  - controller_manager_config.yaml
diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml
index ea2c7fdf..cff809b2 100644
--- a/config/manager/manager.yaml
+++ b/config/manager/manager.yaml
@@ -37,25 +37,10 @@ spec:
           - configMapRef:
               name: ironic
         name: manager
-        securityContext:
-          allowPrivilegeEscalation: false
         livenessProbe:
           httpGet:
             path: /healthz
             port: 9440
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          timeoutSeconds: 2
-          successThreshold: 1
-          failureThreshold: 10
-        readinessProbe:
-          httpGet:
-            path: /readyz
-            port: 9440
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          timeoutSeconds: 2
-          successThreshold: 1
-          failureThreshold: 10
-      serviceAccountName: controller-manager
+          initialDelaySeconds: 3
+          periodSeconds: 3
       terminationGracePeriodSeconds: 10
diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml
index d19136ae..9b8047b7 100644
--- a/config/prometheus/monitor.yaml
+++ b/config/prometheus/monitor.yaml
@@ -11,10 +11,6 @@ spec:
   endpoints:
     - path: /metrics
       port: https
-      scheme: https
-      bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
-      tlsConfig:
-        insecureSkipVerify: true
   selector:
     matchLabels:
       control-plane: controller-manager
diff --git a/config/rbac/auth_proxy_client_clusterrole.yaml b/config/rbac/auth_proxy_client_clusterrole.yaml
index 51a75db4..bd4af137 100644
--- a/config/rbac/auth_proxy_client_clusterrole.yaml
+++ b/config/rbac/auth_proxy_client_clusterrole.yaml
@@ -3,7 +3,5 @@ kind: ClusterRole
 metadata:
   name: metrics-reader
 rules:
-- nonResourceURLs:
-  - "/metrics"
-  verbs:
-  - get
+- nonResourceURLs: ["/metrics"]
+  verbs: ["get"]
diff --git a/config/rbac/auth_proxy_role.yaml b/config/rbac/auth_proxy_role.yaml
index 80e1857c..618f5e41 100644
--- a/config/rbac/auth_proxy_role.yaml
+++ b/config/rbac/auth_proxy_role.yaml
@@ -3,15 +3,11 @@ kind: ClusterRole
 metadata:
   name: proxy-role
 rules:
-- apiGroups:
-  - authentication.k8s.io
+- apiGroups: ["authentication.k8s.io"]
   resources:
   - tokenreviews
-  verbs:
-  - create
-- apiGroups:
-  - authorization.k8s.io
+  verbs: ["create"]
+- apiGroups: ["authorization.k8s.io"]
   resources:
   - subjectaccessreviews
-  verbs:
-  - create
+  verbs: ["create"]
diff --git a/config/rbac/auth_proxy_role_binding.yaml b/config/rbac/auth_proxy_role_binding.yaml
index ec7acc0a..48ed1e4b 100644
--- a/config/rbac/auth_proxy_role_binding.yaml
+++ b/config/rbac/auth_proxy_role_binding.yaml
@@ -8,5 +8,5 @@ roleRef:
   name: proxy-role
 subjects:
 - kind: ServiceAccount
-  name: controller-manager
+  name: default
   namespace: system
diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml
index 731832a6..66c28338 100644
--- a/config/rbac/kustomization.yaml
+++ b/config/rbac/kustomization.yaml
@@ -1,10 +1,4 @@
 resources:
-# All RBAC will be applied under this service account in
-# the deployment namespace. You may comment out this resource
-# if your manager will use a service account that exists at
-# runtime. Be sure to update RoleBinding and ClusterRoleBinding
-# subjects if changing service account names.
-- service_account.yaml
 - role.yaml
 - role_binding.yaml
 - leader_election_role.yaml
diff --git a/config/rbac/leader_election_role_binding.yaml b/config/rbac/leader_election_role_binding.yaml
index 1d1321ed..eed16906 100644
--- a/config/rbac/leader_election_role_binding.yaml
+++ b/config/rbac/leader_election_role_binding.yaml
@@ -8,5 +8,5 @@ roleRef:
   name: leader-election-role
 subjects:
 - kind: ServiceAccount
-  name: controller-manager
+  name: default
   namespace: system
diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml
index 2070ede4..8f265870 100644
--- a/config/rbac/role_binding.yaml
+++ b/config/rbac/role_binding.yaml
@@ -8,5 +8,5 @@ roleRef:
   name: manager-role
 subjects:
 - kind: ServiceAccount
-  name: controller-manager
+  name: default
   namespace: system
diff --git a/config/rbac/service_account.yaml b/config/rbac/service_account.yaml
deleted file mode 100644
index 7cd6025b..00000000
--- a/config/rbac/service_account.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: controller-manager
-  namespace: system
diff --git a/config/render/capm3.yaml b/config/render/capm3.yaml
index 1b7f2199..d3342668 100644
--- a/config/render/capm3.yaml
+++ b/config/render/capm3.yaml
@@ -1243,9 +1243,7 @@ spec:
                   - 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.
+                  name/value pairs.
                 type: object
             required:
             - settings
@@ -1328,6 +1326,10 @@ 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
@@ -1347,7 +1349,7 @@ spec:
               settings:
                 additionalProperties:
                   type: string
-                description: Settings are the actual firmware settings stored as name/value
+                description: Settings are the firmware settings stored as name/value
                   pairs
                 type: object
             required:
@@ -1413,15 +1415,6 @@ spec:
           spec:
             description: PreprovisioningImageSpec defines the desired state of PreprovisioningImage
             properties:
-              acceptFormats:
-                description: acceptFormats is a list of acceptable image formats.
-                items:
-                  description: ImageFormat enumerates the allowed image formats
-                  enum:
-                  - iso
-                  - initrd
-                  type: string
-                type: array
               architecture:
                 description: architecture is the processor architecture for which
                   to build the image.
@@ -1545,12 +1538,6 @@ status:
   conditions: []
   storedVersions: []
 ---
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: baremetal-operator-controller-manager
-  namespace: baremetal-operator-system
----
 apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
@@ -1742,7 +1729,7 @@ roleRef:
   name: baremetal-operator-leader-election-role
 subjects:
 - kind: ServiceAccount
-  name: baremetal-operator-controller-manager
+  name: default
   namespace: baremetal-operator-system
 ---
 apiVersion: rbac.authorization.k8s.io/v1
@@ -1755,7 +1742,7 @@ roleRef:
   name: baremetal-operator-manager-role
 subjects:
 - kind: ServiceAccount
-  name: baremetal-operator-controller-manager
+  name: default
   namespace: baremetal-operator-system
 ---
 apiVersion: rbac.authorization.k8s.io/v1
@@ -1768,7 +1755,7 @@ roleRef:
   name: baremetal-operator-proxy-role
 subjects:
 - kind: ServiceAccount
-  name: baremetal-operator-controller-manager
+  name: default
   namespace: baremetal-operator-system
 ---
 apiVersion: v1
@@ -1788,25 +1775,6 @@ metadata:
   namespace: baremetal-operator-system
 ---
 apiVersion: v1
-data:
-  controller_manager_config.yaml: |
-    apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
-    kind: ControllerManagerConfig
-    health:
-      healthProbeBindAddress: :9440
-    metrics:
-      bindAddress: 127.0.0.1:8085
-    webhook:
-      port: 9443
-    leaderElection:
-      leaderElect: true
-      resourceName: a9498140.metal3.io
-kind: ConfigMap
-metadata:
-  name: baremetal-operator-manager-config
-  namespace: baremetal-operator-system
----
-apiVersion: v1
 kind: Service
 metadata:
   labels:
@@ -1884,35 +1852,20 @@ spec:
         image: quay.io/metal3-io/baremetal-operator
         imagePullPolicy: Always
         livenessProbe:
-          failureThreshold: 10
           httpGet:
             path: /healthz
             port: 9440
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
+          initialDelaySeconds: 3
+          periodSeconds: 3
         name: manager
         ports:
         - containerPort: 9443
           name: webhook-server
           protocol: TCP
-        readinessProbe:
-          failureThreshold: 10
-          httpGet:
-            path: /readyz
-            port: 9440
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 2
-        securityContext:
-          allowPrivilegeEscalation: false
         volumeMounts:
         - mountPath: /tmp/k8s-webhook-server/serving-certs
           name: cert
           readOnly: true
-      serviceAccountName: baremetal-operator-controller-manager
       terminationGracePeriodSeconds: 10
       volumes:
       - name: cert
diff --git a/controllers/metal3.io/baremetalhost_controller.go b/controllers/metal3.io/baremetalhost_controller.go
index a33e0734..712c24b2 100644
--- a/controllers/metal3.io/baremetalhost_controller.go
+++ b/controllers/metal3.io/baremetalhost_controller.go
@@ -26,6 +26,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	"github.com/prometheus/client_golang/prometheus"
@@ -44,7 +46,6 @@ import (
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
 	"github.com/metal3-io/baremetal-operator/pkg/hardware"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
 	"github.com/metal3-io/baremetal-operator/pkg/secretutils"
 	"github.com/metal3-io/baremetal-operator/pkg/utils"
@@ -55,6 +56,7 @@ 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"
@@ -482,7 +484,7 @@ func hasInspectAnnotation(host *metal3v1alpha1.BareMetalHost) bool {
 // clearError removes any existing error message.
 func clearError(host *metal3v1alpha1.BareMetalHost) (dirty bool) {
 	dirty = host.SetOperationalStatus(metal3v1alpha1.OperationalStatusOK)
-	var emptyErrType metal3v1alpha1.ErrorType
+	var emptyErrType metal3v1alpha1.ErrorType = ""
 	if host.Status.ErrorType != emptyErrType {
 		host.Status.ErrorType = emptyErrType
 		dirty = true
@@ -525,13 +527,6 @@ func (r *BareMetalHostReconciler) actionDeleting(prov provisioner.Provisioner, i
 	}
 
 	// Remove finalizer to allow deletion
-	secretManager := secretutils.NewSecretManager(info.log, r.Client, r.APIReader)
-
-	err = secretManager.ReleaseSecret(info.bmcCredsSecret)
-	if err != nil {
-		return actionError{err}
-	}
-
 	info.host.Finalizers = utils.FilterStringFromList(
 		info.host.Finalizers, metal3v1alpha1.BareMetalHostFinalizer)
 	info.log.Info("cleanup is complete, removed finalizer",
@@ -624,26 +619,13 @@ func (r *BareMetalHostReconciler) preprovImageAvailable(info *reconcileInfo, ima
 		return false, nil
 	}
 
-	validFormat := false
-	for _, f := range image.Spec.AcceptFormats {
-		if image.Status.Format == f {
-			validFormat = true
-			break
-		}
-	}
-	if !validFormat {
-		info.log.Info("pre-provisioning image format not accepted",
-			"format", image.Status.Format)
-		return false, nil
-	}
-
 	if image.Spec.NetworkDataName != "" {
 		secretKey := client.ObjectKey{
 			Name:      image.Spec.NetworkDataName,
 			Namespace: image.ObjectMeta.Namespace,
 		}
 		secretManager := r.secretManager(info.log)
-		networkData, err := secretManager.AcquireSecret(secretKey, info.host, false, false)
+		networkData, err := secretManager.AcquireSecret(secretKey, info.host, false)
 		if err != nil {
 			return false, err
 		}
@@ -659,13 +641,17 @@ func (r *BareMetalHostReconciler) preprovImageAvailable(info *reconcileInfo, ima
 		return false, nil
 	}
 
-	if errCond := meta.FindStatusCondition(image.Status.Conditions, string(metal3v1alpha1.ConditionImageError)); errCond.Status == metav1.ConditionTrue {
-		info.log.Info("error building PreprovisioningImage",
-			"message", errCond.Message)
-		return false, imageBuildError{errCond.Message}
-	}
-	if meta.IsStatusConditionTrue(image.Status.Conditions, string(metal3v1alpha1.ConditionImageReady)) {
-		return true, nil
+	for _, cond := range image.Status.Conditions {
+		if cond.Status == metav1.ConditionTrue {
+			switch metal3v1alpha1.ImageStatusConditionType(cond.Type) {
+			case metal3v1alpha1.ConditionImageReady:
+				return true, nil
+			case metal3v1alpha1.ConditionImageError:
+				info.log.Info("error building PreprovisioningImage",
+					"message", cond.Message)
+				return false, imageBuildError{cond.Message}
+			}
+		}
 	}
 
 	info.log.Info("pending PreprovisioningImage not ready")
@@ -696,7 +682,6 @@ func (r *BareMetalHostReconciler) getPreprovImage(info *reconcileInfo, formats [
 	expectedSpec := metal3v1alpha1.PreprovisioningImageSpec{
 		NetworkDataName: info.host.Spec.PreprovisioningNetworkDataName,
 		Architecture:    getHostArchitecture(info.host),
-		AcceptFormats:   formats,
 	}
 
 	preprovImage := metal3v1alpha1.PreprovisioningImage{}
@@ -824,6 +809,14 @@ 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.
@@ -960,7 +953,8 @@ func (r *BareMetalHostReconciler) actionPreparing(prov provisioner.Provisioner,
 	// Use settings in hostFirmwareSettings if available
 	hfs, err := r.getHostFirmwareSettings(info)
 	if err != nil {
-		info.log.Info("hostFirmwareSettings not available for cleaning")
+		// wait until hostFirmwareSettings are ready
+		return actionContinue{subResourceNotReadyRetryDelay}
 	}
 	if hfs != nil {
 		prepareData.ActualFirmwareSettings = hfs.Status.Settings.DeepCopy()
@@ -1334,6 +1328,38 @@ 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) {
 
@@ -1351,9 +1377,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.UpdateRequested)) {
+	if meta.IsStatusConditionTrue(hfs.Status.Conditions, string(metal3v1alpha1.FirmwareSettingsChangeDetected)) {
 
-		if meta.IsStatusConditionTrue(hfs.Status.Conditions, string(metal3v1alpha1.SettingsValid)) {
+		if meta.IsStatusConditionTrue(hfs.Status.Conditions, string(metal3v1alpha1.FirmwareSettingsValid)) {
 			return hfs, nil
 		}
 
@@ -1440,7 +1466,7 @@ func (r *BareMetalHostReconciler) getBMCSecretAndSetOwner(request ctrl.Request,
 	reqLogger := r.Log.WithValues("baremetalhost", request.NamespacedName)
 	secretManager := r.secretManager(reqLogger)
 
-	bmcCredsSecret, err := secretManager.AcquireSecret(host.CredentialsKey(), host, true, true)
+	bmcCredsSecret, err := secretManager.AcquireSecret(host.CredentialsKey(), host, true)
 	if err != nil {
 		if k8serrors.IsNotFound(err) {
 			return nil, &ResolveBMCSecretRefError{message: fmt.Sprintf("The BMC secret %s does not exist", host.CredentialsKey())}
diff --git a/controllers/metal3.io/hostfirmwaresettings_controller.go b/controllers/metal3.io/hostfirmwaresettings_controller.go
index 566480e7..a3370a48 100644
--- a/controllers/metal3.io/hostfirmwaresettings_controller.go
+++ b/controllers/metal3.io/hostfirmwaresettings_controller.go
@@ -21,7 +21,9 @@ import (
 	"crypto/sha256"
 	"fmt"
 	"sort"
+	"strconv"
 	"strings"
+	"time"
 
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
@@ -30,21 +32,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
@@ -115,24 +117,20 @@ 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")
-		// only run again if created
-		return ctrl.Result{}, nil
+		return ctrl.Result{Requeue: true, RequeueAfter: resourceNotAvailableRetryDelay}, 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) {
-			// 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")
+			reqLogger.Info("hostFirmwareSettings not found")
+			return ctrl.Result{Requeue: true, RequeueAfter: resourceNotAvailableRetryDelay}, nil
 		}
+		// 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
@@ -143,13 +141,20 @@ func (r *HostFirmwareSettingsReconciler) Reconcile(ctx context.Context, req ctrl
 
 	ready, err := prov.IsReady()
 	if err != nil || !ready {
-		reqLogger.Info("provisioner is not ready", "RequeueAfter:", provisionerNotReadyRetryDelay)
-		return ctrl.Result{Requeue: true, RequeueAfter: provisionerNotReadyRetryDelay}, nil
+		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
 	}
 
-	// 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 {
+	if err = r.updateHostFirmwareSettings(currentSettings, schema, info); err != nil {
 		return ctrl.Result{}, errors.Wrap(err, "Could not update hostFirmwareSettings")
 	}
 
@@ -157,20 +162,12 @@ func (r *HostFirmwareSettingsReconciler) Reconcile(ctx context.Context, req ctrl
 		r.publishEvent(req, e)
 	}
 
-	// only run again on changes
-	return ctrl.Result{}, nil
+	// requeue to run again after delay
+	return ctrl.Result{Requeue: true, RequeueAfter: reconcilerRequeueDelay}, nil
 }
 
 // Get the firmware settings from the provisioner and update hostFirmwareSettings
-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")
-	}
+func (r *HostFirmwareSettingsReconciler) updateHostFirmwareSettings(currentSettings metal3v1alpha1.SettingsMap, schema map[string]metal3v1alpha1.SettingSchema, info *rInfo) (err error) {
 
 	// get or create a firmwareSchema to hold schema
 	firmwareSchema, err := r.getOrCreateFirmwareSchema(info, schema)
@@ -197,12 +194,13 @@ func (r *HostFirmwareSettingsReconciler) updateStatus(info *rInfo, settings meta
 		info.hfs.Status.Settings = make(metal3v1alpha1.SettingsMap)
 	}
 
-	// Update Status
+	// Update Status on changes
 	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
 	}
 
@@ -214,6 +212,10 @@ 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
 		}
 	}
 
@@ -222,26 +224,33 @@ func (r *HostFirmwareSettingsReconciler) updateStatus(info *rInfo, settings meta
 	generation := info.hfs.GetGeneration()
 
 	if specMismatch {
-		setCondition(generation, &info.hfs.Status, metal3v1alpha1.UpdateRequested, metav1.ConditionTrue, reason, "")
+		setCondition(generation, &info.hfs.Status, metal3v1alpha1.FirmwareSettingsChangeDetected, metav1.ConditionTrue, reason, "")
 
-	} else {
-		setCondition(generation, &info.hfs.Status, metal3v1alpha1.UpdateRequested, metav1.ConditionFalse, 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))
+			}
 
-	// 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, "")
+			reason = reasonConfigurationError
+			setCondition(generation, &info.hfs.Status, metal3v1alpha1.FirmwareSettingsValid, metav1.ConditionFalse, reason, "Invalid BIOS setting")
+		}
 	} else {
-		for _, error := range errors {
-			info.publishEvent("ValidationFailed", fmt.Sprintf("Invalid BIOS setting: %v", error))
+		// 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, "")
 		}
-
-		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)
 }
 
@@ -259,12 +268,19 @@ 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{
@@ -285,15 +301,12 @@ func (r *HostFirmwareSettingsReconciler) getOrCreateFirmwareSchema(info *rInfo,
 	for k, v := range schema {
 		firmwareSchema.Spec.Schema[k] = v
 	}
-
-	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 {
+	// 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.Update(context.TODO(), firmwareSchema); err != nil {
+
+	if err = r.Create(context.TODO(), firmwareSchema); err != nil {
 		return nil, err
 	}
 
@@ -302,91 +315,11 @@ func (r *HostFirmwareSettingsReconciler) getOrCreateFirmwareSchema(info *rInfo,
 	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)
 }
 
@@ -447,19 +380,37 @@ func setCondition(generation int64, status *metal3v1alpha1.HostFirmwareSettingsS
 	meta.SetStatusCondition(&status.Conditions, newCondition)
 }
 
-// Generate a name based on the schema keys which should be the same for similar hardware
+// Generate a name based on the schema key and values 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.
-	// 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)
+	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))
+		}
 	}
-	sort.Strings(keys)
+	sort.Strings(hashkeys)
 
 	h := sha256.New()
-	h.Write([]byte(fmt.Sprintf("%v", keys)))
+	h.Write([]byte(fmt.Sprintf("%v", hashkeys)))
 	hash := fmt.Sprintf("%x", h.Sum(nil))[:8]
 
 	return "schema-" + hash
diff --git a/controllers/metal3.io/preprovisioningimage_controller.go b/controllers/metal3.io/preprovisioningimage_controller.go
index 1f9f83e2..16622831 100644
--- a/controllers/metal3.io/preprovisioningimage_controller.go
+++ b/controllers/metal3.io/preprovisioningimage_controller.go
@@ -18,10 +18,10 @@ package controllers
 
 import (
 	"context"
+	"os"
 	"time"
 
 	"github.com/go-logr/logr"
-	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	apiequality "k8s.io/apimachinery/pkg/api/equality"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -32,9 +32,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/imageprovider"
 	"github.com/metal3-io/baremetal-operator/pkg/secretutils"
-	"github.com/metal3-io/baremetal-operator/pkg/utils"
 )
 
 const (
@@ -45,10 +43,9 @@ const (
 // PreprovisioningImageReconciler reconciles a PreprovisioningImage object
 type PreprovisioningImageReconciler struct {
 	client.Client
-	Log           logr.Logger
-	Scheme        *runtime.Scheme
-	APIReader     client.Reader
-	ImageProvider imageprovider.ImageProvider
+	Log       logr.Logger
+	Scheme    *runtime.Scheme
+	APIReader client.Reader
 }
 
 type imageConditionReason string
@@ -78,30 +75,6 @@ func (r *PreprovisioningImageReconciler) Reconcile(ctx context.Context, req ctrl
 		return ctrl.Result{}, err
 	}
 
-	if !img.DeletionTimestamp.IsZero() {
-		log.Info("cleaning up deleted resource")
-		if err := r.discardExistingImage(&img, log); err != nil {
-			return ctrl.Result{}, err
-		}
-		img.Finalizers = utils.FilterStringFromList(
-			img.Finalizers, metal3.PreprovisioningImageFinalizer)
-		err := r.Update(ctx, &img)
-		if err != nil {
-			return ctrl.Result{}, errors.Wrap(err, "failed to remove finalizer")
-		}
-		return ctrl.Result{}, nil
-	}
-
-	if !utils.StringInList(img.Finalizers, metal3.PreprovisioningImageFinalizer) {
-		log.Info("adding finalizer")
-		img.Finalizers = append(img.Finalizers, metal3.PreprovisioningImageFinalizer)
-		err := r.Update(ctx, &img)
-		if err != nil {
-			return ctrl.Result{}, errors.Wrap(err, "failed to add finalizer")
-		}
-		return ctrl.Result{}, nil
-	}
-
 	changed, err := r.update(&img, log)
 
 	if k8serrors.IsNotFound(err) {
@@ -117,102 +90,42 @@ func (r *PreprovisioningImageReconciler) Reconcile(ctx context.Context, req ctrl
 	return result, err
 }
 
-func configChanged(img *metal3.PreprovisioningImage, format metal3.ImageFormat, networkDataStatus metal3.SecretStatus) bool {
-	return !(img.Status.Format == format &&
-		img.Status.Architecture == img.Spec.Architecture &&
-		img.Status.NetworkData == networkDataStatus)
-}
-
 func (r *PreprovisioningImageReconciler) update(img *metal3.PreprovisioningImage, log logr.Logger) (bool, error) {
 	generation := img.GetGeneration()
 
-	if !r.ImageProvider.SupportsArchitecture(img.Spec.Architecture) {
-		log.Info("image architecture not supported", "architecture", img.Spec.Architecture)
-		return setError(generation, &img.Status, reasonImageConfigurationError, "Architecture not supported"), nil
-	}
-
-	format := r.getImageFormat(img.Spec, log)
-	if format == "" {
-		return setError(generation, &img.Status, reasonImageConfigurationError, "No acceptable image format supported"), nil
+	url, format, errorMessage := getImageURL()
+	if errorMessage != "" {
+		log.Info("no suitable image URL available", "preferredFormat", format)
+		return setError(generation, &img.Status, reasonImageConfigurationError, errorMessage), nil
 	}
 
+	log.Info("image URL available", "url", url, "format", format)
 	secretManager := secretutils.NewSecretManager(log, r.Client, r.APIReader)
-	networkData, secretStatus, err := getNetworkData(secretManager, img)
-	if err != nil {
-		if k8serrors.IsNotFound(err) {
-			log.Info("network data Secret does not exist")
-			return setError(generation, &img.Status, reasonImageMissingNetworkData, "NetworkData secret not found"), err
-		}
-		return false, err
+	secretStatus, err := getNetworkDataStatus(secretManager, img)
+	if err == nil {
+		return setImage(generation, &img.Status, url, format,
+			secretStatus, img.Spec.Architecture,
+			"Set default image"), nil
 	}
 
-	if configChanged(img, format, secretStatus) {
-		reason := "Config changed"
-		if meta.IsStatusConditionTrue(img.Status.Conditions, string(metal3.ConditionImageReady)) {
-			// Ensure we mark the status as not ready before we remove the build
-			// from the image cache.
-			setUnready(generation, &img.Status, reason)
-		} else {
-			if err := r.discardExistingImage(img, log); err != nil {
-				return false, err
-			}
-			// Set up all the data before building the image and adding the URL,
-			// so that even if we fail to write the built image status and the
-			// config subsequently changes, the image cache cannot leak.
-			setImage(generation, &img.Status, "", format,
-				secretStatus, img.Spec.Architecture,
-				reason)
-		}
-		return true, nil
-	}
-
-	var networkDataContent imageprovider.NetworkData
-	if networkData != nil {
-		networkDataContent = networkData.Data
-	}
-	url, err := r.ImageProvider.BuildImage(imageprovider.ImageData{
-		ImageMetadata:     img.ObjectMeta.DeepCopy(),
-		Format:            format,
-		Architecture:      img.Spec.Architecture,
-		NetworkDataStatus: secretStatus,
-	}, networkDataContent, log)
-	if err != nil {
-		return false, err
+	if k8serrors.IsNotFound(err) {
+		log.Info("network data Secret does not exist")
+		return setError(generation, &img.Status, reasonImageMissingNetworkData, "NetworkData secret not found"), err
 	}
-	log.Info("image URL available", "url", url, "format", format)
 
-	return setImage(generation, &img.Status, url, format,
-		secretStatus, img.Spec.Architecture,
-		"Generated image"), nil
+	return false, err
 }
 
-func (r *PreprovisioningImageReconciler) getImageFormat(spec metal3.PreprovisioningImageSpec, log logr.Logger) (format metal3.ImageFormat) {
-	for _, acceptableFormat := range spec.AcceptFormats {
-		if r.ImageProvider.SupportsFormat(acceptableFormat) {
-			return acceptableFormat
-		}
-	}
-
-	if len(spec.AcceptFormats) > 0 {
-		log = log.WithValues("preferredFormat", spec.AcceptFormats[0])
+func getImageURL() (url string, format metal3.ImageFormat, errorMessage string) {
+	format = metal3.ImageFormatISO
+	if iso := os.Getenv("DEPLOY_ISO_URL"); iso != "" {
+		url = iso
+	} else {
+		errorMessage = "No DEPLOY_ISO_URL specified"
 	}
-	log.Info("no acceptable image format supported")
 	return
 }
 
-func (r *PreprovisioningImageReconciler) discardExistingImage(img *metal3.PreprovisioningImage, log logr.Logger) error {
-	if img.Status.Format == "" {
-		return nil
-	}
-	log.Info("discarding existing image", "image_url", img.Status.ImageUrl)
-	return r.ImageProvider.DiscardImage(imageprovider.ImageData{
-		ImageMetadata:     img.ObjectMeta.DeepCopy(),
-		Format:            img.Status.Format,
-		Architecture:      img.Status.Architecture,
-		NetworkDataStatus: img.Status.NetworkData,
-	})
-}
-
 func getErrorRetryDelay(status metal3.PreprovisioningImageStatus) time.Duration {
 	errorCond := meta.FindStatusCondition(status.Conditions, string(metal3.ConditionImageError))
 	if errorCond == nil || errorCond.Status != metav1.ConditionTrue {
@@ -228,22 +141,22 @@ func getErrorRetryDelay(status metal3.PreprovisioningImageStatus) time.Duration
 	return delay
 }
 
-func getNetworkData(secretManager secretutils.SecretManager, img *metal3.PreprovisioningImage) (*corev1.Secret, metal3.SecretStatus, error) {
+func getNetworkDataStatus(secretManager secretutils.SecretManager, img *metal3.PreprovisioningImage) (metal3.SecretStatus, error) {
 	networkDataSecret := img.Spec.NetworkDataName
 	if networkDataSecret == "" {
-		return nil, metal3.SecretStatus{}, nil
+		return metal3.SecretStatus{}, nil
 	}
 
 	secretKey := client.ObjectKey{
 		Name:      networkDataSecret,
 		Namespace: img.ObjectMeta.Namespace,
 	}
-	secret, err := secretManager.AcquireSecret(secretKey, img, false, false)
+	secret, err := secretManager.AcquireSecret(secretKey, img, false)
 	if err != nil {
-		return nil, metal3.SecretStatus{}, err
+		return metal3.SecretStatus{}, err
 	}
 
-	return secret, metal3.SecretStatus{
+	return metal3.SecretStatus{
 		Name:    networkDataSecret,
 		Version: secret.GetResourceVersion(),
 	}, nil
@@ -275,12 +188,8 @@ func setImage(generation int64, status *metal3.PreprovisioningImageStatus, url s
 
 	time := metav1.Now()
 	reason := reasonImageSuccess
-	ready := metav1.ConditionFalse
-	if url != "" {
-		ready = metav1.ConditionTrue
-	}
 	setImageCondition(generation, newStatus,
-		metal3.ConditionImageReady, ready,
+		metal3.ConditionImageReady, metav1.ConditionTrue,
 		time, reason, message)
 	setImageCondition(generation, newStatus,
 		metal3.ConditionImageError, metav1.ConditionFalse,
@@ -291,20 +200,6 @@ func setImage(generation int64, status *metal3.PreprovisioningImageStatus, url s
 	return changed
 }
 
-func setUnready(generation int64, status *metal3.PreprovisioningImageStatus, message string) bool {
-	newStatus := status.DeepCopy()
-
-	time := metav1.Now()
-	reason := reasonImageSuccess
-	setImageCondition(generation, newStatus,
-		metal3.ConditionImageReady, metav1.ConditionFalse,
-		time, reason, message)
-
-	changed := !apiequality.Semantic.DeepEqual(status, &newStatus)
-	*status = *newStatus
-	return changed
-}
-
 func setError(generation int64, status *metal3.PreprovisioningImageStatus, reason imageConditionReason, message string) bool {
 	newStatus := status.DeepCopy()
 	newStatus.ImageUrl = ""
@@ -323,13 +218,15 @@ func setError(generation int64, status *metal3.PreprovisioningImageStatus, reaso
 }
 
 func (r *PreprovisioningImageReconciler) CanStart() bool {
-	for _, fmt := range []metal3.ImageFormat{metal3.ImageFormatISO, metal3.ImageFormatInitRD} {
-		if r.ImageProvider.SupportsFormat(fmt) {
-			return true
-		}
-	}
-	r.Log.Info("not starting preprovisioning image controller; no image data available")
-	return false
+	deployISOURL := os.Getenv("DEPLOY_ISO_URL")
+	hasCfg := deployISOURL != ""
+	if hasCfg {
+		r.Log.Info("have deploy image data",
+			"iso_url", deployISOURL)
+	} else {
+		r.Log.Info("not starting preprovisioning image controller; no image data available")
+	}
+	return hasCfg
 }
 
 func (r *PreprovisioningImageReconciler) SetupWithManager(mgr ctrl.Manager) error {
diff --git a/docs/api.md b/docs/api.md
index 159ec6c3..b9634262 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -50,8 +50,6 @@ communicate with them.
 * HPE iLO 4
   * `ilo4://<host>:<port>` for iLO 4 based systems and the port is optional,
     if using the default one (443).
-  * `ilo4-virtualmedia://<host>:<port>` to use virtual media instead of PXE
-    for iLO 4 based systems.
 * HPE iLO 5
   * `ilo5://<host>:<port>` for iLO 5 based systems and the port is optional,
     if using the default one (443).
diff --git a/docs/dev-setup.md b/docs/dev-setup.md
index e06cc44e..ce547632 100644
--- a/docs/dev-setup.md
+++ b/docs/dev-setup.md
@@ -172,8 +172,8 @@ and clean it with
 
 It is also possible to develop Baremetal Operator using Tilt with CAPM3. Please
 refer to
-[the development setup guide of CAPM3](https://github.com/metal3-io/cluster-api-provider-metal3/blob/main/docs/dev-setup.md#tilt-for-dev-in-capm3)
-and specially the [Baremetal Operator Integration](https://github.com/metal3-io/cluster-api-provider-metal3/blob/main/docs/dev-setup.md#including-baremetal-operator-and-ip-address-manager)
+[the development setup guide of CAPM3](https://github.com/metal3-io/cluster-api-provider-metal3/blob/master/docs/dev-setup.md#tilt-for-dev-in-capm3)
+and specially the [Baremetal Operator Integration](https://github.com/metal3-io/cluster-api-provider-metal3/blob/master/docs/dev-setup.md#including-baremetal-operator-and-ip-address-manager)
 
 ## Using libvirt VMs with Ironic
 
diff --git a/go.mod b/go.mod
index 398a118d..f476aeb1 100644
--- a/go.mod
+++ b/go.mod
@@ -6,11 +6,10 @@ require (
 	github.com/go-logr/logr v0.4.0
 	github.com/gophercloud/gophercloud v0.18.0
 	github.com/metal3-io/baremetal-operator/apis v0.0.0
-	github.com/metal3-io/baremetal-operator/pkg/hardwareutils v0.0.0
+	github.com/metal3-io/baremetal-operator/pkg/ironic v0.0.0
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus/client_golang v1.11.0
 	github.com/stretchr/testify v1.7.0
-	go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489
 	k8s.io/api v0.21.4
 	k8s.io/apimachinery v0.21.4
 	k8s.io/client-go v0.21.4
@@ -21,4 +20,4 @@ require (
 
 replace github.com/metal3-io/baremetal-operator/apis => ./apis
 
-replace github.com/metal3-io/baremetal-operator/pkg/hardwareutils => ./pkg/hardwareutils
+replace github.com/metal3-io/baremetal-operator/pkg/ironic => ./pkg/ironic
diff --git a/hack/manifestlint.sh b/hack/manifestlint.sh
index 1e0c2724..8698aba3 100755
--- a/hack/manifestlint.sh
+++ b/hack/manifestlint.sh
@@ -23,7 +23,7 @@ if [ "${IS_CONTAINER}" != "false" ]; then
     { set +x; } 2>/dev/null
     echo "<-------------------------STARTING MANIFESTS VALIDATION CHECKS------------------------->"
     kubeval --strict --ignore-missing-schemas \
-    -d config,examples -i kustom,patch,controller_manager_config -o tap
+    -d config,examples -i kustom,patch -o tap
     echo "<-------------------------COMPLETED MANIFESTS VALIDATION CHECKS------------------------>"
 else
   "${CONTAINER_RUNTIME}" run --rm \
diff --git a/hack/unit.sh b/hack/unit.sh
index 6993ccc7..05bace2a 100755
--- a/hack/unit.sh
+++ b/hack/unit.sh
@@ -11,7 +11,9 @@ if [ "${IS_CONTAINER}" != "false" ]; then
   eval "$(go env)"
   cd "${GOPATH}"/src/github.com/metal3-io/baremetal-operator
   export XDG_CACHE_HOME="/tmp/.cache"
+
   export COVER_PROFILE="${ARTIFACTS}"/cover.out
+
   TEST_FLAGS=${TEST_FLAGS} make -e unit-cover
 
 else
diff --git a/ironic-deployment/ironic/ironic.yaml b/ironic-deployment/ironic/ironic.yaml
index 9f859267..cb3dc54b 100644
--- a/ironic-deployment/ironic/ironic.yaml
+++ b/ironic-deployment/ironic/ironic.yaml
@@ -26,22 +26,6 @@ spec:
                add: ["NET_ADMIN"]
           command:
             - /bin/rundnsmasq
-          livenessProbe:
-           exec:
-             command: ["sh", "-c", "ss -lun | grep :67 && ss -lun | grep :69"]
-           initialDelaySeconds: 30
-           periodSeconds: 30
-           timeoutSeconds: 10
-           successThreshold: 1
-           failureThreshold: 10
-          readinessProbe:
-           exec:
-             command: ["sh", "-c", "ss -lun | grep :67 && ss -lun | grep :69"]
-           initialDelaySeconds: 30
-           periodSeconds: 30
-           timeoutSeconds: 10
-           successThreshold: 1
-           failureThreshold: 10
           volumeMounts:
             - mountPath: /shared
               name: ironic-data-volume
@@ -53,22 +37,6 @@ spec:
           imagePullPolicy: Always
           command:
             - /bin/runmariadb
-          livenessProbe:
-           exec:
-             command: ["sh", "-c", "mysqladmin status -uironic -p$(printenv MARIADB_PASSWORD)"]
-           initialDelaySeconds: 30
-           periodSeconds: 30
-           timeoutSeconds: 10
-           successThreshold: 1
-           failureThreshold: 10
-          readinessProbe:
-           exec:
-             command: ["sh", "-c", "mysqladmin status -uironic -p$(printenv MARIADB_PASSWORD)"]
-           initialDelaySeconds: 30
-           periodSeconds: 30
-           timeoutSeconds: 10
-           successThreshold: 1
-           failureThreshold: 10
           volumeMounts:
             - mountPath: /shared
               name: ironic-data-volume
@@ -88,22 +56,6 @@ spec:
           imagePullPolicy: Always
           command:
             - /bin/runironic-api
-          livenessProbe:
-           exec:
-             command: ["sh", "-c", "curl -sSf http://127.0.0.1:6385 || curl -sSfk https://127.0.0.1:6385"]
-           initialDelaySeconds: 30
-           periodSeconds: 30
-           timeoutSeconds: 10
-           successThreshold: 1
-           failureThreshold: 10
-          readinessProbe:
-           exec:
-             command: ["sh", "-c", "curl -sSf http://127.0.0.1:6385 || curl -sSfk https://127.0.0.1:6385"]
-           initialDelaySeconds: 30
-           periodSeconds: 30
-           timeoutSeconds: 10
-           successThreshold: 1
-           failureThreshold: 10
           volumeMounts:
             - mountPath: /shared
               name: ironic-data-volume
@@ -121,22 +73,6 @@ spec:
           imagePullPolicy: Always
           command:
             - /bin/runironic-conductor
-          readinessProbe:
-            exec:
-              command: ["sh", "-c", "curl -sd '{}' -o – -k https://127.0.0.1:8089 || curl -sd '{}' -o – http://127.0.0.1:8089"]
-            initialDelaySeconds: 30
-            periodSeconds: 30
-            timeoutSeconds: 10
-            successThreshold: 1
-            failureThreshold: 10
-          livenessProbe:
-            exec:
-              command: ["sh", "-c", "curl -sd '{}' -o – -k https://127.0.0.1:8089 || curl -sd '{}' -o – http://127.0.0.1:8089"]
-            initialDelaySeconds: 30
-            periodSeconds: 30
-            timeoutSeconds: 10
-            successThreshold: 1
-            failureThreshold: 10
           volumeMounts:
             - mountPath: /shared
               name: ironic-data-volume
@@ -160,22 +96,6 @@ spec:
         - name: ironic-inspector
           image: quay.io/metal3-io/ironic
           imagePullPolicy: Always
-          readinessProbe:
-            exec:
-              command: ["sh", "-c", "curl -sSf http://127.0.0.1:5050 || curl -sSf -k https://127.0.0.1:5050"]
-            initialDelaySeconds: 30
-            periodSeconds: 30
-            timeoutSeconds: 10
-            successThreshold: 1
-            failureThreshold: 10
-          livenessProbe:
-            exec:
-              command: ["sh", "-c", "curl -sSf http://127.0.0.1:5050 || curl -sSf -k https://127.0.0.1:5050"]
-            initialDelaySeconds: 30
-            periodSeconds: 30
-            timeoutSeconds: 10
-            successThreshold: 1
-            failureThreshold: 10
           command:
             - /bin/runironic-inspector
           envFrom:
diff --git a/main.go b/main.go
index db41cb11..2c259c97 100644
--- a/main.go
+++ b/main.go
@@ -1,5 +1,6 @@
 /*
 
+
 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
@@ -31,7 +32,6 @@ import (
 
 	metal3iov1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
 	metal3iocontroller "github.com/metal3-io/baremetal-operator/controllers/metal3.io"
-	"github.com/metal3-io/baremetal-operator/pkg/imageprovider"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner/demo"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner/fixture"
@@ -83,7 +83,7 @@ func setupWebhooks(mgr ctrl.Manager) {
 
 func main() {
 	var watchNamespace string
-	var metricsBindAddr string
+	var metricsAddr string
 	var enableLeaderElection bool
 	var preprovImgEnable bool
 	var devLogging bool
@@ -97,7 +97,7 @@ func main() {
 	// namespace.
 	flag.StringVar(&watchNamespace, "namespace", os.Getenv("WATCH_NAMESPACE"),
 		"Namespace that the controller watches to reconcile host resources.")
-	flag.StringVar(&metricsBindAddr, "metrics-addr", "127.0.0.1:8085",
+	flag.StringVar(&metricsAddr, "metrics-addr", "127.0.0.1:8085",
 		"The address the metric endpoint binds to.")
 	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
 		"Enable leader election for controller manager. "+
@@ -126,7 +126,7 @@ func main() {
 
 	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
 		Scheme:                  scheme,
-		MetricsBindAddress:      metricsBindAddr,
+		MetricsBindAddress:      metricsAddr,
 		Port:                    webhookPort,
 		LeaderElection:          enableLeaderElection,
 		LeaderElectionID:        "baremetal-operator",
@@ -166,11 +166,10 @@ func main() {
 
 	if preprovImgEnable {
 		imgReconciler := metal3iocontroller.PreprovisioningImageReconciler{
-			Client:        mgr.GetClient(),
-			Log:           ctrl.Log.WithName("controllers").WithName("PreprovisioningImage"),
-			APIReader:     mgr.GetAPIReader(),
-			Scheme:        mgr.GetScheme(),
-			ImageProvider: imageprovider.NewDefaultImageProvider(),
+			Client:    mgr.GetClient(),
+			Log:       ctrl.Log.WithName("controllers").WithName("PreprovisioningImage"),
+			APIReader: mgr.GetAPIReader(),
+			Scheme:    mgr.GetScheme(),
 		}
 		if imgReconciler.CanStart() {
 			if err = (&imgReconciler).SetupWithManager(mgr); err != nil {
diff --git a/pkg/hardwareutils/go.mod b/pkg/hardwareutils/go.mod
deleted file mode 100644
index 2416e5c1..00000000
--- a/pkg/hardwareutils/go.mod
+++ /dev/null
@@ -1,5 +0,0 @@
-module github.com/metal3-io/baremetal-operator/pkg/hardwareutils
-
-go 1.16
-
-require github.com/pkg/errors v0.9.1
diff --git a/pkg/hardwareutils/go.sum b/pkg/hardwareutils/go.sum
deleted file mode 100644
index 7c401c3f..00000000
--- a/pkg/hardwareutils/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
diff --git a/pkg/imageprovider/default.go b/pkg/imageprovider/default.go
deleted file mode 100644
index c6de4f70..00000000
--- a/pkg/imageprovider/default.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package imageprovider
-
-import (
-	"fmt"
-	"os"
-
-	"github.com/go-logr/logr"
-
-	metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-)
-
-type envImageProvider struct {
-	isoURL    string
-	initrdURL string
-}
-
-func NewDefaultImageProvider() ImageProvider {
-	return envImageProvider{
-		isoURL:    os.Getenv("DEPLOY_ISO_URL"),
-		initrdURL: os.Getenv("DEPLOY_RAMDISK_URL"),
-	}
-}
-
-func (eip envImageProvider) SupportsArchitecture(arch string) bool {
-	return true
-}
-
-func (eip envImageProvider) SupportsFormat(format metal3.ImageFormat) bool {
-	switch format {
-	case metal3.ImageFormatISO:
-		return eip.isoURL != ""
-	case metal3.ImageFormatInitRD:
-		// Assume we are running inside the same process as the BMH controller -
-		// if there is no kernel URL then it will be unable to use the initrd.
-		if os.Getenv("DEPLOY_KERNEL_URL") == "" {
-			return false
-		}
-		return eip.initrdURL != ""
-	default:
-		return false
-	}
-}
-
-func (eip envImageProvider) BuildImage(data ImageData, networkData NetworkData, log logr.Logger) (url string, err error) {
-	switch data.Format {
-	case metal3.ImageFormatISO:
-		url = eip.isoURL
-	case metal3.ImageFormatInitRD:
-		url = eip.initrdURL
-	}
-	if url == "" {
-		err = fmt.Errorf("Unsupported image format \"%s\"", data.Format)
-	}
-	return
-}
-
-func (eip envImageProvider) DiscardImage(data ImageData) error {
-	return nil
-}
diff --git a/pkg/imageprovider/imageprovider.go b/pkg/imageprovider/imageprovider.go
deleted file mode 100644
index ab47ba64..00000000
--- a/pkg/imageprovider/imageprovider.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package imageprovider
-
-import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-
-	"github.com/go-logr/logr"
-
-	metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-)
-
-// ImageData contains information about the image type being requested, and
-// metadata about the request.
-type ImageData struct {
-	ImageMetadata     *metav1.ObjectMeta
-	Format            metal3.ImageFormat
-	Architecture      string
-	NetworkDataStatus metal3.SecretStatus
-}
-
-type NetworkData map[string][]byte
-
-type ImageProvider interface {
-	// SupportsArchitecture returns whether the ImageProvider can provide
-	// images for the given processor architecture.
-	SupportsArchitecture(string) bool
-
-	// SupportsFormat returns whether the ImageProvider can provide images in
-	// the given format.
-	SupportsFormat(metal3.ImageFormat) bool
-
-	// BuildImage requests the ImageProvider to build an image with the
-	// supplied network data and return a URL where it can be accessed.
-	BuildImage(ImageData, NetworkData, logr.Logger) (string, error)
-
-	// DiscardImage notifies the ImageProvider that a previously built image
-	// is no longer required.
-	DiscardImage(ImageData) error
-}
diff --git a/pkg/hardwareutils/bmc/credentials.go b/pkg/ironic/bmc/credentials.go
similarity index 100%
rename from pkg/hardwareutils/bmc/credentials.go
rename to pkg/ironic/bmc/credentials.go
diff --git a/pkg/hardwareutils/bmc/credentials_test.go b/pkg/ironic/bmc/credentials_test.go
similarity index 100%
rename from pkg/hardwareutils/bmc/credentials_test.go
rename to pkg/ironic/bmc/credentials_test.go
diff --git a/pkg/hardwareutils/bmc/errors.go b/pkg/ironic/bmc/errors.go
similarity index 100%
rename from pkg/hardwareutils/bmc/errors.go
rename to pkg/ironic/bmc/errors.go
diff --git a/pkg/hardwareutils/bmc/ibmc.go b/pkg/ironic/bmc/ibmc.go
similarity index 100%
rename from pkg/hardwareutils/bmc/ibmc.go
rename to pkg/ironic/bmc/ibmc.go
diff --git a/pkg/hardwareutils/bmc/idrac.go b/pkg/ironic/bmc/idrac.go
similarity index 100%
rename from pkg/hardwareutils/bmc/idrac.go
rename to pkg/ironic/bmc/idrac.go
diff --git a/pkg/hardwareutils/bmc/idrac_virtualmedia.go b/pkg/ironic/bmc/idrac_virtualmedia.go
similarity index 100%
rename from pkg/hardwareutils/bmc/idrac_virtualmedia.go
rename to pkg/ironic/bmc/idrac_virtualmedia.go
diff --git a/pkg/hardwareutils/bmc/ilo4.go b/pkg/ironic/bmc/ilo4.go
similarity index 83%
rename from pkg/hardwareutils/bmc/ilo4.go
rename to pkg/ironic/bmc/ilo4.go
index bff98bc6..6dffa10f 100644
--- a/pkg/hardwareutils/bmc/ilo4.go
+++ b/pkg/ironic/bmc/ilo4.go
@@ -8,7 +8,6 @@ import (
 
 func init() {
 	RegisterFactory("ilo4", newILOAccessDetails, []string{"https"})
-	RegisterFactory("ilo4-virtualmedia", newILOVirtualMediaAccessDetails, []string{"https"})
 }
 
 func newILOAccessDetails(parsedURL *url.URL, disableCertificateVerification bool) (AccessDetails, error) {
@@ -20,22 +19,11 @@ func newILOAccessDetails(parsedURL *url.URL, disableCertificateVerification bool
 	}, nil
 }
 
-func newILOVirtualMediaAccessDetails(parsedURL *url.URL, disableCertificateVerification bool) (AccessDetails, error) {
-	return &iLOAccessDetails{
-		bmcType:                        parsedURL.Scheme,
-		portNum:                        parsedURL.Port(),
-		hostname:                       parsedURL.Hostname(),
-		disableCertificateVerification: disableCertificateVerification,
-		useVirtualMedia:                true,
-	}, nil
-}
-
 type iLOAccessDetails struct {
 	bmcType                        string
 	portNum                        string
 	hostname                       string
 	disableCertificateVerification bool
-	useVirtualMedia                bool
 }
 
 func (a *iLOAccessDetails) Type() string {
@@ -87,11 +75,7 @@ func (a *iLOAccessDetails) BIOSInterface() string {
 }
 
 func (a *iLOAccessDetails) BootInterface() string {
-	if a.useVirtualMedia {
-		return "ilo-virtual-media"
-	} else {
-		return "ilo-ipxe"
-	}
+	return "ilo-ipxe"
 }
 
 func (a *iLOAccessDetails) ManagementInterface() string {
@@ -115,11 +99,11 @@ func (a *iLOAccessDetails) SupportsSecureBoot() bool {
 }
 
 func (a *iLOAccessDetails) SupportsISOPreprovisioningImage() bool {
-	return a.useVirtualMedia
+	return false
 }
 
 func (a *iLOAccessDetails) RequiresProvisioningNetwork() bool {
-	return !a.useVirtualMedia
+	return true
 }
 
 func (a *iLOAccessDetails) BuildBIOSSettings(firmwareConfig *FirmwareConfig) (settings []map[string]string, err error) {
diff --git a/pkg/hardwareutils/bmc/ilo5.go b/pkg/ironic/bmc/ilo5.go
similarity index 100%
rename from pkg/hardwareutils/bmc/ilo5.go
rename to pkg/ironic/bmc/ilo5.go
diff --git a/pkg/hardwareutils/bmc/ipmi.go b/pkg/ironic/bmc/ipmi.go
similarity index 100%
rename from pkg/hardwareutils/bmc/ipmi.go
rename to pkg/ironic/bmc/ipmi.go
diff --git a/pkg/hardwareutils/bmc/irmc.go b/pkg/ironic/bmc/irmc.go
similarity index 95%
rename from pkg/hardwareutils/bmc/irmc.go
rename to pkg/ironic/bmc/irmc.go
index 1bfa03f9..c6b12f83 100644
--- a/pkg/hardwareutils/bmc/irmc.go
+++ b/pkg/ironic/bmc/irmc.go
@@ -31,9 +31,7 @@ func (a *iRMCAccessDetails) Type() string {
 // NeedsMAC returns true when the host is going to need a separate
 // port created rather than having it discovered.
 func (a *iRMCAccessDetails) NeedsMAC() bool {
-	// For the inspection to work, we need a MAC address
-	// https://github.com/metal3-io/baremetal-operator/pull/284#discussion_r317579040
-	return true
+	return false
 }
 
 func (a *iRMCAccessDetails) Driver() string {
diff --git a/pkg/hardwareutils/bmc/redfish.go b/pkg/ironic/bmc/redfish.go
similarity index 100%
rename from pkg/hardwareutils/bmc/redfish.go
rename to pkg/ironic/bmc/redfish.go
diff --git a/pkg/hardwareutils/bmc/redfish_virtualmedia.go b/pkg/ironic/bmc/redfish_virtualmedia.go
similarity index 100%
rename from pkg/hardwareutils/bmc/redfish_virtualmedia.go
rename to pkg/ironic/bmc/redfish_virtualmedia.go
diff --git a/pkg/provisioner/ironic/clients/auth.go b/pkg/ironic/clients/auth.go
similarity index 100%
rename from pkg/provisioner/ironic/clients/auth.go
rename to pkg/ironic/clients/auth.go
diff --git a/pkg/provisioner/ironic/clients/auth_test.go b/pkg/ironic/clients/auth_test.go
similarity index 100%
rename from pkg/provisioner/ironic/clients/auth_test.go
rename to pkg/ironic/clients/auth_test.go
diff --git a/pkg/provisioner/ironic/clients/client.go b/pkg/ironic/clients/client.go
similarity index 100%
rename from pkg/provisioner/ironic/clients/client.go
rename to pkg/ironic/clients/client.go
diff --git a/pkg/provisioner/ironic/dependencies.go b/pkg/ironic/dependencies.go
similarity index 97%
rename from pkg/provisioner/ironic/dependencies.go
rename to pkg/ironic/dependencies.go
index 92549258..89a69f94 100644
--- a/pkg/provisioner/ironic/dependencies.go
+++ b/pkg/ironic/dependencies.go
@@ -20,7 +20,7 @@ type ironicDependenciesChecker struct {
 	log       logr.Logger
 }
 
-func newIronicDependenciesChecker(client *gophercloud.ServiceClient, inspector *gophercloud.ServiceClient, log logr.Logger) *ironicDependenciesChecker {
+func NewIronicDependenciesChecker(client *gophercloud.ServiceClient, inspector *gophercloud.ServiceClient, log logr.Logger) *ironicDependenciesChecker {
 	return &ironicDependenciesChecker{
 		client:    client,
 		inspector: inspector,
diff --git a/pkg/provisioner/ironic/devicehints/devicehints.go b/pkg/ironic/devicehints/devicehints.go
similarity index 100%
rename from pkg/provisioner/ironic/devicehints/devicehints.go
rename to pkg/ironic/devicehints/devicehints.go
diff --git a/pkg/provisioner/ironic/devicehints/devicehints_test.go b/pkg/ironic/devicehints/devicehints_test.go
similarity index 100%
rename from pkg/provisioner/ironic/devicehints/devicehints_test.go
rename to pkg/ironic/devicehints/devicehints_test.go
diff --git a/pkg/ironic/go.mod b/pkg/ironic/go.mod
new file mode 100644
index 00000000..128d9601
--- /dev/null
+++ b/pkg/ironic/go.mod
@@ -0,0 +1,14 @@
+module github.com/metal3-io/baremetal-operator/pkg/ironic
+
+go 1.16
+
+require (
+	github.com/go-logr/logr v0.4.0
+	github.com/gophercloud/gophercloud v0.18.0
+	github.com/metal3-io/baremetal-operator/apis v0.0.0
+	github.com/pkg/errors v0.9.1
+	github.com/stretchr/testify v1.7.0
+	go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489
+)
+
+replace github.com/metal3-io/baremetal-operator/apis => ../../apis
diff --git a/pkg/ironic/go.sum b/pkg/ironic/go.sum
new file mode 100644
index 00000000..470cb12e
--- /dev/null
+++ b/pkg/ironic/go.sum
@@ -0,0 +1,743 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
+github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+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=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
+github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
+github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
+github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM=
+github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
+github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
+github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
+github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+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/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
+github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
+github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
+github.com/gophercloud/gophercloud v0.18.0 h1:V6hcuMPmjXg+js9flU8T3RIHDCjV7F5CG5GD0MRhP/w=
+github.com/gophercloud/gophercloud v0.18.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
+github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
+github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+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.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=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 h1:1JFLBqwIgdyHN1ZtgjTBwO+blA6gVOmZurpiMEsETKo=
+go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE=
+go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-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=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+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=
+golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190412213103-97732733099d/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-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=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo=
+golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+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-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
+gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.21.4 h1:WtDkzTAuI31WZKDPeIYpEUA+WeUfXAmA7gwj6nzFfbc=
+k8s.io/api v0.21.4/go.mod h1:fTVGP+M4D8+00FN2cMnJqk/eb/GH53bvmNs2SVTmpFk=
+k8s.io/apiextensions-apiserver v0.21.4 h1:HkajN/vmT/9HnFmUxvpXfSGkTCvH/ax4e3+j6mqWUDU=
+k8s.io/apiextensions-apiserver v0.21.4/go.mod h1:OoC8LhI9LnV+wKjZkXIBbLUwtnOGJiTRE33qctH5CIk=
+k8s.io/apimachinery v0.21.4 h1:KDq0lWZVslHkuE5I7iGAQHwpK0aDTlar1E7IWEc4CNw=
+k8s.io/apimachinery v0.21.4/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI=
+k8s.io/apiserver v0.21.4/go.mod h1:SErUuFBBPZUcD2nsUU8hItxoYheqyYr2o/pCINEPW8g=
+k8s.io/client-go v0.21.4 h1:tcwj167If+v+pIGrCjaPG7hFo6SqFPFCCgMJy+Vm8Jc=
+k8s.io/client-go v0.21.4/go.mod h1:t0/eMKyUAq/DoQ7vW8NVVA00/nomlwC+eInsS8PxSew=
+k8s.io/code-generator v0.21.4/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo=
+k8s.io/component-base v0.21.4 h1:Bc0AttSyhJFVXEIHz+VX+D11j/5z7SPPhl6whiXaRzs=
+k8s.io/component-base v0.21.4/go.mod h1:ZKG0eHVX+tUDcaoIGpU3Vtk4TIjMddN9uhEWDmW6Nyg=
+k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=
+k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
+k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0=
+k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
+k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20210802155522-efc7438f0176 h1:Mx0aa+SUAcNRQbs5jUzV8lkDlGFU8laZsY9jrcVX5SY=
+k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/controller-runtime v0.9.7 h1:DlHMlAyLpgEITVvNsuZqMbf8/sJl9HirmCZIeR5H9mQ=
+sigs.k8s.io/controller-runtime v0.9.7/go.mod h1:nExcHcQ2zvLMeoO9K7rOesGCmgu32srN5SENvpAEbGA=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go b/pkg/ironic/hardwaredetails/hardwaredetails.go
similarity index 100%
rename from pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go
rename to pkg/ironic/hardwaredetails/hardwaredetails.go
diff --git a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go b/pkg/ironic/hardwaredetails/hardwaredetails_test.go
similarity index 100%
rename from pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go
rename to pkg/ironic/hardwaredetails/hardwaredetails_test.go
diff --git a/pkg/ironic/raid.go b/pkg/ironic/raid.go
new file mode 100644
index 00000000..ca2466f9
--- /dev/null
+++ b/pkg/ironic/raid.go
@@ -0,0 +1,231 @@
+package ironic
+
+import (
+	"fmt"
+	"reflect"
+
+	"github.com/pkg/errors"
+
+	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
+	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/devicehints"
+)
+
+const (
+	noRAIDInterface       string = "no-raid"
+	softwareRAIDInterface string = "agent"
+)
+
+// BuildRAIDCleanSteps build the clean steps for RAID configuration from BaremetalHost spec
+func BuildRAIDCleanSteps(raidInterface string, target *metal3v1alpha1.RAIDConfig, actual *metal3v1alpha1.RAIDConfig) (cleanSteps []nodes.CleanStep, err error) {
+	err = CheckRAIDConfigure(raidInterface, target)
+	if err != nil {
+		return nil, err
+	}
+
+	// No RAID
+	if raidInterface == noRAIDInterface {
+		return
+	}
+
+	// Software RAID
+	if raidInterface == softwareRAIDInterface {
+		// Ignore HardwareRAIDVolumes
+		if target != nil {
+			target.HardwareRAIDVolumes = nil
+		}
+		if actual != nil {
+			actual.HardwareRAIDVolumes = nil
+		}
+		if reflect.DeepEqual(target, actual) {
+			return
+		}
+
+		cleanSteps = append(
+			cleanSteps,
+			[]nodes.CleanStep{
+				{
+					Interface: "raid",
+					Step:      "delete_configuration",
+				},
+				{
+					Interface: "deploy",
+					Step:      "erase_devices_metadata",
+				},
+			}...,
+		)
+
+		// If software raid configuration is empty, only need to clear old configuration
+		if target == nil || len(target.SoftwareRAIDVolumes) == 0 {
+			return
+		}
+
+		cleanSteps = append(
+			cleanSteps,
+			nodes.CleanStep{
+				Interface: "raid",
+				Step:      "create_configuration",
+			},
+		)
+		return
+	}
+
+	// Hardware RAID
+	// 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
+	}
+	if reflect.DeepEqual(target, actual) {
+		return
+	}
+
+	// Add ‘delete_configuration’ before ‘create_configuration’ to make sure
+	// that only the desired logical disks exist in the system after manual cleaning.
+	cleanSteps = append(
+		cleanSteps,
+		nodes.CleanStep{
+			Interface: "raid",
+			Step:      "delete_configuration",
+		},
+	)
+
+	// If hardware raid configuration is empty, only need to clear old configuration
+	if len(target.HardwareRAIDVolumes) == 0 {
+		return
+	}
+
+	// ‘create_configuration’ doesn’t remove existing disks. It is recommended
+	// that only the desired logical disks exist in the system after manual cleaning.
+	cleanSteps = append(
+		cleanSteps,
+		nodes.CleanStep{
+			Interface: "raid",
+			Step:      "create_configuration",
+		},
+	)
+	return
+}
+
+func CheckRAIDConfigure(raidInterface string, raid *metal3v1alpha1.RAIDConfig) error {
+	switch raidInterface {
+	case noRAIDInterface:
+		if raid != nil && (len(raid.HardwareRAIDVolumes) != 0 || len(raid.SoftwareRAIDVolumes) != 0) {
+			return fmt.Errorf("raid settings are defined, but the node's driver %s does not support RAID", raidInterface)
+		}
+	case softwareRAIDInterface:
+		if raid != nil && len(raid.HardwareRAIDVolumes) != 0 {
+			return fmt.Errorf("node's driver %s does not support hardware RAID", raidInterface)
+		}
+	default:
+		if raid != nil && len(raid.HardwareRAIDVolumes) == 0 && len(raid.SoftwareRAIDVolumes) != 0 {
+			return fmt.Errorf("node's driver %s does not support software RAID", raidInterface)
+		}
+	}
+	return nil
+}
+
+// BuildTargetRAIDCfg build RAID logical disks, this method doesn't set the root volume
+func BuildTargetRAIDCfg(raid *metal3v1alpha1.RAIDConfig) (logicalDisks []nodes.LogicalDisk, err error) {
+	// Deal possible panic
+	defer func() {
+		r := recover()
+		if r != nil {
+			err = fmt.Errorf("panic in build RAID settings: %v", r)
+		}
+	}()
+
+	if raid == nil {
+		return
+	}
+
+	// build logicalDisks
+	if len(raid.HardwareRAIDVolumes) != 0 {
+		logicalDisks, err = buildTargetHardwareRAIDCfg(raid.HardwareRAIDVolumes)
+	} else if len(raid.SoftwareRAIDVolumes) != 0 {
+		logicalDisks, err = buildTargetSoftwareRAIDCfg(raid.SoftwareRAIDVolumes)
+	}
+
+	return
+}
+
+// A private method to build hardware RAID disks
+func buildTargetHardwareRAIDCfg(volumes []metal3v1alpha1.HardwareRAIDVolume) (logicalDisks []nodes.LogicalDisk, err error) {
+	var (
+		logicalDisk    nodes.LogicalDisk
+		nameCheckFlags map[string]int = make(map[string]int)
+	)
+
+	if len(volumes) == 0 {
+		return
+	}
+
+	for index, volume := range volumes {
+		// Check volume's name
+		if volume.Name != "" {
+			i, exist := nameCheckFlags[volume.Name]
+			if exist {
+				return nil, errors.Errorf("the names(%s) of volume[%d] and volume[%d] are repeated", volume.Name, index, i)
+			}
+			nameCheckFlags[volume.Name] = index
+		}
+		// Build logicalDisk
+		logicalDisk = nodes.LogicalDisk{
+			SizeGB:     volume.SizeGibibytes,
+			RAIDLevel:  nodes.RAIDLevel(volume.Level),
+			VolumeName: volume.Name,
+		}
+		if volume.Rotational != nil {
+			if *volume.Rotational {
+				logicalDisk.DiskType = nodes.HDD
+			} else {
+				logicalDisk.DiskType = nodes.SSD
+			}
+		}
+		if volume.NumberOfPhysicalDisks != nil {
+			logicalDisk.NumberOfPhysicalDisks = *volume.NumberOfPhysicalDisks
+		}
+		// Add to logicalDisks
+		logicalDisks = append(logicalDisks, logicalDisk)
+	}
+
+	return
+}
+
+// A private method to build software RAID disks
+func buildTargetSoftwareRAIDCfg(volumes []metal3v1alpha1.SoftwareRAIDVolume) (logicalDisks []nodes.LogicalDisk, err error) {
+	var (
+		logicalDisk nodes.LogicalDisk
+	)
+
+	if len(volumes) == 0 {
+		return
+	}
+
+	if nodes.RAIDLevel(volumes[0].Level) != nodes.RAID1 {
+		return nil, errors.Errorf("the level in first volume of software raid must be RAID1")
+	}
+
+	for _, volume := range volumes {
+		// Build logicalDisk
+		logicalDisk = nodes.LogicalDisk{
+			SizeGB:     volume.SizeGibibytes,
+			RAIDLevel:  nodes.RAIDLevel(volume.Level),
+			Controller: "software",
+		}
+		// Build physical disks hint
+		for i := range volume.PhysicalDisks {
+			logicalDisk.PhysicalDisks = append(logicalDisk.PhysicalDisks, devicehints.MakeHintMap(&volume.PhysicalDisks[i]))
+		}
+		// Add to logicalDisks
+		logicalDisks = append(logicalDisks, logicalDisk)
+	}
+
+	return
+}
diff --git a/pkg/provisioner/ironic/testserver/inspector.go b/pkg/ironic/testserver/inspector.go
similarity index 100%
rename from pkg/provisioner/ironic/testserver/inspector.go
rename to pkg/ironic/testserver/inspector.go
diff --git a/pkg/provisioner/ironic/testserver/ironic.go b/pkg/ironic/testserver/ironic.go
similarity index 100%
rename from pkg/provisioner/ironic/testserver/ironic.go
rename to pkg/ironic/testserver/ironic.go
diff --git a/pkg/provisioner/ironic/testserver/ironic_test.go b/pkg/ironic/testserver/ironic_test.go
similarity index 100%
rename from pkg/provisioner/ironic/testserver/ironic_test.go
rename to pkg/ironic/testserver/ironic_test.go
diff --git a/pkg/provisioner/ironic/testserver/server.go b/pkg/ironic/testserver/server.go
similarity index 100%
rename from pkg/provisioner/ironic/testserver/server.go
rename to pkg/ironic/testserver/server.go
diff --git a/pkg/provisioner/demo/demo.go b/pkg/provisioner/demo/demo.go
index d7e6e6e9..0a5ec0cc 100644
--- a/pkg/provisioner/demo/demo.go
+++ b/pkg/provisioner/demo/demo.go
@@ -3,13 +3,14 @@ package demo
 import (
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/go-logr/logr"
 	logz "sigs.k8s.io/controller-runtime/pkg/log/zap"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
 )
 
@@ -67,7 +68,7 @@ type demoProvisioner struct {
 
 type Demo struct{}
 
-// NewProvisioner returns a new demo Provisioner
+// New returns a new demo Provisioner
 func (d Demo) NewProvisioner(hostData provisioner.HostData, publisher provisioner.EventPublisher) (provisioner.Provisioner, error) {
 	p := &demoProvisioner{
 		objectMeta: hostData.ObjectMeta,
diff --git a/pkg/provisioner/fixture/fixture.go b/pkg/provisioner/fixture/fixture.go
index c6e09d25..ea14e16f 100644
--- a/pkg/provisioner/fixture/fixture.go
+++ b/pkg/provisioner/fixture/fixture.go
@@ -3,11 +3,12 @@ package fixture
 import (
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+
 	"github.com/go-logr/logr"
 	logz "sigs.k8s.io/controller-runtime/pkg/log/zap"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
 )
 
@@ -75,7 +76,7 @@ type Fixture struct {
 	customDeploy *metal3v1alpha1.CustomDeploy
 }
 
-// NewProvisioner returns a new Fixture Provisioner
+// New returns a new Fixture Provisioner
 func (f *Fixture) NewProvisioner(hostData provisioner.HostData, publisher provisioner.EventPublisher) (provisioner.Provisioner, error) {
 	p := &fixtureProvisioner{
 		provID:    hostData.ProvisionerID,
diff --git a/pkg/provisioner/ironic/factory.go b/pkg/provisioner/ironic/factory.go
index 5d3e10bf..f96d9869 100644
--- a/pkg/provisioner/ironic/factory.go
+++ b/pkg/provisioner/ironic/factory.go
@@ -11,8 +11,8 @@ import (
 	"github.com/gophercloud/gophercloud"
 	logz "sigs.k8s.io/controller-runtime/pkg/log/zap"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
 )
 
 type ironicProvisionerFactory struct {
diff --git a/pkg/provisioner/ironic/ironic.go b/pkg/provisioner/ironic/ironic.go
index 5b9140a2..f7e358b7 100644
--- a/pkg/provisioner/ironic/ironic.go
+++ b/pkg/provisioner/ironic/ironic.go
@@ -5,22 +5,24 @@ import (
 	"strings"
 	"time"
 
-	"github.com/go-logr/logr"
-	"github.com/pkg/errors"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/devicehints"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/hardwaredetails"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"github.com/go-logr/logr"
 	"github.com/gophercloud/gophercloud"
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports"
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
-
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"github.com/pkg/errors"
 	"sigs.k8s.io/yaml"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/devicehints"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/hardwaredetails"
 )
 
 var (
@@ -552,6 +554,14 @@ func (p *ironicProvisioner) PreprovisioningImageFormats() ([]metal3v1alpha1.Imag
 	var formats []metal3v1alpha1.ImageFormat
 	if accessDetails.SupportsISOPreprovisioningImage() {
 		formats = append(formats, metal3v1alpha1.ImageFormatISO)
+	} else {
+		if p.config.deployKernelURL != "" && p.config.deployRamdiskURL != "" {
+			// This is a PXE driver (no ISO support) so it shouldn't require any
+			// network customisation to boot the image, and we have sufficient
+			// data available to configure. Therefore, do not request an image
+			// build.
+			return nil, nil
+		}
 	}
 	if p.config.deployKernelURL != "" {
 		formats = append(formats, metal3v1alpha1.ImageFormatInitRD)
@@ -601,6 +611,8 @@ func setDeployImage(driverInfo map[string]interface{}, config ironicConfig, acce
 			deployImageInfo[deployISOKey] = config.deployISOURL
 			return deployImageInfo
 		}
+	}
+	if !config.havePreprovImgBuilder || !allowISO {
 		if allowInitRD && config.deployRamdiskURL != "" {
 			deployImageInfo[deployKernelKey] = config.deployKernelURL
 			deployImageInfo[deployRamdiskKey] = config.deployRamdiskURL
@@ -1137,7 +1149,7 @@ func (p *ironicProvisioner) ironicHasSameImage(ironicNode *nodes.Node, image met
 
 func (p *ironicProvisioner) buildManualCleaningSteps(bmcAccess bmc.AccessDetails, data provisioner.PrepareData) (cleanSteps []nodes.CleanStep, err error) {
 	// Build raid clean steps
-	raidCleanSteps, err := BuildRAIDCleanSteps(bmcAccess.RAIDInterface(), data.TargetRAIDConfig, data.ActualRAIDConfig)
+	raidCleanSteps, err := ironic.BuildRAIDCleanSteps(bmcAccess.RAIDInterface(), data.TargetRAIDConfig, data.ActualRAIDConfig)
 	if err != nil {
 		return nil, err
 	}
@@ -1149,7 +1161,7 @@ func (p *ironicProvisioner) buildManualCleaningSteps(bmcAccess bmc.AccessDetails
 		bmcConfig := bmc.FirmwareConfig(*data.FirmwareConfig)
 		firmwareConfig = &bmcConfig
 	}
-	bmcsettings, err := bmcAccess.BuildBIOSSettings(firmwareConfig)
+	fwConfigSettings, err := bmcAccess.BuildBIOSSettings(firmwareConfig)
 	if err != nil {
 		return nil, err
 	}
@@ -1158,13 +1170,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 _, bmcsetting := range bmcsettings {
-			if val, exists := data.ActualFirmwareSettings[bmcsetting["name"]]; exists {
-				if bmcsetting["value"] != val {
-					newSettings = buildFirmwareSettings(newSettings, bmcsetting["name"], bmcsetting["value"])
+		for _, fwConfigSetting := range fwConfigSettings {
+			if val, exists := data.ActualFirmwareSettings[fwConfigSetting["name"]]; exists {
+				if fwConfigSetting["value"] != val {
+					newSettings = buildFirmwareSettings(newSettings, fwConfigSetting["name"], fwConfigSetting["value"])
 				}
 			} else {
-				p.log.Info("name converted from bmc driver not found in firmware settings", "name", bmcsetting["name"], "node", p.nodeID)
+				p.log.Info("name converted from bmc driver not found in firmware settings", "name", fwConfigSetting["name"], "node", p.nodeID)
 			}
 		}
 
@@ -1172,14 +1184,20 @@ 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 _, bmcsetting := range bmcsettings {
-			newSettings = append(newSettings, bmcsetting)
+		for _, fwConfigSetting := range fwConfigSettings {
+			newSettings = append(newSettings, fwConfigSetting)
 		}
 	}
 
@@ -1815,7 +1833,7 @@ func ironicNodeName(objMeta metav1.ObjectMeta) string {
 func (p *ironicProvisioner) IsReady() (result bool, err error) {
 	p.debugLog.Info("verifying ironic provisioner dependencies")
 
-	checker := newIronicDependenciesChecker(p.client, p.inspector, p.log)
+	checker := ironic.NewIronicDependenciesChecker(p.client, p.inspector, p.log)
 	return checker.IsReady()
 }
 
diff --git a/pkg/provisioner/ironic/raid.go b/pkg/provisioner/ironic/raid.go
index f9d59edc..771061e5 100644
--- a/pkg/provisioner/ironic/raid.go
+++ b/pkg/provisioner/ironic/raid.go
@@ -1,25 +1,15 @@
 package ironic
 
 import (
-	"fmt"
-	"reflect"
-
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
-	"github.com/pkg/errors"
 
-	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/devicehints"
-)
-
-const (
-	noRAIDInterface       string = "no-raid"
-	softwareRAIDInterface string = "agent"
 )
 
 // setTargetRAIDCfg set the RAID settings to the ironic Node for RAID configuration steps
 func setTargetRAIDCfg(p *ironicProvisioner, raidInterface string, ironicNode *nodes.Node, data provisioner.PrepareData) (provisioner.Result, error) {
-	err := checkRAIDConfigure(raidInterface, data.TargetRAIDConfig)
+	err := ironic.CheckRAIDConfigure(raidInterface, data.TargetRAIDConfig)
 	if err != nil {
 		return operationFailed(err.Error())
 	}
@@ -27,7 +17,7 @@ func setTargetRAIDCfg(p *ironicProvisioner, raidInterface string, ironicNode *no
 	var logicalDisks []nodes.LogicalDisk
 
 	// Build target for RAID configuration steps
-	logicalDisks, err = BuildTargetRAIDCfg(data.TargetRAIDConfig)
+	logicalDisks, err = ironic.BuildTargetRAIDCfg(data.TargetRAIDConfig)
 	if err != nil {
 		return operationFailed(err.Error())
 	}
@@ -54,217 +44,3 @@ func setTargetRAIDCfg(p *ironicProvisioner, raidInterface string, ironicNode *no
 	}
 	return provisioner.Result{}, nil
 }
-
-// BuildTargetRAIDCfg build RAID logical disks, this method doesn't set the root volume
-func BuildTargetRAIDCfg(raid *metal3v1alpha1.RAIDConfig) (logicalDisks []nodes.LogicalDisk, err error) {
-	// Deal possible panic
-	defer func() {
-		r := recover()
-		if r != nil {
-			err = fmt.Errorf("panic in build RAID settings: %v", r)
-		}
-	}()
-
-	if raid == nil {
-		return
-	}
-
-	// build logicalDisks
-	if len(raid.HardwareRAIDVolumes) != 0 {
-		logicalDisks, err = buildTargetHardwareRAIDCfg(raid.HardwareRAIDVolumes)
-	} else if len(raid.SoftwareRAIDVolumes) != 0 {
-		logicalDisks, err = buildTargetSoftwareRAIDCfg(raid.SoftwareRAIDVolumes)
-	}
-
-	return
-}
-
-// A private method to build hardware RAID disks
-func buildTargetHardwareRAIDCfg(volumes []metal3v1alpha1.HardwareRAIDVolume) (logicalDisks []nodes.LogicalDisk, err error) {
-	var (
-		logicalDisk    nodes.LogicalDisk
-		nameCheckFlags = make(map[string]int)
-	)
-
-	if len(volumes) == 0 {
-		return
-	}
-
-	for index, volume := range volumes {
-		// Check volume's name
-		if volume.Name != "" {
-			i, exist := nameCheckFlags[volume.Name]
-			if exist {
-				return nil, errors.Errorf("the names(%s) of volume[%d] and volume[%d] are repeated", volume.Name, index, i)
-			}
-			nameCheckFlags[volume.Name] = index
-		}
-		// Build logicalDisk
-		logicalDisk = nodes.LogicalDisk{
-			SizeGB:     volume.SizeGibibytes,
-			RAIDLevel:  nodes.RAIDLevel(volume.Level),
-			VolumeName: volume.Name,
-		}
-		if volume.Rotational != nil {
-			if *volume.Rotational {
-				logicalDisk.DiskType = nodes.HDD
-			} else {
-				logicalDisk.DiskType = nodes.SSD
-			}
-		}
-		if volume.NumberOfPhysicalDisks != nil {
-			logicalDisk.NumberOfPhysicalDisks = *volume.NumberOfPhysicalDisks
-		}
-		// Add to logicalDisks
-		logicalDisks = append(logicalDisks, logicalDisk)
-	}
-
-	return
-}
-
-// A private method to build software RAID disks
-func buildTargetSoftwareRAIDCfg(volumes []metal3v1alpha1.SoftwareRAIDVolume) (logicalDisks []nodes.LogicalDisk, err error) {
-	var (
-		logicalDisk nodes.LogicalDisk
-	)
-
-	if len(volumes) == 0 {
-		return
-	}
-
-	if nodes.RAIDLevel(volumes[0].Level) != nodes.RAID1 {
-		return nil, errors.Errorf("the level in first volume of software raid must be RAID1")
-	}
-
-	for _, volume := range volumes {
-		// Build logicalDisk
-		logicalDisk = nodes.LogicalDisk{
-			SizeGB:     volume.SizeGibibytes,
-			RAIDLevel:  nodes.RAIDLevel(volume.Level),
-			Controller: "software",
-		}
-		// Build physical disks hint
-		for i := range volume.PhysicalDisks {
-			logicalDisk.PhysicalDisks = append(logicalDisk.PhysicalDisks, devicehints.MakeHintMap(&volume.PhysicalDisks[i]))
-		}
-		// Add to logicalDisks
-		logicalDisks = append(logicalDisks, logicalDisk)
-	}
-
-	return
-}
-
-// BuildRAIDCleanSteps build the clean steps for RAID configuration from BaremetalHost spec
-func BuildRAIDCleanSteps(raidInterface string, target *metal3v1alpha1.RAIDConfig, actual *metal3v1alpha1.RAIDConfig) (cleanSteps []nodes.CleanStep, err error) {
-	err = checkRAIDConfigure(raidInterface, target)
-	if err != nil {
-		return nil, err
-	}
-
-	// No RAID
-	if raidInterface == noRAIDInterface {
-		return
-	}
-
-	// Software RAID
-	if raidInterface == softwareRAIDInterface {
-		// Ignore HardwareRAIDVolumes
-		if target != nil {
-			target.HardwareRAIDVolumes = nil
-		}
-		if actual != nil {
-			actual.HardwareRAIDVolumes = nil
-		}
-		if reflect.DeepEqual(target, actual) {
-			return
-		}
-
-		cleanSteps = append(
-			cleanSteps,
-			[]nodes.CleanStep{
-				{
-					Interface: "raid",
-					Step:      "delete_configuration",
-				},
-				{
-					Interface: "deploy",
-					Step:      "erase_devices_metadata",
-				},
-			}...,
-		)
-
-		// If software raid configuration is empty, only need to clear old configuration
-		if target == nil || len(target.SoftwareRAIDVolumes) == 0 {
-			return
-		}
-
-		cleanSteps = append(
-			cleanSteps,
-			nodes.CleanStep{
-				Interface: "raid",
-				Step:      "create_configuration",
-			},
-		)
-		return
-	}
-
-	// Hardware RAID
-	// 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
-	}
-	if reflect.DeepEqual(target, actual) {
-		return
-	}
-
-	// Add ‘delete_configuration’ before ‘create_configuration’ to make sure
-	// that only the desired logical disks exist in the system after manual cleaning.
-	cleanSteps = append(
-		cleanSteps,
-		nodes.CleanStep{
-			Interface: "raid",
-			Step:      "delete_configuration",
-		},
-	)
-
-	// If hardware raid configuration is empty, only need to clear old configuration
-	if len(target.HardwareRAIDVolumes) == 0 {
-		return
-	}
-
-	// ‘create_configuration’ doesn’t remove existing disks. It is recommended
-	// that only the desired logical disks exist in the system after manual cleaning.
-	cleanSteps = append(
-		cleanSteps,
-		nodes.CleanStep{
-			Interface: "raid",
-			Step:      "create_configuration",
-		},
-	)
-	return
-}
-
-func checkRAIDConfigure(raidInterface string, raid *metal3v1alpha1.RAIDConfig) error {
-	switch raidInterface {
-	case noRAIDInterface:
-		if raid != nil && (len(raid.HardwareRAIDVolumes) != 0 || len(raid.SoftwareRAIDVolumes) != 0) {
-			return fmt.Errorf("raid settings are defined, but the node's driver %s does not support RAID", raidInterface)
-		}
-	case softwareRAIDInterface:
-		if raid != nil && len(raid.HardwareRAIDVolumes) != 0 {
-			return fmt.Errorf("node's driver %s does not support hardware RAID", raidInterface)
-		}
-	default:
-		if raid != nil && len(raid.HardwareRAIDVolumes) == 0 && len(raid.SoftwareRAIDVolumes) != 0 {
-			return fmt.Errorf("node's driver %s does not support software RAID", raidInterface)
-		}
-	}
-	return nil
-}
diff --git a/pkg/provisioner/provisioner.go b/pkg/provisioner/provisioner.go
index 4c6f402c..c7dc681f 100644
--- a/pkg/provisioner/provisioner.go
+++ b/pkg/provisioner/provisioner.go
@@ -4,11 +4,12 @@ import (
 	"errors"
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
 	"github.com/metal3-io/baremetal-operator/pkg/hardware"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 )
 
 /*
diff --git a/pkg/secretutils/secret_manager.go b/pkg/secretutils/secret_manager.go
index 05a039ef..b7a525ed 100644
--- a/pkg/secretutils/secret_manager.go
+++ b/pkg/secretutils/secret_manager.go
@@ -12,13 +12,6 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
-
-	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/utils"
-)
-
-const (
-	SecretsFinalizer = metal3v1alpha1.BareMetalHostFinalizer + "/secret"
 )
 
 // SecretManager is a type for fetching Secrets whether or not they are in the
@@ -65,7 +58,7 @@ func (sm *SecretManager) findSecret(key types.NamespacedName) (secret *corev1.Se
 // claimSecret ensures that the Secret has a label that will ensure it is
 // present in the cache (and that we can watch for changes), and optionally
 // that it has a particular owner reference.
-func (sm *SecretManager) claimSecret(secret *corev1.Secret, owner client.Object, ownerIsController, addFinalizer bool) error {
+func (sm *SecretManager) claimSecret(secret *corev1.Secret, owner client.Object, ownerIsController bool) error {
 	log := sm.log.WithValues("secret", secret.Name, "secretNamespace", secret.Namespace)
 	needsUpdate := false
 	if !metav1.HasLabel(secret.ObjectMeta, LabelEnvironmentName) {
@@ -105,12 +98,6 @@ func (sm *SecretManager) claimSecret(secret *corev1.Secret, owner client.Object,
 		}
 	}
 
-	if addFinalizer && !utils.StringInList(secret.Finalizers, SecretsFinalizer) {
-		log.Info("setting secret finalizer")
-		secret.Finalizers = append(secret.Finalizers, SecretsFinalizer)
-		needsUpdate = true
-	}
-
 	if needsUpdate {
 		if err := sm.client.Update(context.TODO(), secret); err != nil {
 			return errors.Wrap(err, fmt.Sprintf("failed to update secret %s in namespace %s", secret.ObjectMeta.Name, secret.ObjectMeta.Namespace))
@@ -124,12 +111,12 @@ func (sm *SecretManager) claimSecret(secret *corev1.Secret, owner client.Object,
 // will ensure it is present in the cache (and that we can watch for changes),
 // and optionally that it has a particular owner reference. The owner reference
 // may optionally be a controller reference.
-func (sm *SecretManager) obtainSecretForOwner(key types.NamespacedName, owner client.Object, ownerIsController, addFinalizer bool) (*corev1.Secret, error) {
+func (sm *SecretManager) obtainSecretForOwner(key types.NamespacedName, owner client.Object, ownerIsController bool) (*corev1.Secret, error) {
 	secret, err := sm.findSecret(key)
 	if err != nil {
 		return nil, errors.Wrap(err, fmt.Sprintf("failed to fetch secret %s in namespace %s", key.Name, key.Namespace))
 	}
-	err = sm.claimSecret(secret, owner, ownerIsController, addFinalizer)
+	err = sm.claimSecret(secret, owner, ownerIsController)
 
 	return secret, err
 }
@@ -138,37 +125,16 @@ func (sm *SecretManager) obtainSecretForOwner(key types.NamespacedName, owner cl
 // ensure it is present in the cache (and that we can watch for changes), and
 // that it has a particular owner reference. The owner reference may optionally
 // be a controller reference.
-func (sm *SecretManager) AcquireSecret(key types.NamespacedName, owner client.Object, ownerIsController, addFinalizer bool) (*corev1.Secret, error) {
+func (sm *SecretManager) AcquireSecret(key types.NamespacedName, owner client.Object, ownerIsController bool) (*corev1.Secret, error) {
 	if owner == nil {
 		panic("AcquireSecret called with no owner")
 	}
 
-	return sm.obtainSecretForOwner(key, owner, ownerIsController, addFinalizer)
+	return sm.obtainSecretForOwner(key, owner, ownerIsController)
 }
 
 // ObtainSecret retrieves a Secret and ensures that it has a label that will
 // ensure it is present in the cache (and that we can watch for changes).
 func (sm *SecretManager) ObtainSecret(key types.NamespacedName) (*corev1.Secret, error) {
-	return sm.obtainSecretForOwner(key, nil, false, false)
-}
-
-// ReleaseSecret removes secrets manager finalizer from specified secret when needed.
-func (sm *SecretManager) ReleaseSecret(secret *corev1.Secret) error {
-	if !utils.StringInList(secret.Finalizers, SecretsFinalizer) {
-		return nil
-	}
-
-	// Remove finalizer from secret to allow deletion
-	secret.Finalizers = utils.FilterStringFromList(
-		secret.Finalizers, SecretsFinalizer)
-
-	if err := sm.client.Update(context.Background(), secret); err != nil {
-		return errors.Wrap(err, fmt.Sprintf("failed to remove finalizer from secret %s in namespace %s",
-			secret.ObjectMeta.Name, secret.ObjectMeta.Namespace))
-	}
-
-	sm.log.Info("removed secret finalizer",
-		"remaining", secret.Finalizers)
-
-	return nil
+	return sm.obtainSecretForOwner(key, nil, false)
 }
diff --git a/tools/run_local_ironic.sh b/tools/run_local_ironic.sh
index a98ef86d..8e9e0ae7 100755
--- a/tools/run_local_ironic.sh
+++ b/tools/run_local_ironic.sh
@@ -203,13 +203,13 @@ fi
 # Start dnsmasq, http, mariadb, and ironic containers using same image
 
 # See this file for env vars you can set, like IP, DHCP_RANGE, INTERFACE
-# https://github.com/metal3-io/ironic-image/blob/master/scripts/rundnsmasq
+# https://github.com/metal3-io/ironic/blob/master/rundnsmasq.sh
 # shellcheck disable=SC2086
 sudo "${CONTAINER_RUNTIME}" run -d --net host --privileged --name dnsmasq \
      ${POD} --env-file "${IRONIC_DATA_DIR}/ironic-vars.env" \
      -v "$IRONIC_DATA_DIR:/shared" --entrypoint /bin/rundnsmasq "${IRONIC_IMAGE}"
 
-# https://github.com/metal3-io/ironic-image/blob/master/scripts/runmariadb
+# https://github.com/metal3-io/ironic/blob/master/runmariadb.sh
 # shellcheck disable=SC2086
 sudo "${CONTAINER_RUNTIME}" run -d --net host --privileged --name mariadb \
      ${POD} ${CERTS_MOUNTS} --env-file "${IRONIC_DATA_DIR}/ironic-vars.env" \
@@ -217,7 +217,7 @@ sudo "${CONTAINER_RUNTIME}" run -d --net host --privileged --name mariadb \
      --env "MARIADB_PASSWORD=$mariadb_password" "${IRONIC_IMAGE}"
 
 # See this file for additional env vars you may want to pass, like IP and INTERFACE
-# https://github.com/metal3-io/ironic-image/blob/master/scripts/runironic-api
+# https://github.com/metal3-io/ironic/blob/master/runironic-api.sh
 # shellcheck disable=SC2086
 sudo "${CONTAINER_RUNTIME}" run -d --net host --privileged --name ironic-api \
      ${POD} ${CERTS_MOUNTS} ${BASIC_AUTH_MOUNTS} ${IRONIC_HTPASSWD} \
@@ -227,7 +227,7 @@ sudo "${CONTAINER_RUNTIME}" run -d --net host --privileged --name ironic-api \
      -v "$IRONIC_DATA_DIR:/shared" "${IRONIC_IMAGE}"
 
 # See this file for additional env vars you may want to pass, like IP and INTERFACE
-# https://github.com/metal3-io/ironic-image/blob/master/scripts/runironic-conductor
+# https://github.com/metal3-io/ironic/blob/master/runironic-conductor.sh
 # shellcheck disable=SC2086
 sudo "${CONTAINER_RUNTIME}" run -d --net host --privileged --name ironic-conductor \
      ${POD} ${CERTS_MOUNTS} ${BASIC_AUTH_MOUNTS} ${IRONIC_HTPASSWD} \


Test patch:
diff --git a/controllers/metal3.io/baremetalhost_controller_test.go b/controllers/metal3.io/baremetalhost_controller_test.go
index f1021066..6aa07159 100644
--- a/controllers/metal3.io/baremetalhost_controller_test.go
+++ b/controllers/metal3.io/baremetalhost_controller_test.go
@@ -9,6 +9,8 @@ import (
 	"fmt"
 	"testing"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+
 	"github.com/stretchr/testify/assert"
 
 	corev1 "k8s.io/api/core/v1"
@@ -26,9 +28,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner/fixture"
-	"github.com/metal3-io/baremetal-operator/pkg/secretutils"
 	"github.com/metal3-io/baremetal-operator/pkg/utils"
 )
 
@@ -442,15 +442,11 @@ func TestAddFinalizers(t *testing.T) {
 
 	tryReconcile(t, r, host,
 		func(host *metal3v1alpha1.BareMetalHost, result reconcile.Result) bool {
-			t.Logf("host finalizers: %v", host.ObjectMeta.Finalizers)
-			if !utils.StringInList(host.ObjectMeta.Finalizers, metal3v1alpha1.BareMetalHostFinalizer) {
-				return false
+			t.Logf("finalizers: %v", host.ObjectMeta.Finalizers)
+			if utils.StringInList(host.ObjectMeta.Finalizers, metal3v1alpha1.BareMetalHostFinalizer) {
+				return true
 			}
-
-			hostSecret := getHostSecret(t, r, host)
-			t.Logf("BMC secret finalizers: %v", hostSecret.ObjectMeta.Finalizers)
-
-			return utils.StringInList(hostSecret.ObjectMeta.Finalizers, secretutils.SecretsFinalizer)
+			return false
 		},
 	)
 }
@@ -1380,7 +1376,7 @@ func TestDeleteHost(t *testing.T) {
 
 			tryReconcile(t, r, host,
 				func(host *metal3v1alpha1.BareMetalHost, result reconcile.Result) bool {
-					return fix.Deleted && host == nil && !utils.StringInList(badSecret.Finalizers, secretutils.SecretsFinalizer)
+					return fix.Deleted && host == nil
 				},
 			)
 		})
@@ -2125,15 +2121,13 @@ func TestGetPreprovImageCreateUpdate(t *testing.T) {
 func TestGetPreprovImage(t *testing.T) {
 	host := newDefaultHost(t)
 	imageURL := "http://example.test/image.iso"
-	acceptFormats := []metal3v1alpha1.ImageFormat{metal3v1alpha1.ImageFormatISO, metal3v1alpha1.ImageFormatInitRD}
 	image := &metal3v1alpha1.PreprovisioningImage{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      host.Name,
 			Namespace: namespace,
 		},
 		Spec: metal3v1alpha1.PreprovisioningImageSpec{
-			Architecture:  "x86_64",
-			AcceptFormats: acceptFormats,
+			Architecture: "x86_64",
 		},
 		Status: metal3v1alpha1.PreprovisioningImageStatus{
 			Architecture: "x86_64",
@@ -2154,7 +2148,7 @@ func TestGetPreprovImage(t *testing.T) {
 	r := newTestReconciler(host, image)
 	i := makeReconcileInfo(host)
 
-	imgData, err := r.getPreprovImage(i, acceptFormats)
+	imgData, err := r.getPreprovImage(i, []metal3v1alpha1.ImageFormat{metal3v1alpha1.ImageFormatISO})
 	assert.NoError(t, err)
 	assert.NotNil(t, imgData)
 	assert.Equal(t, imageURL, imgData.ImageURL)
@@ -2210,8 +2204,7 @@ func TestPreprovImageAvailable(t *testing.T) {
 		{
 			Scenario: "ready no netdata",
 			Spec: metal3v1alpha1.PreprovisioningImageSpec{
-				Architecture:  "x86_64",
-				AcceptFormats: []metal3v1alpha1.ImageFormat{"iso", "initrd"},
+				Architecture: "x86_64",
 			},
 			Status: metal3v1alpha1.PreprovisioningImageStatus{
 				Architecture: "x86_64",
@@ -2233,7 +2226,6 @@ func TestPreprovImageAvailable(t *testing.T) {
 			Scenario: "ready",
 			Spec: metal3v1alpha1.PreprovisioningImageSpec{
 				Architecture:    "x86_64",
-				AcceptFormats:   []metal3v1alpha1.ImageFormat{"iso", "initrd"},
 				NetworkDataName: "network_secret_1",
 			},
 			Status: metal3v1alpha1.PreprovisioningImageStatus{
@@ -2256,65 +2248,10 @@ func TestPreprovImageAvailable(t *testing.T) {
 			},
 			Available: true,
 		},
-		{
-			Scenario: "ready initrd",
-			Spec: metal3v1alpha1.PreprovisioningImageSpec{
-				Architecture:    "x86_64",
-				AcceptFormats:   []metal3v1alpha1.ImageFormat{"initrd"},
-				NetworkDataName: "network_secret_1",
-			},
-			Status: metal3v1alpha1.PreprovisioningImageStatus{
-				Architecture: "x86_64",
-				Format:       "initrd",
-				NetworkData: metal3v1alpha1.SecretStatus{
-					Name:    "network_secret_1",
-					Version: "1000",
-				},
-				Conditions: []metav1.Condition{
-					{
-						Type:   string(metal3v1alpha1.ConditionImageReady),
-						Status: metav1.ConditionTrue,
-					},
-					{
-						Type:   string(metal3v1alpha1.ConditionImageError),
-						Status: metav1.ConditionFalse,
-					},
-				},
-			},
-			Available: true,
-		},
-		{
-			Scenario: "ready initrd fallback",
-			Spec: metal3v1alpha1.PreprovisioningImageSpec{
-				Architecture:    "x86_64",
-				AcceptFormats:   []metal3v1alpha1.ImageFormat{"iso", "initrd"},
-				NetworkDataName: "network_secret_1",
-			},
-			Status: metal3v1alpha1.PreprovisioningImageStatus{
-				Architecture: "x86_64",
-				Format:       "initrd",
-				NetworkData: metal3v1alpha1.SecretStatus{
-					Name:    "network_secret_1",
-					Version: "1000",
-				},
-				Conditions: []metav1.Condition{
-					{
-						Type:   string(metal3v1alpha1.ConditionImageReady),
-						Status: metav1.ConditionTrue,
-					},
-					{
-						Type:   string(metal3v1alpha1.ConditionImageError),
-						Status: metav1.ConditionFalse,
-					},
-				},
-			},
-			Available: true,
-		},
 		{
 			Scenario: "ready secret outdated",
 			Spec: metal3v1alpha1.PreprovisioningImageSpec{
 				Architecture:    "x86_64",
-				AcceptFormats:   []metal3v1alpha1.ImageFormat{"iso", "initrd"},
 				NetworkDataName: "network_secret_1",
 			},
 			Status: metal3v1alpha1.PreprovisioningImageStatus{
@@ -2341,7 +2278,6 @@ func TestPreprovImageAvailable(t *testing.T) {
 			Scenario: "ready secret mismatch",
 			Spec: metal3v1alpha1.PreprovisioningImageSpec{
 				Architecture:    "x86_64",
-				AcceptFormats:   []metal3v1alpha1.ImageFormat{"iso", "initrd"},
 				NetworkDataName: "network_secret_1",
 			},
 			Status: metal3v1alpha1.PreprovisioningImageStatus{
@@ -2367,30 +2303,7 @@ func TestPreprovImageAvailable(t *testing.T) {
 		{
 			Scenario: "ready arch mismatch",
 			Spec: metal3v1alpha1.PreprovisioningImageSpec{
-				Architecture:  "aarch64",
-				AcceptFormats: []metal3v1alpha1.ImageFormat{"iso", "initrd"},
-			},
-			Status: metal3v1alpha1.PreprovisioningImageStatus{
-				Architecture: "x86_64",
-				Format:       "iso",
-				Conditions: []metav1.Condition{
-					{
-						Type:   string(metal3v1alpha1.ConditionImageReady),
-						Status: metav1.ConditionTrue,
-					},
-					{
-						Type:   string(metal3v1alpha1.ConditionImageError),
-						Status: metav1.ConditionFalse,
-					},
-				},
-			},
-			Available: false,
-		},
-		{
-			Scenario: "ready format mismatch",
-			Spec: metal3v1alpha1.PreprovisioningImageSpec{
-				Architecture:  "x86_64",
-				AcceptFormats: []metal3v1alpha1.ImageFormat{"initrd"},
+				Architecture: "aarch64",
 			},
 			Status: metal3v1alpha1.PreprovisioningImageStatus{
 				Architecture: "x86_64",
@@ -2411,8 +2324,7 @@ func TestPreprovImageAvailable(t *testing.T) {
 		{
 			Scenario: "not ready",
 			Spec: metal3v1alpha1.PreprovisioningImageSpec{
-				Architecture:  "x86_64",
-				AcceptFormats: []metal3v1alpha1.ImageFormat{"iso", "initrd"},
+				Architecture: "x86_64",
 			},
 			Status: metal3v1alpha1.PreprovisioningImageStatus{
 				Architecture: "x86_64",
@@ -2433,8 +2345,7 @@ func TestPreprovImageAvailable(t *testing.T) {
 		{
 			Scenario: "failed",
 			Spec: metal3v1alpha1.PreprovisioningImageSpec{
-				Architecture:  "x86_64",
-				AcceptFormats: []metal3v1alpha1.ImageFormat{"iso", "initrd"},
+				Architecture: "x86_64",
 			},
 			Status: metal3v1alpha1.PreprovisioningImageStatus{
 				Architecture: "x86_64",
diff --git a/controllers/metal3.io/host_state_machine_test.go b/controllers/metal3.io/host_state_machine_test.go
index 20e30f4f..8f3b5e8b 100644
--- a/controllers/metal3.io/host_state_machine_test.go
+++ b/controllers/metal3.io/host_state_machine_test.go
@@ -4,20 +4,21 @@ import (
 	"testing"
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
 
-	promutil "github.com/prometheus/client_golang/prometheus/testutil"
 	"github.com/stretchr/testify/assert"
-	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	ctrl "sigs.k8s.io/controller-runtime"
-	fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
-	logf "sigs.k8s.io/controller-runtime/pkg/log"
 
 	"github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
 	"github.com/metal3-io/baremetal-operator/pkg/hardware"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
+	promutil "github.com/prometheus/client_golang/prometheus/testutil"
+	corev1 "k8s.io/api/core/v1"
+	ctrl "sigs.k8s.io/controller-runtime"
+	fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
+	logf "sigs.k8s.io/controller-runtime/pkg/log"
 )
 
 func testStateMachine(host *metal3v1alpha1.BareMetalHost) *hostStateMachine {
diff --git a/controllers/metal3.io/hostfirmwaresettings_test.go b/controllers/metal3.io/hostfirmwaresettings_test.go
index 667cb3e7..9e99c956 100644
--- a/controllers/metal3.io/hostfirmwaresettings_test.go
+++ b/controllers/metal3.io/hostfirmwaresettings_test.go
@@ -21,16 +21,16 @@ import (
 const (
 	hostName      string = "myHostName"
 	hostNamespace string = "myHostNamespace"
-	schemaName    string = "schema-17e7ebad" // Hash generated from schema, change this if the schema is changed
+	schemaName    string = "schema-4bcc035f" // Hash generated from schema, change this if the schema is changed
 )
 
 var (
-	iTrue      = true
-	iFalse     = false
-	minLength  = 0
-	maxLength  = 20
-	lowerBound = 0
-	upperBound = 20
+	iTrue      bool = true
+	iFalse     bool = false
+	minLength  int  = 0
+	maxLength  int  = 20
+	lowerBound int  = 0
+	upperBound int  = 20
 )
 
 // Test support for HostFirmwareSettings in the HostFirmwareSettingsReconciler
@@ -67,10 +67,6 @@ 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
 }
@@ -133,7 +129,7 @@ func getSchema() *metal3v1alpha1.FirmwareSchema {
 				{
 					APIVersion: "metal3.io/v1alpha1",
 					Kind:       "HostFirmwareSettings",
-					Name:       hostName,
+					Name:       "dummyhfs",
 				},
 			},
 		},
@@ -214,8 +210,36 @@ func createBaremetalHost() *metal3v1alpha1.BareMetalHost {
 	return bmh
 }
 
-func getExpectedSchemaResource() *metal3v1alpha1.FirmwareSchema {
+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 {
 	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
@@ -295,7 +319,6 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						"SecureBoot":            "Enabled",
 					},
 					Conditions: []metav1.Condition{
-						{Type: "UpdateRequested", Status: "False", Reason: "Success"},
 						{Type: "Valid", Status: "True", Reason: "Success"},
 					},
 				},
@@ -335,7 +358,6 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						"SecureBoot":            "Enabled",
 					},
 					Conditions: []metav1.Condition{
-						{Type: "UpdateRequested", Status: "False", Reason: "Success"},
 						{Type: "Valid", Status: "True", Reason: "Success"},
 					},
 				},
@@ -356,6 +378,7 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 					Settings: metal3v1alpha1.DesiredSettingsMap{
 						"NetworkBootRetryCount": intstr.FromString("10"),
 						"ProcVirtualization":    intstr.FromString("Enabled"),
+						"AssetTag":              intstr.FromString("Z98765432"),
 					},
 				},
 				Status: metal3v1alpha1.HostFirmwareSettingsStatus{
@@ -364,6 +387,7 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						Namespace: hostNamespace,
 					},
 					Settings: metal3v1alpha1.SettingsMap{
+						"AssetTag":              "Z98765432",
 						"L2Cache":               "10x256 KB",
 						"NetworkBootRetryCount": "10",
 						"ProcVirtualization":    "Enabled",
@@ -376,6 +400,7 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 					Settings: metal3v1alpha1.DesiredSettingsMap{
 						"NetworkBootRetryCount": intstr.FromString("10"),
 						"ProcVirtualization":    intstr.FromString("Enabled"),
+						"AssetTag":              intstr.FromString("Z98765432"),
 					},
 				},
 				Status: metal3v1alpha1.HostFirmwareSettingsStatus{
@@ -391,7 +416,7 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						"SecureBoot":            "Enabled",
 					},
 					Conditions: []metav1.Condition{
-						{Type: "UpdateRequested", Status: "True", Reason: "Success"},
+						{Type: "ChangeDetected", Status: "True", Reason: "Success"},
 						{Type: "Valid", Status: "True", Reason: "Success"},
 					},
 				},
@@ -447,7 +472,7 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 						"SecureBoot":            "Enabled",
 					},
 					Conditions: []metav1.Condition{
-						{Type: "UpdateRequested", Status: "True", Reason: "Success"},
+						{Type: "ChangeDetected", Status: "True", Reason: "Success"},
 						{Type: "Valid", Status: "False", Reason: "ConfigurationError", Message: "Invalid BIOS setting"},
 					},
 				},
@@ -482,14 +507,17 @@ 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
 			}
 
-			err := r.updateHostFirmwareSettings(prov, info)
+			currentSettings, schema, err := prov.GetFirmwareSettings(true)
+			assert.Equal(t, nil, err)
+
+			err = r.updateHostFirmwareSettings(currentSettings, schema, info)
 			assert.Equal(t, nil, err)
 
 			// Check that resources get created or updated
@@ -501,11 +529,12 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 
 			// Use the same time for expected and actual
 			currentTime := metav1.Now()
-			for i := 0; i < 2; i++ {
+			tc.ExpectedSettings.Status.LastUpdated = &currentTime
+			actualSettings.Status.LastUpdated = &currentTime
+			for i := range tc.ExpectedSettings.Status.Conditions {
 				tc.ExpectedSettings.Status.Conditions[i].LastTransitionTime = currentTime
 				actualSettings.Status.Conditions[i].LastTransitionTime = currentTime
 			}
-
 			assert.Equal(t, tc.ExpectedSettings, actualSettings)
 
 			key = client.ObjectKey{
@@ -513,8 +542,12 @@ func TestStoreHostFirmwareSettings(t *testing.T) {
 			actualSchema := &metal3v1alpha1.FirmwareSchema{}
 			err = r.Client.Get(ctx, key, actualSchema)
 			assert.Equal(t, nil, err)
-			expectedSchema := getExpectedSchemaResource()
-			expectedSchema.ObjectMeta.ResourceVersion = "2"
+			var expectedSchema *metal3v1alpha1.FirmwareSchema
+			if tc.CreateSchemaResource {
+				expectedSchema = getExpectedSchemaTwoOwners()
+			} else {
+				expectedSchema = getExpectedSchema()
+			}
 			assert.Equal(t, expectedSchema, actualSchema)
 		})
 	}
@@ -605,7 +638,7 @@ func TestValidateHostFirmwareSettings(t *testing.T) {
 				hfs: hfs,
 			}
 
-			errors := r.validateHostFirmwareSettings(info, getExpectedSchemaResource())
+			errors := r.validateHostFirmwareSettings(info, getExpectedSchema())
 			if len(errors) == 0 {
 				assert.Equal(t, tc.ExpectedError, "")
 			} else {
diff --git a/pkg/hardwareutils/LICENSE b/pkg/ironic/LICENSE
similarity index 100%
rename from pkg/hardwareutils/LICENSE
rename to pkg/ironic/LICENSE
diff --git a/pkg/hardwareutils/bmc/access.go b/pkg/ironic/bmc/access.go
similarity index 100%
rename from pkg/hardwareutils/bmc/access.go
rename to pkg/ironic/bmc/access.go
diff --git a/pkg/hardwareutils/bmc/access_test.go b/pkg/ironic/bmc/access_test.go
similarity index 98%
rename from pkg/hardwareutils/bmc/access_test.go
rename to pkg/ironic/bmc/access_test.go
index 9dcd84e2..cc67f4f7 100644
--- a/pkg/hardwareutils/bmc/access_test.go
+++ b/pkg/ironic/bmc/access_test.go
@@ -476,7 +476,7 @@ func TestStaticDriverInfo(t *testing.T) {
 		{
 			Scenario:   "irmc",
 			input:      "irmc://192.168.122.1",
-			needsMac:   true,
+			needsMac:   false,
 			driver:     "irmc",
 			bios:       "",
 			boot:       "pxe",
@@ -636,18 +636,6 @@ func TestStaticDriverInfo(t *testing.T) {
 			raid:       "no-raid",
 		},
 
-		{
-			Scenario:   "ilo4 virtual media",
-			input:      "ilo4-virtualmedia://192.168.122.1",
-			needsMac:   true,
-			driver:     "ilo",
-			bios:       "",
-			boot:       "ilo-virtual-media",
-			management: "",
-			power:      "",
-			raid:       "no-raid",
-		},
-
 		{
 			Scenario:   "ilo5",
 			input:      "ilo5://192.168.122.1",
@@ -1083,17 +1071,6 @@ func TestDriverInfo(t *testing.T) {
 			},
 		},
 
-		{
-			Scenario: "ilo4 virtual media",
-			input:    "ilo4-virtualmedia://192.168.122.1",
-			expects: map[string]interface{}{
-				"ilo_address":   "192.168.122.1",
-				"ilo_password":  "",
-				"ilo_username":  "",
-				"ilo_verify_ca": false,
-			},
-		},
-
 		{
 			Scenario: "ilo5",
 			input:    "ilo5://192.168.122.1",
@@ -1170,8 +1147,8 @@ func TestUnknownType(t *testing.T) {
 }
 
 func TestBuildBIOSCleanSteps(t *testing.T) {
-	var True = true
-	var False = false
+	var True bool = true
+	var False bool = false
 
 	cases := []struct {
 		name          string
diff --git a/pkg/provisioner/ironic/raid_test.go b/pkg/ironic/raid_test.go
similarity index 98%
rename from pkg/provisioner/ironic/raid_test.go
rename to pkg/ironic/raid_test.go
index 0c48e8ad..6a2015dd 100644
--- a/pkg/provisioner/ironic/raid_test.go
+++ b/pkg/ironic/raid_test.go
@@ -10,8 +10,8 @@ import (
 )
 
 func TestBuildTargetRAIDCfg(t *testing.T) {
-	var TRUE = true
-	var FALSE = false
+	var TRUE bool = true
+	var FALSE bool = false
 	cases := []struct {
 		name          string
 		raid          *metal3v1alpha1.RAIDConfig
@@ -449,7 +449,7 @@ func TestCheckRAIDConfigure(t *testing.T) {
 
 	for _, c := range cases {
 		t.Run(c.raidInterface, func(t *testing.T) {
-			err := checkRAIDConfigure(c.raidInterface, c.RAID)
+			err := CheckRAIDConfigure(c.raidInterface, c.RAID)
 			if (err != nil) != c.expectedError {
 				t.Errorf("Got unexpected error: %v", err)
 			}
diff --git a/pkg/provisioner/ironic/testbmc/testbmc.go b/pkg/ironic/testbmc/testbmc.go
similarity index 98%
rename from pkg/provisioner/ironic/testbmc/testbmc.go
rename to pkg/ironic/testbmc/testbmc.go
index 50a900a1..996e510c 100644
--- a/pkg/provisioner/ironic/testbmc/testbmc.go
+++ b/pkg/ironic/testbmc/testbmc.go
@@ -3,7 +3,7 @@ package testbmc
 import (
 	"net/url"
 
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
 )
 
 func init() {
diff --git a/pkg/provisioner/ironic/adopt_test.go b/pkg/provisioner/ironic/adopt_test.go
index fbd8334f..28ee624d 100644
--- a/pkg/provisioner/ironic/adopt_test.go
+++ b/pkg/provisioner/ironic/adopt_test.go
@@ -4,14 +4,16 @@ import (
 	"testing"
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 )
 
 func TestAdopt(t *testing.T) {
diff --git a/pkg/provisioner/ironic/bios_test.go b/pkg/provisioner/ironic/bios_test.go
index a26f2aab..9e055066 100644
--- a/pkg/provisioner/ironic/bios_test.go
+++ b/pkg/provisioner/ironic/bios_test.go
@@ -6,9 +6,9 @@ import (
 	"github.com/stretchr/testify/assert"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
 )
 
 func TestGetFirmwareSettings(t *testing.T) {
diff --git a/pkg/provisioner/ironic/configdrive_test.go b/pkg/provisioner/ironic/configdrive_test.go
index c891bef2..27bffed3 100644
--- a/pkg/provisioner/ironic/configdrive_test.go
+++ b/pkg/provisioner/ironic/configdrive_test.go
@@ -3,16 +3,17 @@ package ironic
 import (
 	"testing"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 
 	"github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner/fixture"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 )
 
 func TestEmpty(t *testing.T) {
diff --git a/pkg/provisioner/ironic/delete_test.go b/pkg/provisioner/ironic/delete_test.go
index 1475bec9..8c4d21bf 100644
--- a/pkg/provisioner/ironic/delete_test.go
+++ b/pkg/provisioner/ironic/delete_test.go
@@ -5,13 +5,15 @@ import (
 	"testing"
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/stretchr/testify/assert"
 
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 )
 
 type TestFunc func(string)
diff --git a/pkg/provisioner/ironic/findhost_test.go b/pkg/provisioner/ironic/findhost_test.go
index fbdf1974..bc6e86e2 100644
--- a/pkg/provisioner/ironic/findhost_test.go
+++ b/pkg/provisioner/ironic/findhost_test.go
@@ -3,11 +3,11 @@ package ironic
 import (
 	"testing"
 
-	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
 
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
+	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 )
 
 func TestFindExistingHost(t *testing.T) {
diff --git a/pkg/provisioner/ironic/inspecthardware_test.go b/pkg/provisioner/ironic/inspecthardware_test.go
index fd5a44a7..0fc5cd47 100644
--- a/pkg/provisioner/ironic/inspecthardware_test.go
+++ b/pkg/provisioner/ironic/inspecthardware_test.go
@@ -5,15 +5,17 @@ import (
 	"testing"
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
+	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
+
+	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
-
-	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 )
 
 func TestInspectHardware(t *testing.T) {
diff --git a/pkg/provisioner/ironic/ironic_test.go b/pkg/provisioner/ironic/ironic_test.go
index d51c8f34..78a7eff5 100644
--- a/pkg/provisioner/ironic/ironic_test.go
+++ b/pkg/provisioner/ironic/ironic_test.go
@@ -3,20 +3,21 @@ package ironic
 import (
 	"testing"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+
 	"github.com/stretchr/testify/assert"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 	logz "sigs.k8s.io/controller-runtime/pkg/log/zap"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
 
 	// We don't use this package directly here, but need it imported
 	// so it registers its test fixture with the other BMC access
 	// types.
-	_ "github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testbmc"
+	_ "github.com/metal3-io/baremetal-operator/pkg/ironic/testbmc"
 )
 
 func init() {
diff --git a/pkg/provisioner/ironic/power_test.go b/pkg/provisioner/ironic/power_test.go
index 41ee6c74..04708949 100644
--- a/pkg/provisioner/ironic/power_test.go
+++ b/pkg/provisioner/ironic/power_test.go
@@ -6,14 +6,15 @@ import (
 	"testing"
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 )
 
 func TestPowerOn(t *testing.T) {
diff --git a/pkg/provisioner/ironic/prepare_test.go b/pkg/provisioner/ironic/prepare_test.go
index 22573288..88b9074d 100644
--- a/pkg/provisioner/ironic/prepare_test.go
+++ b/pkg/provisioner/ironic/prepare_test.go
@@ -5,15 +5,16 @@ import (
 	"testing"
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 )
 
 type RAIDTestBMC struct{}
diff --git a/pkg/provisioner/ironic/provision_test.go b/pkg/provisioner/ironic/provision_test.go
index 725941e4..20c8a97c 100644
--- a/pkg/provisioner/ironic/provision_test.go
+++ b/pkg/provisioner/ironic/provision_test.go
@@ -5,20 +5,22 @@ import (
 	"testing"
 	"time"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection"
 	"github.com/stretchr/testify/assert"
-	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testbmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner/fixture"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testbmc"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 
-	_ "github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
+	"k8s.io/apimachinery/pkg/util/intstr"
+
+	_ "github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
 )
 
 func TestProvision(t *testing.T) {
@@ -400,8 +402,8 @@ func TestIronicHasSameImage(t *testing.T) {
 
 func TestBuildCleanSteps(t *testing.T) {
 
-	var True = true
-	var False = false
+	var True bool = true
+	var False bool = false
 
 	nodeUUID := "33ce8659-7400-4c68-9535-d10766f07a58"
 	cases := []struct {
diff --git a/pkg/provisioner/ironic/provisioncapacity_test.go b/pkg/provisioner/ironic/provisioncapacity_test.go
index 9293bbd9..0d120b0c 100644
--- a/pkg/provisioner/ironic/provisioncapacity_test.go
+++ b/pkg/provisioner/ironic/provisioncapacity_test.go
@@ -4,12 +4,12 @@ import (
 	"fmt"
 	"testing"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/stretchr/testify/assert"
-
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 )
 
 func TestHasCapacity(t *testing.T) {
diff --git a/pkg/provisioner/ironic/ready_test.go b/pkg/provisioner/ironic/ready_test.go
index 69782661..cca488c4 100644
--- a/pkg/provisioner/ironic/ready_test.go
+++ b/pkg/provisioner/ironic/ready_test.go
@@ -4,11 +4,11 @@ import (
 	"net/http"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
 
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
+	"github.com/stretchr/testify/assert"
 )
 
 func TestProvisionerIsReady(t *testing.T) {
diff --git a/pkg/provisioner/ironic/updatehardwarestate_test.go b/pkg/provisioner/ironic/updatehardwarestate_test.go
index f2df0bc5..90fd4ecf 100644
--- a/pkg/provisioner/ironic/updatehardwarestate_test.go
+++ b/pkg/provisioner/ironic/updatehardwarestate_test.go
@@ -4,12 +4,12 @@ import (
 	"net/http"
 	"testing"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/stretchr/testify/assert"
-
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 )
 
 func TestUpdateHardwareState(t *testing.T) {
diff --git a/pkg/provisioner/ironic/updateopts_test.go b/pkg/provisioner/ironic/updateopts_test.go
index 8ca5db4c..6dae99f9 100644
--- a/pkg/provisioner/ironic/updateopts_test.go
+++ b/pkg/provisioner/ironic/updateopts_test.go
@@ -4,19 +4,19 @@ import (
 	"fmt"
 	"testing"
 
-	"github.com/pkg/errors"
-	"github.com/stretchr/testify/assert"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
 
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
+	"github.com/pkg/errors"
+	"github.com/stretchr/testify/assert"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
 	"github.com/metal3-io/baremetal-operator/pkg/hardware"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
 )
 
 func TestOptionValueEqual(t *testing.T) {
diff --git a/pkg/provisioner/ironic/validatemanagementaccess_test.go b/pkg/provisioner/ironic/validatemanagementaccess_test.go
index c82beea2..21c96e09 100644
--- a/pkg/provisioner/ironic/validatemanagementaccess_test.go
+++ b/pkg/provisioner/ironic/validatemanagementaccess_test.go
@@ -4,15 +4,16 @@ import (
 	"net/http"
 	"testing"
 
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/bmc"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/clients"
+	"github.com/metal3-io/baremetal-operator/pkg/ironic/testserver"
+
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
 	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports"
 	"github.com/stretchr/testify/assert"
 
 	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/clients"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/testserver"
 )
 
 func TestValidateManagementAccessNoMAC(t *testing.T) {
@@ -826,7 +827,7 @@ func TestPreprovisioningImageFormats(t *testing.T) {
 			Name:              "enabled ipmi",
 			Address:           "ipmi://example.test",
 			PreprovImgEnabled: true,
-			Expected:          []metal3v1alpha1.ImageFormat{"initrd"},
+			Expected:          nil,
 		},
 		{
 			Name:              "enabled virtualmedia",
@@ -977,7 +978,7 @@ func TestSetDeployImage(t *testing.T) {
 			},
 			ExpectBuild: false,
 			ExpectISO:   false,
-			ExpectPXE:   false,
+			ExpectPXE:   true,
 		},
 		{
 			Scenario: "pxe build no kernel",
diff --git a/pkg/utils/stringlist_test.go b/pkg/utils/stringlist_test.go
deleted file mode 100644
index 7f2a335c..00000000
--- a/pkg/utils/stringlist_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package utils
-
-import (
-	"reflect"
-	"testing"
-)
-
-func TestStringInList(t *testing.T) {
-	cases := []struct {
-		list   []string
-		str    string
-		expect bool
-	}{
-		{
-			list:   []string{"a", "b", "c"},
-			str:    "a",
-			expect: true,
-		},
-		{
-			list:   []string{"a", "b", "c"},
-			str:    "d",
-			expect: false,
-		},
-	}
-
-	for _, c := range cases {
-		got := StringInList(c.list, c.str)
-		if c.expect != got {
-			t.Errorf("Expected '%t', but got '%t'", c.expect, got)
-		}
-
-	}
-}
-
-func TestFilterStringFromList(t *testing.T) {
-	cases := []struct {
-		list      []string
-		str       string
-		expectStr []string
-	}{
-		{
-			list:      []string{"a", "b", "c"},
-			str:       "a",
-			expectStr: []string{"b", "c"},
-		},
-		{
-			list:      []string{"a", "b", "c"},
-			str:       "d",
-			expectStr: []string{"a", "b", "c"},
-		},
-	}
-
-	for _, c := range cases {
-		newList := FilterStringFromList(c.list, c.str)
-		if !reflect.DeepEqual(newList, c.expectStr) {
-			t.Errorf("Expected '%s', but got '%s'", c.expectStr, newList)
-		}
-
-	}
-}