Repository: metal3-io/baremetal-operator
Pull request #543 (2020-06-01 13:39:57)

initialize reviewers list
Add reviewers who are not already in the approvers list based on the
policy described in https://github.com/metal3-io/metal3-docs/pull/93

/hold

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/543#" title="Author self-approved">dhellmann</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)~~ [dhellmann]

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":[]} -->
metal3-io-bot: The following users are mentioned in OWNERS file(s) but are not members of the metal3-io org.

Once all users have been added as [members]() of the org, you can trigger verification by writing `/verify-owners` in a comment.
- dukov
  - OWNERS

Patch:
diff --git a/OWNERS b/OWNERS
index 7da2f7e7..b2574b7c 100644
--- a/OWNERS
+++ b/OWNERS
@@ -7,3 +7,6 @@ approvers:
  - russellb
  - stbenjam
  - zaneb
+
+reviewers:
+ - honza
\ No newline at end of file
diff --git a/cmd/get-hardware-details/main.go b/cmd/get-hardware-details/main.go
index 066adebb..5a80be57 100644
--- a/cmd/get-hardware-details/main.go
+++ b/cmd/get-hardware-details/main.go
@@ -23,7 +23,7 @@ func main() {
 			IronicInspectorEndpoint: os.Args[1],
 		})
 	if err != nil {
-		fmt.Printf("could not get inspector client: %s", err)
+		fmt.Printf("could not get inpsector client: %s", err)
 		os.Exit(1)
 	}
 
diff --git a/deploy/crds/metal3.io_baremetalhosts_crd.yaml b/deploy/crds/metal3.io_baremetalhosts_crd.yaml
index 8f1ba483..adef06cc 100644
--- a/deploy/crds/metal3.io_baremetalhosts_crd.yaml
+++ b/deploy/crds/metal3.io_baremetalhosts_crd.yaml
@@ -203,51 +203,6 @@ spec:
             online:
               description: Should the server be online?
               type: boolean
-            rootDeviceHints:
-              description: Provide guidance about how to choose the device for the
-                image being provisioned.
-              properties:
-                deviceName:
-                  description: A Linux device name like "/dev/vda". The hint must
-                    match the actual value exactly.
-                  type: string
-                hctl:
-                  description: A SCSI bus address like 0:0:0:0. The hint must match
-                    the actual value exactly.
-                  type: string
-                minSizeGigabytes:
-                  description: The minimum size of the device in Gigabytes.
-                  minimum: 0
-                  type: integer
-                model:
-                  description: A vendor-specific device identifier. The hint can be
-                    a substring of the actual value.
-                  type: string
-                rotational:
-                  description: True if the device should use spinning media, false
-                    otherwise.
-                  type: boolean
-                serialNumber:
-                  description: Device serial number. The hint must match the actual
-                    value exactly.
-                  type: string
-                vendor:
-                  description: The name of the vendor or manufacturer of the device.
-                    The hint can be a substring of the actual value.
-                  type: string
-                wwn:
-                  description: Unique storage identifier. The hint must match the
-                    actual value exactly.
-                  type: string
-                wwnVendorExtension:
-                  description: Unique vendor storage identifier. The hint must match
-                    the actual value exactly.
-                  type: string
-                wwnWithExtension:
-                  description: Unique storage identifier with the vendor extension
-                    appended. The hint must match the actual value exactly.
-                  type: string
-              type: object
             taints:
               description: Taints is the full, authoritative list of taints to apply
                 to the corresponding Machine. This list will overwrite any modifications
@@ -617,50 +572,6 @@ spec:
                   - checksum
                   - url
                   type: object
-                rootDeviceHints:
-                  description: The RootDevicehints set by the user
-                  properties:
-                    deviceName:
-                      description: A Linux device name like "/dev/vda". The hint must
-                        match the actual value exactly.
-                      type: string
-                    hctl:
-                      description: A SCSI bus address like 0:0:0:0. The hint must
-                        match the actual value exactly.
-                      type: string
-                    minSizeGigabytes:
-                      description: The minimum size of the device in Gigabytes.
-                      minimum: 0
-                      type: integer
-                    model:
-                      description: A vendor-specific device identifier. The hint can
-                        be a substring of the actual value.
-                      type: string
-                    rotational:
-                      description: True if the device should use spinning media, false
-                        otherwise.
-                      type: boolean
-                    serialNumber:
-                      description: Device serial number. The hint must match the actual
-                        value exactly.
-                      type: string
-                    vendor:
-                      description: The name of the vendor or manufacturer of the device.
-                        The hint can be a substring of the actual value.
-                      type: string
-                    wwn:
-                      description: Unique storage identifier. The hint must match
-                        the actual value exactly.
-                      type: string
-                    wwnVendorExtension:
-                      description: Unique vendor storage identifier. The hint must
-                        match the actual value exactly.
-                      type: string
-                    wwnWithExtension:
-                      description: Unique storage identifier with the vendor extension
-                        appended. The hint must match the actual value exactly.
-                      type: string
-                  type: object
                 state:
                   description: An indiciator for what the provisioner is doing with
                     the host.
diff --git a/deploy/default/kustomization.yaml b/deploy/default/kustomization.yaml
index 60c8d18f..b1248090 100644
--- a/deploy/default/kustomization.yaml
+++ b/deploy/default/kustomization.yaml
@@ -5,12 +5,13 @@ resources:
 - ../namespace
 - ../rbac
 - ../crds
-- ../operator
+- ../operator/ironic
 configMapGenerator:
-- behavior: merge
-  envs:
+- envs:
   - ironic_bmo_configmap.env
   name: ironic-bmo-configmap
-
-configurations:
-- kustomizeconfig.yaml
+secretGenerator:
+- literals:
+  - password=changeme
+  name: mariadb-password
+  type: Opaque
diff --git a/deploy/default/kustomizeconfig.yaml b/deploy/default/kustomizeconfig.yaml
deleted file mode 100644
index 6996507a..00000000
--- a/deploy/default/kustomizeconfig.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-# the following config is for teaching kustomize where to look at when substituting vars.
-# It requires kustomize v2.1.0 or newer to work properly.
-namespace:
-- kind: ClusterRoleBinding
-  group: rbac.authorization.k8s.io
-  path: subjects/namespace
-  create: false
diff --git a/deploy/operator/bmo.yaml b/deploy/operator/bmo.yaml
deleted file mode 100644
index e96c4a1c..00000000
--- a/deploy/operator/bmo.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: metal3-baremetal-operator
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      name: metal3-baremetal-operator
-  template:
-    metadata:
-      labels:
-        name: metal3-baremetal-operator
-    spec:
-      serviceAccountName: metal3-baremetal-operator
-      containers:
-        - name: baremetal-operator
-          image: quay.io/metal3-io/baremetal-operator
-          ports:
-          - containerPort: 60000
-            name: metrics
-          command:
-          - /baremetal-operator
-          imagePullPolicy: Always
-          env:
-            - name: POD_NAME
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.name
-          envFrom:
-            - configMapRef:
-                name: ironic-bmo-configmap
\ No newline at end of file
diff --git a/deploy/operator/kustomization.yaml b/deploy/operator/kustomization.yaml
deleted file mode 100644
index d7bb8f78..00000000
--- a/deploy/operator/kustomization.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-apiVersion: kustomize.config.k8s.io/v1beta1
-kind: Kustomization
-resources:
-- bmo.yaml
\ No newline at end of file
diff --git a/docs/api.md b/docs/api.md
index 47394d8e..c6663995 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -19,15 +19,6 @@ sure that you remove the annotation  **only if the value of the annotation is
 not `metal3.io/capm3`, but another value that you have provided**. Removing the
 annotation will enable the reconciliation again.
 
-### Unhealthy annotation
-
-It is possible to mark BareMetalHost object as unhealthy by adding an
-annotation `baremetalhost.metal3.io/unhealthy`. This annotation does not
-stop the reconciliation of the BMH. This annotation is used in the upper layers
-for coordination. For example **Metal³** provider should not provision BMH
-set as unhealthy. Removing the annotation will enable the normal operations
-on the provider layers.
-
 ### BareMetalHost spec
 
 The *BareMetalHost's* *spec* defines the desire state of the host. It contains
@@ -48,8 +39,6 @@ mainly, but not only, provisioning details.
         for attaching the provisioning image to the host.
     * Fujitsu iRMC
       * `irmc://<host>:<port>`, where `<port>` is optional if using the default.
-    * HUAWEI ibmc
-      * `ibmc://<host>:<port>` (or `ibmc+http://<host>:<port>` to disable TLS)
     * Redfish
       * `redfish://` (or `redfish+http://` to disable TLS)
       * `redfish-virtualmedia://` to use virtual media instead of PXE
@@ -101,50 +90,6 @@ mainly, but not only, provisioning details.
 
 * *description* -- A human-provided string to help identify the host.
 
-* *hardwareProfile* -- **This field is deprecated. See rootDeviceHints instead.**
-  The name of the hardware profile to use. The following are the current
-  supported `hardwareProfile` settings and their corresponding root devices.
-
-  | **hardwareProfile** | **Root Device** |
-  |---------------------|-----------------|
-  | `unknown`           | /dev/sda        |
-  | `libvirt`           | /dev/vda        |
-  | `dell`              | HCTL: 0:0:0:0   |
-  | `dell-raid`         | HCTL: 0:2:0:0   |
-  | `openstack`         | /dev/vdb        |
-
-  **NOTE:** These are subject to change.
-
-* *rootDeviceHints* -- Guidance for how to choose the device to
-  receive the image being provisioned. The storage devices are
-  examined in the order they are discovered during inspection and the
-  hint values are compared to the inspected values. The first
-  discovered device that matches is used. Hints can be combined, and
-  if multiple hints are provided then a device must match all hints in
-  order to be selected.
-  * *deviceName* -- A string containing a Linux device name like
-    `/dev/vda`. The hint must match the actual value exactly.
-  * *hctl* -- A string containing a SCSI bus address like
-    `0:0:0:0`. The hint must match the actual value exactly.
-  * *model* -- A string containing a vendor-specific device
-    identifier. The hint can be a substring of the actual value.
-  * *vendor* -- A string containing the name of the vendor or
-    manufacturer of the device. The hint can be a substring of the
-    actual value.
-  * *serialNumber* -- A string contianing the device serial
-    number. The hint must match the actual value exactly.
-  * *minSizeGigabytes* -- An integer representing the minimum size of the
-    device in Gigabytes.
-  * *wwn* -- A string containing the unique storage identifier. The
-    hint must match the actual value exactly.
-  * *wwnWithExtension* -- A string containing the unique storage
-    identifier with the vendor extension appended. The hint must match
-    the actual value exactly.
-  * *wwnVendorExtension* -- A string containing the unique vendor
-    storage indentifier. The hint must match the actual value exactly.
-  * *rotational* -- A boolean indicating whether the device should be
-    a rotating disk (`true`) or not (`false`).
-
 ### BareMetalHost status
 
 Moving onto the next block, the *BareMetalHost's* *status* which represents
@@ -208,10 +153,8 @@ details, etc.
   * *systemVendor* -- Contains information about the host's *manufacturer*,
     the *productName* and *serialNumber*.
   * *ramMebibytes* -- The host's amount of memory in Mebibytes.
-
-* *hardwareProfile* -- **This field is deprecated. See rootDeviceHints instead.**
-  The name of the hardware profile that matches the
-  hardware discovered on the host based on the details saved
+* *hardwareProfile* -- The name of the hardware profile that matches the
+  hardware discovered on the host. These details are saved
   to the *Hardware* section. If the hardware does not match any
   known profile, the value `unknown` will be set on this field
   and is used by default. In practice, this only affects which device
@@ -230,7 +173,6 @@ details, etc.
 
 * *poweredOn* -- Boolean indicating whether the host is powered on.
   See *online* on the *BareMetalHost's* *Spec*.
-
 * *provisioning* -- Settings related to deploying an image to the host.
   * *state* -- The current state of any ongoing provisioning operation.
     The following are the currently supported ones:
@@ -251,11 +193,6 @@ details, etc.
       by an agent.
     * *power management error* -- An error was found while trying to power
       the host either on or off.
-  * *id* -- The unique identifier for the service in the underlying
-    provisioning tool.
-  * *image* -- The image most recently provisioned to the host.
-  * *rootDeviceHints* -- The root device selection instructions used
-    for the most recent provisioning operation.
 
 ### BareMetalHost Example
 
diff --git a/docs/configuration.md b/docs/configuration.md
index 9bb8653e..0867b202 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -25,9 +25,9 @@ Kustomization Configuration
 It is possible to deploy ```baremetal-operator``` with three different operator
 configurations, namely:
 
-1. operator with ironic
-2. operator without ironic
-3. ironic without operator
+1. operator without ironic
+2. operator with ironic
+3. operator with ironic and keepalived
 
-A detailed overview of the configuration is presented in [Bare Metal Operator
-and Ironic Configuration](deploying.md).
+A detailed overview of the Kustomization configuration is presented in [Ironic
+Keepalived Configuration](ironic-endpoint-keepalived-configuration.md)
diff --git a/docs/deploying.md b/docs/deploying.md
deleted file mode 100644
index b630481f..00000000
--- a/docs/deploying.md
+++ /dev/null
@@ -1,123 +0,0 @@
-# Running Bare Metal Operator with/without Ironic
-
-This document explains the deployment scenarios of deploying Bare Metal
-Operator(BMO) with/without Ironic.
-
-**These are the deployment use cases in this document:**
-
-1. Deploying baremetal operator with Ironic.
-
-2. Deploying baremetal operator without Ironic.
-
-3. Deploying only Ironic.
-
-## Current structure of baremetal-operator deployment directory
-
-```diff
-tree deploy/
-deploy/
-├── crds
-│   ├── kustomization.yaml
-│   └── metal3.io_baremetalhosts_crd.yaml
-├── default
-│   ├── ironic_bmo_configmap.env
-│   └── kustomization.yaml
-├── ironic_ci.env
-├── namespace
-│   ├── kustomization.yaml
-│   └── namespace.yaml
-├── operator
-│   ├── bmo.yaml
-│   └── kustomization.yaml
-├── rbac
-│   ├── kustomization.yaml
-│   ├── role_binding.yaml
-│   ├── role.yaml
-│   └── service_account.yaml
-└── role.yaml -> rbac/role.yaml
-```
-
-The `deploy` directory has one top level folder for deployment,
-namely `default` and it deploys only baremetal operator through kustomization.
-In addition, `crds`, `namespace` and `rbac` folders have their own kustomization
-and yaml files.
-
-## Current structure of ironic-deployment directory
-
-```diff
-tree ironic-deployment/
-ironic-deployment/
-├── default
-│   ├── ironic_bmo_configmap.env
-│   └── kustomization.yaml
-├── ironic
-│   ├── ironic.yaml
-│   └── kustomization.yaml
-└── keepalived
-    ├── ironic_bmo_configmap.env
-    ├── keepalived_patch.yaml
-    └── kustomization.yaml
-```
-
-ironic-deployment folder has three top level folder for deployments,
-namely `default`,  `ironic` and `keepalived`. `default` and `ironic` deploy
-only ironic, `keepalived` deploys the ironic with keepalived. As the name
-implies, `keepalived/keepalived_patch.yaml` patches the default image URL
-through kustomization.
-The user should run following commands to be able to meet requirements of each
-use case as provided below:
-
-### Commands to deploy baremetal operator with Ironic
-
-```diff
-kustomize build $BMOPATH/deploy/default | kubectl apply -f-
-kustomize build $BMOPATH/ironic-deployment/default | kubectl apply -f-
-```
-
-### Command to deploy baremetal operator without Ironic
-
-```diff
-kustomize build $BMOPATH/deploy/default | kubectl apply -f-
-```
-
-### Command to deploy only Ironic
-
-```diff
-kustomize build $BMOPATH/ironic-deployment/default | kubectl apply -f-
-```
-
-where $BMOPATH points to the baremetal-operator path.
-
-#### Useful tips
-
-It is worth mentioning some tips for when the different configurations are
-useful as well. For example:
-
-1. Only BMO is deployed, in  a case when Ironic is already running, e.g. as part
-   of Cluster API Provider Metal3
-   [(CAPM3)](https://github.com/metal3-io/cluster-api-provider-metal3) when
-   a successful pivoting state was met and ironic being deployed.
-
-2. BMO and Ironic are deployed together, in a case when CAPM3 is not used and
-   those to be deployed as a bundle.
-
-3. Only Ironic is deployed, in a case when BMO is deployed as part of CAPM3 and
-   only Ironic setup is sufficient, e.g.
-   [clusterctl](https://cluster-api.sigs.k8s.io/clusterctl/commands/move.html)
-   provided by Cluster API(CAPI) deploys BMO, so that it can take care of moving
-   the BaremetalHost during the pivoting.
-
-**Important Note**
-When the baremetal-operator is deployed through metal3-dev-env, this container
-inherits the following environment variables through configmap:
-
-```ini
-
-$PROVISIONING_IP
-$PROVISIONING_CIDR
-$PROVISIONING_INTERFACE
-
-```
-
-In case you are deploying baremetak-operator locally, make sure to populate and
-export these environment variables before deploying.
diff --git a/docs/dev-setup.md b/docs/dev-setup.md
index 3767476a..a18003a3 100644
--- a/docs/dev-setup.md
+++ b/docs/dev-setup.md
@@ -2,8 +2,9 @@
 
 ## Install the operator-sdk
 
-Follow the instructions on the [Operator SDK website](https://sdk.operatorframework.io/docs/install-operator-sdk/)
-to check out and install the operator-sdk tools.
+Follow the instructions in the Quick Start section of
+<https://github.com/operator-framework/operator-sdk> to check out and
+install the operator-sdk tools.
 
 ## Install openapi-gen
 
@@ -47,7 +48,7 @@ go get k8s.io/kube-openapi/cmd/openapi-gen
     export DEPLOY_RAMDISK_URL=http://172.22.0.1/images/ironic-python-agent.initramfs
     export IRONIC_ENDPOINT=http://localhost:6385/v1/
     export IRONIC_INSPECTOR_ENDPOINT=http://localhost:5050/v1
-    operator-sdk run --local --watch-namespace=metal3
+    operator-sdk up local --namespace=metal3
     ```
 
 1. Create the CR
diff --git a/go.mod b/go.mod
index d404ca1a..f5dea03e 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,6 @@ require (
 	github.com/prometheus/client_golang v1.5.1
 	github.com/securego/gosec v0.0.0-20200401082031-e946c8c39989 // indirect
 	github.com/spf13/cobra v0.0.6 // indirect
-	github.com/stretchr/testify v1.4.0
 	golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 // indirect
 	golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
 	golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
@@ -29,6 +28,7 @@ require (
 	k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab
 	sigs.k8s.io/controller-runtime v0.5.2
 	sigs.k8s.io/yaml v1.2.0
+
 )
 
 replace (
diff --git a/ironic-deployment/default/ironic_bmo_configmap.env b/ironic-deployment/default/ironic_bmo_configmap.env
deleted file mode 100644
index 938b3ee3..00000000
--- a/ironic-deployment/default/ironic_bmo_configmap.env
+++ /dev/null
@@ -1,9 +0,0 @@
-HTTP_PORT=6180
-PROVISIONING_INTERFACE=eth2
-DHCP_RANGE=172.22.0.10,172.22.0.100
-DEPLOY_KERNEL_URL=http://172.22.0.2:6180/images/ironic-python-agent.kernel
-DEPLOY_RAMDISK_URL=http://172.22.0.2:6180/images/ironic-python-agent.initramfs
-IRONIC_ENDPOINT=http://172.22.0.2:6385/v1/
-IRONIC_INSPECTOR_ENDPOINT=http://172.22.0.2:5050/v1/
-CACHEURL=http://172.22.0.1/images
-IRONIC_FAST_TRACK=false
\ No newline at end of file
diff --git a/ironic-deployment/default/kustomization.yaml b/ironic-deployment/default/kustomization.yaml
deleted file mode 100644
index fb7c97cb..00000000
--- a/ironic-deployment/default/kustomization.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-apiVersion: kustomize.config.k8s.io/v1beta1
-kind: Kustomization
-namespace: metal3
-resources:
-- ../ironic
-configMapGenerator:
-- envs:
-  - ironic_bmo_configmap.env
-  name: ironic-bmo-configmap
-secretGenerator:
-- literals:
-  - password=changeme
-  name: mariadb-password
-  type: Opaque
\ No newline at end of file
diff --git a/ironic-deployment/ironic/ironic.yaml b/ironic-deployment/ironic/ironic.yaml
deleted file mode 100644
index 037f8190..00000000
--- a/ironic-deployment/ironic/ironic.yaml
+++ /dev/null
@@ -1,96 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: metal3-ironic
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      name: metal3-ironic
-  template:
-    metadata:
-      labels:
-        name: metal3-ironic
-    spec:
-      hostNetwork: true
-      containers:
-        - name: ironic-dnsmasq
-          image: quay.io/metal3-io/ironic
-          imagePullPolicy: Always
-          securityContext:
-             capabilities:
-               add: ["NET_ADMIN"]
-          command:
-            - /bin/rundnsmasq
-          volumeMounts:
-            - mountPath: /shared
-              name: ironic-data-volume
-          envFrom:
-            - configMapRef:
-                name: ironic-bmo-configmap
-        - name: mariadb
-          image: quay.io/metal3-io/ironic
-          imagePullPolicy: Always
-          command:
-            - /bin/runmariadb
-          volumeMounts:
-            - mountPath: /shared
-              name: ironic-data-volume
-          env:
-            - name: MARIADB_PASSWORD
-              valueFrom:
-                secretKeyRef:
-                  name: mariadb-password
-                  key: password
-        - name: ironic-httpd
-          image: quay.io/metal3-io/ironic
-          imagePullPolicy: Always
-          securityContext:
-             capabilities:
-               add: ["NET_ADMIN"]
-          command:
-            - /bin/runhttpd
-          volumeMounts:
-            - mountPath: /shared
-              name: ironic-data-volume
-          envFrom:
-            - configMapRef:
-                name: ironic-bmo-configmap
-        - name: ironic
-          image: quay.io/metal3-io/ironic
-          imagePullPolicy: Always
-          command:
-            - /bin/runironic
-          volumeMounts:
-            - mountPath: /shared
-              name: ironic-data-volume
-          envFrom:
-            - configMapRef:
-                name: ironic-bmo-configmap
-          env:
-            - name: MARIADB_PASSWORD
-              valueFrom:
-                secretKeyRef:
-                  name: mariadb-password
-                  key: password
-        - name: ironic-inspector
-          image: quay.io/metal3-io/ironic-inspector
-          imagePullPolicy: Always
-          envFrom:
-            - configMapRef:
-                name: ironic-bmo-configmap
-      initContainers:
-        - name: ironic-ipa-downloader
-          image: quay.io/metal3-io/ironic-ipa-downloader
-          imagePullPolicy: Always
-          command:
-            - /usr/local/bin/get-resource.sh
-          envFrom:
-            - configMapRef:
-                name: ironic-bmo-configmap
-          volumeMounts:
-            - mountPath: /shared
-              name: ironic-data-volume
-      volumes:
-        - name: ironic-data-volume
-          emptyDir: {}
\ No newline at end of file
diff --git a/ironic-deployment/ironic/kustomization.yaml b/ironic-deployment/ironic/kustomization.yaml
deleted file mode 100644
index 01aaa615..00000000
--- a/ironic-deployment/ironic/kustomization.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-apiVersion: kustomize.config.k8s.io/v1beta1
-kind: Kustomization
-resources:
-- ironic.yaml
\ No newline at end of file
diff --git a/ironic-deployment/keepalived/ironic_bmo_configmap.env b/ironic-deployment/keepalived/ironic_bmo_configmap.env
deleted file mode 100644
index 2ca15298..00000000
--- a/ironic-deployment/keepalived/ironic_bmo_configmap.env
+++ /dev/null
@@ -1,11 +0,0 @@
-HTTP_PORT=6180
-PROVISIONING_IP=172.22.0.2
-PROVISIONING_CIDR=24
-PROVISIONING_INTERFACE=ironicendpoint
-DHCP_RANGE=172.22.0.10,172.22.0.100
-DEPLOY_KERNEL_URL=http://172.22.0.2:6180/images/ironic-python-agent.kernel
-DEPLOY_RAMDISK_URL=http://172.22.0.2:6180/images/ironic-python-agent.initramfs
-IRONIC_ENDPOINT=http://172.22.0.2:6385/v1/
-IRONIC_INSPECTOR_ENDPOINT=http://172.22.0.2:5050/v1/
-CACHEURL=http://172.22.0.1/images
-IRONIC_FAST_TRACK=false
\ No newline at end of file
diff --git a/ironic-deployment/keepalived/keepalived_patch.yaml b/ironic-deployment/keepalived/keepalived_patch.yaml
deleted file mode 100644
index e6a2e244..00000000
--- a/ironic-deployment/keepalived/keepalived_patch.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: metal3-ironic
-spec:
-  template:
-    spec:
-      containers:
-      # Change the value of image field below to your controller image URL
-      - image: quay.io/metal3-io/keepalived
-        name: ironic-endpoint-keepalived
-        securityContext:
-              capabilities:
-                add: ["NET_ADMIN"]
-        envFrom:
-          - configMapRef:
-              name: ironic-bmo-configmap
\ No newline at end of file
diff --git a/ironic-deployment/keepalived/kustomization.yaml b/ironic-deployment/keepalived/kustomization.yaml
deleted file mode 100644
index e0df059c..00000000
--- a/ironic-deployment/keepalived/kustomization.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-apiVersion: kustomize.config.k8s.io/v1beta1
-kind: Kustomization
-namespace: metal3
-resources:
-- ../../deploy/namespace
-- ../ironic
-configMapGenerator:
-- envs:
-  - ironic_bmo_configmap.env
-  name: ironic-bmo-configmap
-secretGenerator:
-- literals:
-  - password=changeme
-  name: mariadb-password
-  type: Opaque
-patchesStrategicMerge:
-- keepalived_patch.yaml
\ No newline at end of file
diff --git a/pkg/apis/metal3/v1alpha1/baremetalhost_types.go b/pkg/apis/metal3/v1alpha1/baremetalhost_types.go
index e360ed40..a4ffc717 100644
--- a/pkg/apis/metal3/v1alpha1/baremetalhost_types.go
+++ b/pkg/apis/metal3/v1alpha1/baremetalhost_types.go
@@ -28,54 +28,8 @@ const (
 	// annotation is present and status is empty, BMO will reconstruct BMH Status
 	// from the status annotation.
 	StatusAnnotation = "baremetalhost.metal3.io/status"
-
-	// UnhealthyAnnotation is the annotation that sets unhealthy status of BMH
-	UnhealthyAnnotation = "baremetalhost.metal3.io/unhealthy"
 )
 
-// RootDeviceHints holds the hints for specifying the storage location
-// for the root filesystem for the image.
-type RootDeviceHints struct {
-	// A Linux device name like "/dev/vda". The hint must match the
-	// actual value exactly.
-	DeviceName string `json:"deviceName,omitempty"`
-
-	// A SCSI bus address like 0:0:0:0. The hint must match the actual
-	// value exactly.
-	HCTL string `json:"hctl,omitempty"`
-
-	// A vendor-specific device identifier. The hint can be a
-	// substring of the actual value.
-	Model string `json:"model,omitempty"`
-
-	// The name of the vendor or manufacturer of the device. The hint
-	// can be a substring of the actual value.
-	Vendor string `json:"vendor,omitempty"`
-
-	// Device serial number. The hint must match the actual value
-	// exactly.
-	SerialNumber string `json:"serialNumber,omitempty"`
-
-	// The minimum size of the device in Gigabytes.
-	// +kubebuilder:validation:Minimum=0
-	MinSizeGigabytes int `json:"minSizeGigabytes,omitempty"`
-
-	// Unique storage identifier. The hint must match the actual value
-	// exactly.
-	WWN string `json:"wwn,omitempty"`
-
-	// Unique storage identifier with the vendor extension
-	// appended. The hint must match the actual value exactly.
-	WWNWithExtension string `json:"wwnWithExtension,omitempty"`
-
-	// Unique vendor storage identifier. The hint must match the
-	// actual value exactly.
-	WWNVendorExtension string `json:"wwnVendorExtension,omitempty"`
-
-	// True if the device should use spinning media, false otherwise.
-	Rotational *bool `json:"rotational,omitempty"`
-}
-
 // OperationalStatus represents the state of the host
 type OperationalStatus string
 
@@ -211,10 +165,6 @@ type BareMetalHostSpec struct {
 	// automatically determine the profile.
 	HardwareProfile string `json:"hardwareProfile,omitempty"`
 
-	// Provide guidance about how to choose the device for the image
-	// being provisioned.
-	RootDeviceHints *RootDeviceHints `json:"rootDeviceHints,omitempty"`
-
 	// Which MAC address will PXE boot? This is optional for some
 	// types, but required for libvirt VMs driven by vbmc.
 	// +kubebuilder:validation:Pattern=`[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}`
@@ -541,9 +491,6 @@ type ProvisionStatus struct {
 	// Image holds the details of the last image successfully
 	// provisioned to the host.
 	Image Image `json:"image,omitempty"`
-
-	// The RootDevicehints set by the user
-	RootDeviceHints *RootDeviceHints `json:"rootDeviceHints,omitempty"`
 }
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
diff --git a/pkg/apis/metal3/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/metal3/v1alpha1/zz_generated.deepcopy.go
index 4c57aff7..dcd9c3ab 100644
--- a/pkg/apis/metal3/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/metal3/v1alpha1/zz_generated.deepcopy.go
@@ -113,11 +113,6 @@ func (in *BareMetalHostSpec) DeepCopyInto(out *BareMetalHostSpec) {
 		}
 	}
 	out.BMC = in.BMC
-	if in.RootDeviceHints != nil {
-		in, out := &in.RootDeviceHints, &out.RootDeviceHints
-		*out = new(RootDeviceHints)
-		(*in).DeepCopyInto(*out)
-	}
 	if in.ConsumerRef != nil {
 		in, out := &in.ConsumerRef, &out.ConsumerRef
 		*out = new(v1.ObjectReference)
@@ -375,11 +370,6 @@ func (in *OperationMetric) DeepCopy() *OperationMetric {
 func (in *ProvisionStatus) DeepCopyInto(out *ProvisionStatus) {
 	*out = *in
 	in.Image.DeepCopyInto(&out.Image)
-	if in.RootDeviceHints != nil {
-		in, out := &in.RootDeviceHints, &out.RootDeviceHints
-		*out = new(RootDeviceHints)
-		(*in).DeepCopyInto(*out)
-	}
 	return
 }
 
@@ -393,27 +383,6 @@ func (in *ProvisionStatus) DeepCopy() *ProvisionStatus {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *RootDeviceHints) DeepCopyInto(out *RootDeviceHints) {
-	*out = *in
-	if in.Rotational != nil {
-		in, out := &in.Rotational, &out.Rotational
-		*out = new(bool)
-		**out = **in
-	}
-	return
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RootDeviceHints.
-func (in *RootDeviceHints) DeepCopy() *RootDeviceHints {
-	if in == nil {
-		return nil
-	}
-	out := new(RootDeviceHints)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Storage) DeepCopyInto(out *Storage) {
 	*out = *in
diff --git a/pkg/bmc/ibmc.go b/pkg/bmc/ibmc.go
deleted file mode 100644
index 12c41a7c..00000000
--- a/pkg/bmc/ibmc.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package bmc
-
-import (
-	"net/url"
-	"strings"
-)
-
-func init() {
-	registerFactory("ibmc", newIbmcAccessDetails)
-	registerFactory("ibmc+http", newIbmcAccessDetails)
-	registerFactory("ibmc+https", newIbmcAccessDetails)
-}
-
-func newIbmcAccessDetails(parsedURL *url.URL, disableCertificateVerification bool) (AccessDetails, error) {
-	return &ibmcAccessDetails{
-		bmcType:                        parsedURL.Scheme,
-		host:                           parsedURL.Host,
-		path:                           parsedURL.Path,
-		disableCertificateVerification: disableCertificateVerification,
-	}, nil
-}
-
-type ibmcAccessDetails struct {
-	bmcType                        string
-	host                           string
-	path                           string
-	disableCertificateVerification bool
-}
-
-func (a *ibmcAccessDetails) Type() string {
-	return a.bmcType
-}
-
-// NeedsMAC returns true when the host is going to need a separate
-// port created rather than having it discovered.
-func (a *ibmcAccessDetails) 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
-}
-
-func (a *ibmcAccessDetails) Driver() string {
-	return "ibmc"
-}
-
-func (a *ibmcAccessDetails) DisableCertificateVerification() bool {
-	return a.disableCertificateVerification
-}
-
-const ibmcDefaultScheme = "https"
-
-// DriverInfo returns a data structure to pass as the DriverInfo
-// parameter when creating a node in Ironic. The structure is
-// pre-populated with the access information, and the caller is
-// expected to add any other information that might be needed (such as
-// the kernel and ramdisk locations).
-func (a *ibmcAccessDetails) DriverInfo(bmcCreds Credentials) map[string]interface{} {
-
-	ibmcAddress := []string{}
-	schemes := strings.Split(a.bmcType, "+")
-	if len(schemes) > 1 {
-		ibmcAddress = append(ibmcAddress, schemes[1])
-	} else {
-		ibmcAddress = append(ibmcAddress, ibmcDefaultScheme)
-	}
-	ibmcAddress = append(ibmcAddress, "://")
-	ibmcAddress = append(ibmcAddress, a.host)
-	ibmcAddress = append(ibmcAddress, a.path)
-
-	result := map[string]interface{}{
-		"ibmc_username": bmcCreds.Username,
-		"ibmc_password": bmcCreds.Password,
-		"ibmc_address":  strings.Join(ibmcAddress, ""),
-	}
-
-	if a.disableCertificateVerification {
-		result["ibmc_verify_ca"] = false
-	}
-
-	return result
-}
-
-func (a *ibmcAccessDetails) BootInterface() string {
-	return "pxe"
-}
-
-func (a *ibmcAccessDetails) ManagementInterface() string {
-	return "ibmc"
-}
-
-func (a *ibmcAccessDetails) PowerInterface() string {
-	return "ibmc"
-}
-
-func (a *ibmcAccessDetails) RAIDInterface() string {
-	return ""
-}
-
-func (a *ibmcAccessDetails) VendorInterface() string {
-	return ""
-}
diff --git a/pkg/controller/baremetalhost/baremetalhost_controller.go b/pkg/controller/baremetalhost/baremetalhost_controller.go
index 101bea83..15aa32ef 100644
--- a/pkg/controller/baremetalhost/baremetalhost_controller.go
+++ b/pkg/controller/baremetalhost/baremetalhost_controller.go
@@ -207,13 +207,6 @@ func (r *ReconcileBareMetalHost) Reconcile(request reconcile.Request) (result re
 		objStatus, err := r.getHostStatusFromAnnotation(host)
 		if err == nil && objStatus != nil {
 			host.Status = *objStatus
-			if host.Status.LastUpdated.IsZero() {
-				// Ensure the LastUpdated timestamp in set to avoid
-				// infinite loops if the annotation only contained
-				// part of the status information.
-				t := metav1.Now()
-				host.Status.LastUpdated = &t
-			}
 			errStatus := r.client.Status().Update(context.TODO(), host)
 			if errStatus != nil {
 				return reconcile.Result{}, errors.Wrap(err, "Could not restore status from annotation")
@@ -573,7 +566,6 @@ func (r *ReconcileBareMetalHost) actionMatchProfile(prov provisioner.Provisioner
 		info.log.Info("updating hardware profile", "profile", hardwareProfile)
 		info.publishEvent("ProfileSet", fmt.Sprintf("Hardware profile set: %s", hardwareProfile))
 	}
-
 	info.host.ClearError()
 	return actionComplete{}
 }
@@ -623,13 +615,6 @@ func (r *ReconcileBareMetalHost) actionProvisioning(prov provisioner.Provisioner
 	return actionComplete{}
 }
 
-// clearHostProvisioningSettings removes the values related to
-// provisioning that do not trigger re-provisioning from the status
-// fields of a host.
-func clearHostProvisioningSettings(host *metal3v1alpha1.BareMetalHost) {
-	host.Status.Provisioning.RootDeviceHints = nil
-}
-
 func (r *ReconcileBareMetalHost) actionDeprovisioning(prov provisioner.Provisioner, info *reconcileInfo) actionResult {
 	info.log.Info("deprovisioning")
 
@@ -654,10 +639,9 @@ func (r *ReconcileBareMetalHost) actionDeprovisioning(prov provisioner.Provision
 		return actionContinueNoWrite{}
 	}
 
-	// After the provisioner is done, clear the provisioning settings
-	// so we transition to the next state.
+	// After the provisioner is done, clear the image settings so we
+	// transition to the next state.
 	info.host.Status.Provisioning.Image = metal3v1alpha1.Image{}
-	clearHostProvisioningSettings(info.host)
 
 	return actionComplete{}
 }
@@ -794,44 +778,12 @@ func (r *ReconcileBareMetalHost) actionManageReady(prov provisioner.Provisioner,
 	}
 
 	if info.host.NeedsProvisioning() {
-		// Ensure the root device hints we're going to use are stored.
-		dirty, err := saveHostProvisioningSettings(info.host)
-		if err != nil {
-			return actionError{errors.Wrap(err, "Could not save the host provisioning settings")}
-		}
-		if dirty {
-			info.log.Info("updating host provisioning settings")
-		}
 		info.host.ClearError()
 		return actionComplete{}
 	}
 	return r.manageHostPower(prov, info)
 }
 
-// saveHostProvisioningSettings copies the values related to
-// provisioning that do not trigger re-provisioning into the status
-// fields of the host.
-func saveHostProvisioningSettings(host *metal3v1alpha1.BareMetalHost) (dirty bool, err error) {
-
-	// Ensure the root device hints we're going to use are stored.
-	//
-	// If the user has provided explicit root device hints, they take
-	// precedence. Otherwise use the values from the hardware profile.
-	hintSource := host.Spec.RootDeviceHints
-	if hintSource == nil {
-		hwProf, err := hardware.GetProfile(host.HardwareProfile())
-		if err != nil {
-			return false, errors.Wrap(err, "Could not update root device hints")
-		}
-		hintSource = &hwProf.RootDeviceHints
-	}
-	if (hintSource != nil && host.Status.Provisioning.RootDeviceHints == nil) || *hintSource != *(host.Status.Provisioning.RootDeviceHints) {
-		host.Status.Provisioning.RootDeviceHints = hintSource
-		dirty = true
-	}
-	return
-}
-
 func (r *ReconcileBareMetalHost) saveHostStatus(host *metal3v1alpha1.BareMetalHost) error {
 	t := metav1.Now()
 	host.Status.LastUpdated = &t
@@ -873,7 +825,7 @@ func (r *ReconcileBareMetalHost) saveHostAnnotation(host *metal3v1alpha1.BareMet
 	}
 
 	delete(host.Annotations, metal3v1alpha1.StatusAnnotation)
-	newAnnotation, err := marshalStatusAnnotation(&host.Status)
+	newAnnotation, err := json.Marshal(host.Status)
 	if err != nil {
 		return err
 	}
@@ -884,22 +836,6 @@ func (r *ReconcileBareMetalHost) saveHostAnnotation(host *metal3v1alpha1.BareMet
 	return r.client.Update(context.TODO(), host.DeepCopy())
 }
 
-func marshalStatusAnnotation(status *metal3v1alpha1.BareMetalHostStatus) ([]byte, error) {
-	newAnnotation, err := json.Marshal(status)
-	if err != nil {
-		return []byte{}, errors.Wrap(err, "failed to marshall status annotation")
-	}
-	return newAnnotation, nil
-}
-
-func unmarshalStatusAnnotation(content []byte) (*metal3v1alpha1.BareMetalHostStatus, error) {
-	objStatus := &metal3v1alpha1.BareMetalHostStatus{}
-	if err := json.Unmarshal(content, objStatus); err != nil {
-		return nil, errors.Wrap(err, "Failed to fetch Status from annotation")
-	}
-	return objStatus, nil
-}
-
 // extract host from Status annotation
 func (r *ReconcileBareMetalHost) getHostStatusFromAnnotation(host *metal3v1alpha1.BareMetalHost) (*metal3v1alpha1.BareMetalHostStatus, error) {
 	annotations := host.GetAnnotations()
@@ -907,9 +843,9 @@ func (r *ReconcileBareMetalHost) getHostStatusFromAnnotation(host *metal3v1alpha
 	if annotations[metal3v1alpha1.StatusAnnotation] == "" {
 		return nil, nil
 	}
-	objStatus, err := unmarshalStatusAnnotation(content)
-	if err != nil {
-		return nil, err
+	objStatus := &metal3v1alpha1.BareMetalHostStatus{}
+	if err := json.Unmarshal(content, objStatus); err != nil {
+		return nil, errors.Wrap(err, "Failed to fetch Status from annotation")
 	}
 	return objStatus, nil
 }
diff --git a/pkg/hardware/profile.go b/pkg/hardware/profile.go
index 73c357ba..908a7747 100644
--- a/pkg/hardware/profile.go
+++ b/pkg/hardware/profile.go
@@ -2,8 +2,6 @@ package hardware
 
 import (
 	"fmt"
-
-	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/pkg/apis/metal3/v1alpha1"
 )
 
 const (
@@ -19,7 +17,7 @@ type Profile struct {
 
 	// RootDeviceHints holds the suggestions for placing the storage
 	// for the root filesystem.
-	RootDeviceHints metal3v1alpha1.RootDeviceHints
+	RootDeviceHints RootDeviceHints
 
 	// RootGB is the size of the root volume in GB
 	RootGB int
@@ -31,12 +29,26 @@ type Profile struct {
 	CPUArch string
 }
 
+// RootDeviceHints holds the hints for specifying the storage location
+// for the root filesystem for the image.
+//
+// NOTE(dhellmann): Valid ironic hints are: "vendor,
+// wwn_vendor_extension, wwn_with_extension, by_path, serial, wwn,
+// size, rotational, name, hctl, model"
+type RootDeviceHints struct {
+	// A device name like "/dev/vda"
+	DeviceName string
+
+	// A SCSI bus address like 0:0:0:0
+	HCTL string
+}
+
 var profiles = make(map[string]Profile)
 
 func init() {
 	profiles[DefaultProfileName] = Profile{
 		Name: DefaultProfileName,
-		RootDeviceHints: metal3v1alpha1.RootDeviceHints{
+		RootDeviceHints: RootDeviceHints{
 			DeviceName: "/dev/sda",
 		},
 		RootGB:  10,
@@ -46,7 +58,7 @@ func init() {
 
 	profiles["libvirt"] = Profile{
 		Name: "libvirt",
-		RootDeviceHints: metal3v1alpha1.RootDeviceHints{
+		RootDeviceHints: RootDeviceHints{
 			DeviceName: "/dev/vda",
 		},
 		RootGB:  10,
@@ -56,7 +68,7 @@ func init() {
 
 	profiles["dell"] = Profile{
 		Name: "dell",
-		RootDeviceHints: metal3v1alpha1.RootDeviceHints{
+		RootDeviceHints: RootDeviceHints{
 			HCTL: "0:0:0:0",
 		},
 		RootGB:  10,
@@ -66,7 +78,7 @@ func init() {
 
 	profiles["dell-raid"] = Profile{
 		Name: "dell-raid",
-		RootDeviceHints: metal3v1alpha1.RootDeviceHints{
+		RootDeviceHints: RootDeviceHints{
 			HCTL: "0:2:0:0",
 		},
 		RootGB:  10,
@@ -76,7 +88,7 @@ func init() {
 
 	profiles["openstack"] = Profile{
 		Name: "openstack",
-		RootDeviceHints: metal3v1alpha1.RootDeviceHints{
+		RootDeviceHints: RootDeviceHints{
 			DeviceName: "/dev/vdb",
 		},
 		RootGB:  10,
diff --git a/pkg/provisioner/ironic/devicehints/devicehints.go b/pkg/provisioner/ironic/devicehints/devicehints.go
deleted file mode 100644
index f4f0cbd3..00000000
--- a/pkg/provisioner/ironic/devicehints/devicehints.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package devicehints
-
-import (
-	"fmt"
-
-	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/pkg/apis/metal3/v1alpha1"
-)
-
-// MakeHintMap converts a RootDeviceHints instance into a string map
-// suitable to pass to ironic.
-func MakeHintMap(source *metal3v1alpha1.RootDeviceHints) map[string]string {
-	hints := map[string]string{}
-
-	if source == nil {
-		return hints
-	}
-
-	if source.DeviceName != "" {
-		hints["name"] = fmt.Sprintf("s== %s", source.DeviceName)
-	}
-	if source.HCTL != "" {
-		hints["hctl"] = fmt.Sprintf("s== %s", source.HCTL)
-	}
-	if source.Model != "" {
-		hints["model"] = fmt.Sprintf("<in> %s", source.Model)
-	}
-	if source.Vendor != "" {
-		hints["vendor"] = fmt.Sprintf("<in> %s", source.Vendor)
-	}
-	if source.SerialNumber != "" {
-		hints["serial"] = fmt.Sprintf("s== %s", source.SerialNumber)
-	}
-	if source.MinSizeGigabytes != 0 {
-		hints["size"] = fmt.Sprintf(">= %d", source.MinSizeGigabytes)
-	}
-	if source.WWN != "" {
-		hints["wwn"] = fmt.Sprintf("s== %s", source.WWN)
-	}
-	if source.WWNWithExtension != "" {
-		hints["wwn_with_extension"] = fmt.Sprintf("s== %s", source.WWNWithExtension)
-	}
-	if source.WWNVendorExtension != "" {
-		hints["wwn_vendor_extension"] = fmt.Sprintf("s== %s", source.WWNVendorExtension)
-	}
-	switch {
-	case source.Rotational == nil:
-	case *source.Rotational == true:
-		hints["rotational"] = "true"
-	case *source.Rotational == false:
-		hints["rotational"] = "false"
-	}
-
-	return hints
-}
diff --git a/pkg/provisioner/ironic/ironic.go b/pkg/provisioner/ironic/ironic.go
index 3766adea..372600f7 100644
--- a/pkg/provisioner/ironic/ironic.go
+++ b/pkg/provisioner/ironic/ironic.go
@@ -24,7 +24,6 @@ import (
 	"github.com/metal3-io/baremetal-operator/pkg/bmc"
 	"github.com/metal3-io/baremetal-operator/pkg/hardware"
 	"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"
 )
 
@@ -310,27 +309,6 @@ func (p *ironicProvisioner) ValidateManagementAccess(credentialsChanged bool) (r
 					Value: string(p.host.ObjectMeta.UID),
 				},
 			}
-
-			// image_checksum
-			//
-			// FIXME: For older versions of ironic that do not have
-			// https://review.opendev.org/#/c/711816/ failing to
-			// include the 'image_checksum' causes ironic to refuse to
-			// provision the image, even if the other hash value
-			// parameters are given. We only want to do that for MD5,
-			// however, because those versions of ironic only support
-			// MD5 checksums.
-			if checksumType == string(metal3v1alpha1.MD5) {
-				updates = append(
-					updates,
-					nodes.UpdateOperation{
-						Op:    nodes.AddOp,
-						Path:  "/instance_info/image_checksum",
-						Value: checksum,
-					},
-				)
-			}
-
 			if p.host.Spec.Image.DiskFormat != nil {
 				updates = append(updates, nodes.UpdateOperation{
 					Op:    nodes.AddOp,
@@ -582,7 +560,6 @@ func (p *ironicProvisioner) UpdateHardwareState() (result provisioner.Result, er
 func (p *ironicProvisioner) getUpdateOptsForNode(ironicNode *nodes.Node) (updates nodes.UpdateOpts, err error) {
 
 	hwProf, err := hardware.GetProfile(p.host.HardwareProfile())
-
 	if err != nil {
 		return updates, errors.Wrap(err,
 			fmt.Sprintf("Could not start provisioning with bad hardware profile %s",
@@ -643,32 +620,6 @@ func (p *ironicProvisioner) getUpdateOptsForNode(ironicNode *nodes.Node) (update
 		},
 	)
 
-	// image_checksum
-	//
-	// FIXME: For older versions of ironic that do not have
-	// https://review.opendev.org/#/c/711816/ failing to include the
-	// 'image_checksum' causes ironic to refuse to provision the
-	// image, even if the other hash value parameters are given. We
-	// only want to do that for MD5, however, because those versions
-	// of ironic only support MD5 checksums.
-	if checksumType == string(metal3v1alpha1.MD5) {
-		if _, ok := ironicNode.InstanceInfo["image_checksum"]; !ok {
-			op = nodes.AddOp
-			p.log.Info("adding image_checksum")
-		} else {
-			op = nodes.ReplaceOp
-			p.log.Info("updating image_checksum")
-		}
-		updates = append(
-			updates,
-			nodes.UpdateOperation{
-				Op:    op,
-				Path:  "/instance_info/image_checksum",
-				Value: checksum,
-			},
-		)
-	}
-
 	if p.host.Spec.Image.DiskFormat != nil {
 		updates = append(updates, nodes.UpdateOperation{
 			Op:    nodes.AddOp,
@@ -722,12 +673,13 @@ func (p *ironicProvisioner) getUpdateOptsForNode(ironicNode *nodes.Node) (update
 		op = nodes.ReplaceOp
 		p.log.Info("updating root_device")
 	}
-
-	// hints
-	//
-	// If the user has provided explicit root device hints, they take
-	// precedence. Otherwise use the values from the hardware profile.
-	hints := devicehints.MakeHintMap(p.host.Status.Provisioning.RootDeviceHints)
+	hints := map[string]string{}
+	switch {
+	case hwProf.RootDeviceHints.DeviceName != "":
+		hints["name"] = hwProf.RootDeviceHints.DeviceName
+	case hwProf.RootDeviceHints.HCTL != "":
+		hints["hctl"] = hwProf.RootDeviceHints.HCTL
+	}
 	p.log.Info("using root device", "hints", hints)
 	updates = append(
 		updates,


Test patch:
diff --git a/pkg/bmc/access_test.go b/pkg/bmc/access_test.go
index 1214010f..e2e535c7 100644
--- a/pkg/bmc/access_test.go
+++ b/pkg/bmc/access_test.go
@@ -230,87 +230,6 @@ func TestParse(t *testing.T) {
 			Hostname: "192.168.122.1",
 			Path:     "",
 		},
-
-		// ibmc
-		{
-			Scenario: "ibmc url",
-			Address:  "ibmc://192.168.122.1",
-			Type:     "ibmc",
-			Port:     "",
-			Host:     "192.168.122.1",
-			Hostname: "192.168.122.1",
-			Path:     "",
-		},
-
-		{
-			Scenario: "ibmc url path",
-			Address:  "ibmc://192.168.122.1:6233/foo",
-			Type:     "ibmc",
-			Port:     "6233",
-			Host:     "192.168.122.1",
-			Hostname: "192.168.122.1:6233",
-			Path:     "/foo",
-		},
-
-		{
-			Scenario: "ibmc url with http scheme",
-			Address:  "ibmc+http://192.168.122.1",
-			Type:     "ibmc+http",
-			Port:     "",
-			Host:     "192.168.122.1",
-			Hostname: "192.168.122.1",
-			Path:     "",
-		},
-
-		{
-			Scenario: "ibmc url with http scheme",
-			Address:  "ibmc+https://192.168.122.1",
-			Type:     "ibmc+https",
-			Port:     "",
-			Host:     "192.168.122.1",
-			Hostname: "192.168.122.1",
-			Path:     "",
-		},
-
-		{
-			Scenario: "ibmc url path",
-			Address:  "ibmc://192.168.122.1:6233/foo",
-			Type:     "ibmc",
-			Port:     "6233",
-			Host:     "192.168.122.1",
-			Hostname: "192.168.122.1:6233",
-			Path:     "/foo",
-		},
-
-		{
-			Scenario: "ibmc url ipv6",
-			Address:  "ibmc://[fe80::fc33:62ff:fe83:8a76]",
-			Type:     "ibmc",
-			Port:     "",
-			Host:     "fe80::fc33:62ff:fe83:8a76",
-			Hostname: "[fe80::fc33:62ff:fe83:8a76]",
-			Path:     "",
-		},
-
-		{
-			Scenario: "ibmc url path ipv6",
-			Address:  "ibmc://[fe80::fc33:62ff:fe83:8a76]:6233/foo",
-			Type:     "ibmc",
-			Port:     "6233",
-			Host:     "fe80::fc33:62ff:fe83:8a76",
-			Hostname: "[fe80::fc33:62ff:fe83:8a76]:6233",
-			Path:     "/foo",
-		},
-
-		{
-			Scenario: "ibmc url no sep",
-			Address:  "ibmc:192.168.122.1",
-			Type:     "ibmc",
-			Port:     "",
-			Host:     "192.168.122.1",
-			Hostname: "192.168.122.1",
-			Path:     "",
-		},
 	} {
 		t.Run(tc.Scenario, func(t *testing.T) {
 			url, err := getParsedURL(tc.Address)
@@ -472,18 +391,6 @@ func TestStaticDriverInfo(t *testing.T) {
 			raid:       "no-raid",
 			vendor:     "no-vendor",
 		},
-
-		{
-			Scenario:   "ibmc",
-			input:      "ibmc://192.168.122.1:6233",
-			needsMac:   true,
-			driver:     "ibmc",
-			boot:       "pxe",
-			management: "ibmc",
-			power:      "ibmc",
-			raid:       "no-raid",
-			vendor:     "",
-		},
 	} {
 		t.Run(tc.Scenario, func(t *testing.T) {
 			acc, err := NewAccessDetails(tc.input, false)
@@ -748,73 +655,6 @@ func TestDriverInfo(t *testing.T) {
 				"redfish_verify_ca": false,
 			},
 		},
-
-		// ibmc driver testcases
-		{
-			Scenario: "ibmc",
-			input:    "ibmc://192.168.122.1/foo/bar",
-			expects: map[string]interface{}{
-				"ibmc_address":   "https://192.168.122.1/foo/bar",
-				"ibmc_password":  "",
-				"ibmc_username":  "",
-				"ibmc_verify_ca": false,
-			},
-		},
-
-		{
-			Scenario: "ibmc http",
-			input:    "ibmc+http://192.168.122.1/foo/bar",
-			expects: map[string]interface{}{
-				"ibmc_address":   "http://192.168.122.1/foo/bar",
-				"ibmc_password":  "",
-				"ibmc_username":  "",
-				"ibmc_verify_ca": false,
-			},
-		},
-
-		{
-			Scenario: "ibmc https",
-			input:    "ibmc+https://192.168.122.1/foo/bar",
-			expects: map[string]interface{}{
-				"ibmc_address":   "https://192.168.122.1/foo/bar",
-				"ibmc_password":  "",
-				"ibmc_username":  "",
-				"ibmc_verify_ca": false,
-			},
-		},
-
-		{
-			Scenario: "ibmc port",
-			input:    "ibmc://192.168.122.1:8080/foo/bar",
-			expects: map[string]interface{}{
-				"ibmc_address":   "https://192.168.122.1:8080/foo/bar",
-				"ibmc_password":  "",
-				"ibmc_username":  "",
-				"ibmc_verify_ca": false,
-			},
-		},
-
-		{
-			Scenario: "ibmc ipv6",
-			input:    "ibmc://[fe80::fc33:62ff:fe83:8a76]/foo/bar",
-			expects: map[string]interface{}{
-				"ibmc_address":   "https://[fe80::fc33:62ff:fe83:8a76]/foo/bar",
-				"ibmc_password":  "",
-				"ibmc_username":  "",
-				"ibmc_verify_ca": false,
-			},
-		},
-
-		{
-			Scenario: "ibmc ipv6 port",
-			input:    "ibmc://[fe80::fc33:62ff:fe83:8a76]:8080/foo",
-			expects: map[string]interface{}{
-				"ibmc_address":   "https://[fe80::fc33:62ff:fe83:8a76]:8080/foo",
-				"ibmc_password":  "",
-				"ibmc_username":  "",
-				"ibmc_verify_ca": false,
-			},
-		},
 	} {
 		t.Run(tc.Scenario, func(t *testing.T) {
 			acc, err := NewAccessDetails(tc.input, true)
diff --git a/pkg/controller/baremetalhost/baremetalhost_controller_test.go b/pkg/controller/baremetalhost/baremetalhost_controller_test.go
index df47234b..02211998 100644
--- a/pkg/controller/baremetalhost/baremetalhost_controller_test.go
+++ b/pkg/controller/baremetalhost/baremetalhost_controller_test.go
@@ -7,8 +7,6 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
-
 	corev1 "k8s.io/api/core/v1"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -30,7 +28,7 @@ import (
 const (
 	namespace         string = "test-namespace"
 	defaultSecretName string = "bmc-creds-valid"
-	statusAnnotation  string = `{"operationalStatus":"OK","lastUpdated":"2020-04-15T15:00:50Z","hardwareProfile":"StatusProfile","hardware":{"systemVendor":{"manufacturer":"QEMU","productName":"Standard PC (Q35 + ICH9, 2009)","serialNumber":""},"firmware":{"bios":{"date":"","vendor":"","version":""}},"ramMebibytes":4096,"nics":[{"name":"eth0","model":"0x1af4 0x0001","mac":"00:b7:8b:bb:3d:f6","ip":"172.22.0.64","speedGbps":0,"vlanId":0,"pxe":true},{"name":"eth1","model":"0x1af4  0x0001","mac":"00:b7:8b:bb:3d:f8","ip":"192.168.111.20","speedGbps":0,"vlanId":0,"pxe":false}],"storage":[{"name":"/dev/sda","rotational":true,"sizeBytes":53687091200,"vendor":"QEMU","model":"QEMU HARDDISK","serialNumber":"drive-scsi0-0-0-0","hctl":"6:0:0:0"}],"cpu":{"arch":"x86_64","model":"Intel Xeon E3-12xx v2 (IvyBridge)","clockMegahertz":2494.224,"flags":["aes","apic","arat","avx","clflush","cmov","constant_tsc","cx16","cx8","de","eagerfpu","ept","erms","f16c","flexpriority","fpu","fsgsbase","fxsr","hypervisor","lahf_lm","lm","mca","mce","mmx","msr","mtrr","nopl","nx","pae","pat","pclmulqdq","pge","pni","popcnt","pse","pse36","rdrand","rdtscp","rep_good","sep","smep","sse","sse2","sse4_1","sse4_2","ssse3","syscall","tpr_shadow","tsc","tsc_adjust","tsc_deadline_timer","vme","vmx","vnmi","vpid","x2apic","xsave","xsaveopt","xtopology"],"count":4},"hostname":"node-0"},"provisioning":{"state":"provisioned","ID":"8a0ede17-7b87-44ac-9293-5b7d50b94b08","image":{"url":"bar","checksum":""}},"goodCredentials":{"credentials":{"name":"node-0-bmc-secret","namespace":"metal3"},"credentialsVersion":"879"},"triedCredentials":{"credentials":{"name":"node-0-bmc-secret","namespace":"metal3"},"credentialsVersion":"879"},"errorMessage":"","poweredOn":true,"operationHistory":{"register":{"start":"2020-04-15T12:06:26Z","end":"2020-04-15T12:07:12Z"},"inspect":{"start":"2020-04-15T12:07:12Z","end":"2020-04-15T12:09:29Z"},"provision":{"start":null,"end":null},"deprovision":{"start":null,"end":null}}}`
+	statusAnnotaion   string = `{"operationalStatus":"OK","lastUpdated":"2020-04-15T15:00:50Z","hardwareProfile":"StatusProfile","hardware":{"systemVendor":{"manufacturer":"QEMU","productName":"Standard PC (Q35 + ICH9, 2009)","serialNumber":""},"firmware":{"bios":{"date":"","vendor":"","version":""}},"ramMebibytes":4096,"nics":[{"name":"eth0","model":"0x1af4 0x0001","mac":"00:b7:8b:bb:3d:f6","ip":"172.22.0.64","speedGbps":0,"vlanId":0,"pxe":true},{"name":"eth1","model":"0x1af4  0x0001","mac":"00:b7:8b:bb:3d:f8","ip":"192.168.111.20","speedGbps":0,"vlanId":0,"pxe":false}],"storage":[{"name":"/dev/sda","rotational":true,"sizeBytes":53687091200,"vendor":"QEMU","model":"QEMU HARDDISK","serialNumber":"drive-scsi0-0-0-0","hctl":"6:0:0:0"}],"cpu":{"arch":"x86_64","model":"Intel Xeon E3-12xx v2 (IvyBridge)","clockMegahertz":2494.224,"flags":["aes","apic","arat","avx","clflush","cmov","constant_tsc","cx16","cx8","de","eagerfpu","ept","erms","f16c","flexpriority","fpu","fsgsbase","fxsr","hypervisor","lahf_lm","lm","mca","mce","mmx","msr","mtrr","nopl","nx","pae","pat","pclmulqdq","pge","pni","popcnt","pse","pse36","rdrand","rdtscp","rep_good","sep","smep","sse","sse2","sse4_1","sse4_2","ssse3","syscall","tpr_shadow","tsc","tsc_adjust","tsc_deadline_timer","vme","vmx","vnmi","vpid","x2apic","xsave","xsaveopt","xtopology"],"count":4},"hostname":"node-0"},"provisioning":{"state":"provisioned","ID":"8a0ede17-7b87-44ac-9293-5b7d50b94b08","image":{"url":"bar","checksum":""}},"goodCredentials":{"credentials":{"name":"node-0-bmc-secret","namespace":"metal3"},"credentialsVersion":"879"},"triedCredentials":{"credentials":{"name":"node-0-bmc-secret","namespace":"metal3"},"credentialsVersion":"879"},"errorMessage":"","poweredOn":true,"operationHistory":{"register":{"start":"2020-04-15T12:06:26Z","end":"2020-04-15T12:07:12Z"},"inspect":{"start":"2020-04-15T12:07:12Z","end":"2020-04-15T12:09:29Z"},"provision":{"start":null,"end":null},"deprovision":{"start":null,"end":null}}}`
 )
 
 func init() {
@@ -202,7 +200,7 @@ func waitForProvisioningState(t *testing.T, r *ReconcileBareMetalHost, host *met
 func TestStatusAnnotation_EmptyStatus(t *testing.T) {
 	host := newDefaultHost(t)
 	host.Annotations = map[string]string{
-		metal3v1alpha1.StatusAnnotation: statusAnnotation,
+		metal3v1alpha1.StatusAnnotation: statusAnnotaion,
 	}
 	host.Spec.Online = true
 	host.Spec.Image = &metal3v1alpha1.Image{URL: "foo", Checksum: "123"}
@@ -224,7 +222,7 @@ func TestStatusAnnotation_EmptyStatus(t *testing.T) {
 func TestStatusAnnotation_StatusPresent(t *testing.T) {
 	host := newDefaultHost(t)
 	host.Annotations = map[string]string{
-		metal3v1alpha1.StatusAnnotation: statusAnnotation,
+		metal3v1alpha1.StatusAnnotation: statusAnnotaion,
 	}
 	host.Spec.Online = true
 	time := metav1.Now()
@@ -242,44 +240,7 @@ func TestStatusAnnotation_StatusPresent(t *testing.T) {
 	)
 }
 
-// TestStatusAnnotation_Partial ensures that if the status annotation
-// does not include the LastUpdated value reconciliation does not go
-// into an infinite loop.
-func TestStatusAnnotation_Partial(t *testing.T) {
-	// Build a version of the annotation text that does not include
-	// a LastUpdated value.
-	unpackedStatus, err := unmarshalStatusAnnotation([]byte(statusAnnotation))
-	if err != nil {
-		t.Fatal(err)
-		return
-	}
-	unpackedStatus.LastUpdated = nil
-	packedStatus, err := marshalStatusAnnotation(unpackedStatus)
-	if err != nil {
-		t.Fatal(err)
-		return
-	}
-
-	host := newDefaultHost(t)
-	host.Annotations = map[string]string{
-		metal3v1alpha1.StatusAnnotation: string(packedStatus),
-	}
-	host.Spec.Online = true
-	host.Spec.Image = &metal3v1alpha1.Image{URL: "foo", Checksum: "123"}
-
-	r := newTestReconciler(host)
-
-	tryReconcile(t, r, host,
-		func(host *metal3v1alpha1.BareMetalHost, result reconcile.Result) bool {
-			if host.Status.HardwareProfile == "StatusProfile" && host.Status.Provisioning.Image.URL == "bar" {
-				return true
-			}
-			return false
-		},
-	)
-}
-
-// TestStatusAnnotation tests if statusAnnotation is populated correctly
+// TestStatusAnnotation tests if statusAnnotaion is populated correctly
 func TestStatusAnnotation(t *testing.T) {
 	host := newDefaultHost(t)
 	host.Spec.Online = true
@@ -1076,111 +1037,3 @@ func TestDeleteHost(t *testing.T) {
 		})
 	}
 }
-
-// TestUpdateRootDeviceHints verifies that we apply the correct
-// precedence rules to the root device hints settings for a host.
-func TestUpdateRootDeviceHints(t *testing.T) {
-	rotational := true
-
-	testCases := []struct {
-		Scenario string
-		Host     metal3v1alpha1.BareMetalHost
-		Dirty    bool
-		Expected *metal3v1alpha1.RootDeviceHints
-	}{
-		{
-			Scenario: "override profile with explicit hints",
-			Host: metal3v1alpha1.BareMetalHost{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "myhost",
-					Namespace: "myns",
-					UID:       "27720611-e5d1-45d3-ba3a-222dcfaa4ca2",
-				},
-				Spec: metal3v1alpha1.BareMetalHostSpec{
-					HardwareProfile: "libvirt",
-					RootDeviceHints: &metal3v1alpha1.RootDeviceHints{
-						DeviceName:         "userd_devicename",
-						HCTL:               "1:2:3:4",
-						Model:              "userd_model",
-						Vendor:             "userd_vendor",
-						SerialNumber:       "userd_serial",
-						MinSizeGigabytes:   40,
-						WWN:                "userd_wwn",
-						WWNWithExtension:   "userd_with_extension",
-						WWNVendorExtension: "userd_vendor_extension",
-						Rotational:         &rotational,
-					},
-				},
-				Status: metal3v1alpha1.BareMetalHostStatus{
-					HardwareProfile: "libvirt",
-				},
-			},
-			Dirty: true,
-			Expected: &metal3v1alpha1.RootDeviceHints{
-				DeviceName:         "userd_devicename",
-				HCTL:               "1:2:3:4",
-				Model:              "userd_model",
-				Vendor:             "userd_vendor",
-				SerialNumber:       "userd_serial",
-				MinSizeGigabytes:   40,
-				WWN:                "userd_wwn",
-				WWNWithExtension:   "userd_with_extension",
-				WWNVendorExtension: "userd_vendor_extension",
-				Rotational:         &rotational,
-			},
-		},
-
-		{
-			Scenario: "use profile hints",
-			Host: metal3v1alpha1.BareMetalHost{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "myhost",
-					Namespace: "myns",
-					UID:       "27720611-e5d1-45d3-ba3a-222dcfaa4ca2",
-				},
-				Spec: metal3v1alpha1.BareMetalHostSpec{
-					HardwareProfile: "libvirt",
-				},
-				Status: metal3v1alpha1.BareMetalHostStatus{
-					HardwareProfile: "libvirt",
-				},
-			},
-			Dirty: true,
-			Expected: &metal3v1alpha1.RootDeviceHints{
-				DeviceName: "/dev/vda",
-			},
-		},
-
-		{
-			Scenario: "default profile hints",
-			Host: metal3v1alpha1.BareMetalHost{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "myhost",
-					Namespace: "myns",
-					UID:       "27720611-e5d1-45d3-ba3a-222dcfaa4ca2",
-				},
-				Spec: metal3v1alpha1.BareMetalHostSpec{
-					HardwareProfile: "unknown",
-				},
-				Status: metal3v1alpha1.BareMetalHostStatus{
-					HardwareProfile: "unknown",
-				},
-			},
-			Dirty: true,
-			Expected: &metal3v1alpha1.RootDeviceHints{
-				DeviceName: "/dev/sda",
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.Scenario, func(t *testing.T) {
-			dirty, err := saveHostProvisioningSettings(&tc.Host)
-			if err != nil {
-				t.Fatal(err)
-			}
-			assert.Equal(t, tc.Dirty, dirty, "dirty flag did not match")
-			assert.Equal(t, tc.Expected, tc.Host.Status.Provisioning.RootDeviceHints)
-		})
-	}
-}
diff --git a/pkg/provisioner/ironic/devicehints/devicehints_test.go b/pkg/provisioner/ironic/devicehints/devicehints_test.go
deleted file mode 100644
index 609f1344..00000000
--- a/pkg/provisioner/ironic/devicehints/devicehints_test.go
+++ /dev/null
@@ -1,157 +0,0 @@
-package devicehints
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-
-	metal3v1alpha1 "github.com/metal3-io/baremetal-operator/pkg/apis/metal3/v1alpha1"
-)
-
-func TestMakeHintMap(t *testing.T) {
-	addressableTrue := true
-	addressableFalse := false
-
-	for _, tc := range []struct {
-		Scenario string
-		Hints    metal3v1alpha1.RootDeviceHints
-		Expected map[string]string
-	}{
-		{
-			Scenario: "device-name",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				DeviceName: "userd_devicename",
-			},
-			Expected: map[string]string{
-				"name": "s== userd_devicename",
-			},
-		},
-		{
-			Scenario: "hctl",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				HCTL: "1:2:3:4",
-			},
-			Expected: map[string]string{
-				"hctl": "s== 1:2:3:4",
-			},
-		},
-		{
-			Scenario: "model",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				Model: "userd_model",
-			},
-			Expected: map[string]string{
-				"model": "<in> userd_model",
-			},
-		},
-		{
-			Scenario: "vendor",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				Vendor: "userd_vendor",
-			},
-			Expected: map[string]string{
-				"vendor": "<in> userd_vendor",
-			},
-		},
-		{
-			Scenario: "serial-number",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				SerialNumber: "userd_serial",
-			},
-			Expected: map[string]string{
-				"serial": "s== userd_serial",
-			},
-		},
-		{
-			Scenario: "min-size",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				MinSizeGigabytes: 40,
-			},
-			Expected: map[string]string{
-				"size": ">= 40",
-			},
-		},
-		{
-			Scenario: "wwn",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				WWN: "userd_wwn",
-			},
-			Expected: map[string]string{
-				"wwn": "s== userd_wwn",
-			},
-		},
-		{
-			Scenario: "wwn-with-extension",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				WWNWithExtension: "userd_with_extension",
-			},
-			Expected: map[string]string{
-				"wwn_with_extension": "s== userd_with_extension",
-			},
-		},
-		{
-			Scenario: "wwn-extension",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				WWNVendorExtension: "userd_vendor_extension",
-			},
-			Expected: map[string]string{
-				"wwn_vendor_extension": "s== userd_vendor_extension",
-			},
-		},
-		{
-			Scenario: "rotational-true",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				Rotational: &addressableTrue,
-			},
-			Expected: map[string]string{
-				"rotational": "true",
-			},
-		},
-		{
-			Scenario: "rotational-false",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				Rotational: &addressableFalse,
-			},
-			Expected: map[string]string{
-				"rotational": "false",
-			},
-		},
-		{
-			Scenario: "everything-bagel",
-			Hints: metal3v1alpha1.RootDeviceHints{
-				DeviceName:         "userd_devicename",
-				HCTL:               "1:2:3:4",
-				Model:              "userd_model",
-				Vendor:             "userd_vendor",
-				SerialNumber:       "userd_serial",
-				MinSizeGigabytes:   40,
-				WWN:                "userd_wwn",
-				WWNWithExtension:   "userd_with_extension",
-				WWNVendorExtension: "userd_vendor_extension",
-				Rotational:         &addressableTrue,
-			},
-			Expected: map[string]string{
-				"name":                 "s== userd_devicename",
-				"hctl":                 "s== 1:2:3:4",
-				"model":                "<in> userd_model",
-				"vendor":               "<in> userd_vendor",
-				"serial":               "s== userd_serial",
-				"size":                 ">= 40",
-				"wwn":                  "s== userd_wwn",
-				"wwn_with_extension":   "s== userd_with_extension",
-				"wwn_vendor_extension": "s== userd_vendor_extension",
-				"rotational":           "true",
-			},
-		},
-		{
-			Scenario: "empty",
-			Hints:    metal3v1alpha1.RootDeviceHints{},
-			Expected: map[string]string{},
-		},
-	} {
-		t.Run(tc.Scenario, func(t *testing.T) {
-			actual := MakeHintMap(&tc.Hints)
-			assert.Equal(t, tc.Expected, actual, "hint map does not match")
-		})
-	}
-}
diff --git a/pkg/provisioner/ironic/ironic_test.go b/pkg/provisioner/ironic/ironic_test.go
index e26ac1ad..d172f9a2 100644
--- a/pkg/provisioner/ironic/ironic_test.go
+++ b/pkg/provisioner/ironic/ironic_test.go
@@ -1,11 +1,8 @@
 package ironic
 
 import (
-	"fmt"
 	"testing"
 
-	"github.com/stretchr/testify/assert"
-
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
 
@@ -20,114 +17,6 @@ func init() {
 	logf.SetLogger(logf.ZapLogger(true))
 }
 
-func TestGetUpdateOptsForNodeWithRootHints(t *testing.T) {
-	rotational := true
-	host := &metal3v1alpha1.BareMetalHost{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      "myhost",
-			Namespace: "myns",
-			UID:       "27720611-e5d1-45d3-ba3a-222dcfaa4ca2",
-		},
-		Spec: metal3v1alpha1.BareMetalHostSpec{
-			Image: &metal3v1alpha1.Image{
-				URL: "not-empty",
-			},
-			Online:          true,
-			HardwareProfile: "libvirt",
-			RootDeviceHints: &metal3v1alpha1.RootDeviceHints{
-				DeviceName:         "userd_devicename",
-				HCTL:               "1:2:3:4",
-				Model:              "userd_model",
-				Vendor:             "userd_vendor",
-				SerialNumber:       "userd_serial",
-				MinSizeGigabytes:   40,
-				WWN:                "userd_wwn",
-				WWNWithExtension:   "userd_with_extension",
-				WWNVendorExtension: "userd_vendor_extension",
-				Rotational:         &rotational,
-			},
-		},
-		Status: metal3v1alpha1.BareMetalHostStatus{
-			Provisioning: metal3v1alpha1.ProvisionStatus{
-				ID: "provisioning-id",
-				// Place the hints in the status field to pretend the
-				// controller has already reconciled partially.
-				RootDeviceHints: &metal3v1alpha1.RootDeviceHints{
-					DeviceName:         "userd_devicename",
-					HCTL:               "1:2:3:4",
-					Model:              "userd_model",
-					Vendor:             "userd_vendor",
-					SerialNumber:       "userd_serial",
-					MinSizeGigabytes:   40,
-					WWN:                "userd_wwn",
-					WWNWithExtension:   "userd_with_extension",
-					WWNVendorExtension: "userd_vendor_extension",
-					Rotational:         &rotational,
-				},
-			},
-			HardwareProfile: "libvirt",
-		},
-	}
-
-	eventPublisher := func(reason, message string) {}
-
-	prov, err := newProvisioner(host, bmc.Credentials{}, eventPublisher)
-	ironicNode := &nodes.Node{}
-
-	patches, err := prov.getUpdateOptsForNode(ironicNode)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	t.Logf("patches: %v", patches)
-
-	expected := []struct {
-		Path  string            // the node property path
-		Map   map[string]string // Expected roothdevicehint map
-		Value interface{}       // the value being passed to ironic (or value associated with the key)
-	}{
-		{
-			Path:  "/properties/root_device",
-			Value: "userdefined_devicename",
-			Map: map[string]string{
-				"name":                 "s== userd_devicename",
-				"hctl":                 "s== 1:2:3:4",
-				"model":                "<in> userd_model",
-				"vendor":               "<in> userd_vendor",
-				"serial":               "s== userd_serial",
-				"size":                 ">= 40",
-				"wwn":                  "s== userd_wwn",
-				"wwn_with_extension":   "s== userd_with_extension",
-				"wwn_vendor_extension": "s== userd_vendor_extension",
-				"rotational":           "true",
-			},
-		},
-	}
-
-	for _, e := range expected {
-		t.Run(e.Path, func(t *testing.T) {
-			t.Logf("expected: %v", e)
-			var update nodes.UpdateOperation
-			for _, patch := range patches {
-				update = patch.(nodes.UpdateOperation)
-				if update.Path == e.Path {
-					break
-				}
-			}
-			if update.Path != e.Path {
-				t.Errorf("did not find %q in updates", e.Path)
-				return
-			}
-			t.Logf("update: %v", update)
-			if e.Map != nil {
-				assert.Equal(t, e.Map, update.Value, fmt.Sprintf("%s does not match", e.Path))
-			} else {
-				assert.Equal(t, e.Value, update.Value, fmt.Sprintf("%s does not match", e.Path))
-			}
-		})
-	}
-}
-
 func TestGetUpdateOptsForNodeVirtual(t *testing.T) {
 	host := &metal3v1alpha1.BareMetalHost{
 		ObjectMeta: metav1.ObjectMeta{
@@ -164,6 +53,8 @@ func TestGetUpdateOptsForNodeVirtual(t *testing.T) {
 
 	t.Logf("patches: %v", patches)
 
+	var update nodes.UpdateOperation
+
 	expected := []struct {
 		Path  string      // the node property path
 		Key   string      // if value is a map, the key we care about
@@ -193,6 +84,11 @@ func TestGetUpdateOptsForNodeVirtual(t *testing.T) {
 			Path:  "/instance_info/root_gb",
 			Value: 10,
 		},
+		{
+			Path:  "/instance_info/root_device",
+			Value: "/dev/vda",
+			Key:   "name",
+		},
 		{
 			Path:  "/properties/cpu_arch",
 			Value: "x86_64",
@@ -203,23 +99,18 @@ func TestGetUpdateOptsForNodeVirtual(t *testing.T) {
 		},
 	}
 
-	for _, e := range expected {
-		t.Run(e.Path, func(t *testing.T) {
-			t.Logf("expected: %v", e)
-			var update nodes.UpdateOperation
-			for _, patch := range patches {
-				update = patch.(nodes.UpdateOperation)
-				if update.Path == e.Path {
-					break
-				}
+	for i, e := range expected {
+		update = patches[i].(nodes.UpdateOperation)
+		if e.Key != "" {
+			m := update.Value.(map[string]string)
+			if m[e.Key] != e.Value {
+				t.Errorf("expected %s=%q got %s=%q", e.Path, e.Value, update.Path, update.Value)
 			}
-			if update.Path != e.Path {
-				t.Errorf("did not find %q in updates", e.Path)
-				return
+		} else {
+			if update.Value != e.Value {
+				t.Errorf("expected %s=%q got %s=%q", e.Path, e.Value, update.Path, update.Value)
 			}
-			t.Logf("update: %v", update)
-			assert.Equal(t, e.Value, update.Value, fmt.Sprintf("%s does not match", e.Path))
-		})
+		}
 	}
 }
 
@@ -259,6 +150,8 @@ func TestGetUpdateOptsForNodeDell(t *testing.T) {
 
 	t.Logf("patches: %v", patches)
 
+	var update nodes.UpdateOperation
+
 	expected := []struct {
 		Path  string      // the node property path
 		Key   string      // if value is a map, the key we care about
@@ -284,6 +177,11 @@ func TestGetUpdateOptsForNodeDell(t *testing.T) {
 			Path:  "/instance_info/root_gb",
 			Value: 10,
 		},
+		{
+			Path:  "/instance_info/root_device",
+			Value: "0:0:0:0",
+			Key:   "hctl",
+		},
 		{
 			Path:  "/properties/cpu_arch",
 			Value: "x86_64",
@@ -294,22 +192,17 @@ func TestGetUpdateOptsForNodeDell(t *testing.T) {
 		},
 	}
 
-	for _, e := range expected {
-		t.Run(e.Path, func(t *testing.T) {
-			t.Logf("expected: %v", e)
-			var update nodes.UpdateOperation
-			for _, patch := range patches {
-				update = patch.(nodes.UpdateOperation)
-				if update.Path == e.Path {
-					break
-				}
+	for i, e := range expected {
+		update = patches[i].(nodes.UpdateOperation)
+		if e.Key != "" {
+			m := update.Value.(map[string]string)
+			if m[e.Key] != e.Value {
+				t.Errorf("expected %s=%q got %s=%q", e.Path, e.Value, update.Path, update.Value)
 			}
-			if update.Path != e.Path {
-				t.Errorf("did not find %q in updates", e.Path)
-				return
+		} else {
+			if update.Value != e.Value {
+				t.Errorf("expected %s=%q got %s=%q", e.Path, e.Value, update.Path, update.Value)
 			}
-			t.Logf("update: %v", update)
-			assert.Equal(t, e.Value, update.Value, fmt.Sprintf("%s does not match", e.Path))
-		})
+		}
 	}
 }