Repository: metal3-io/baremetal-operator
Pull request #401 (2020-01-23 02:08:34)

Expand image checksum support
The BareMetalHost.Spec currently supports providing a checksum for the image to be provisioned as either a string or URL. But at the moment, the checksum defaults to md5 only. This PR supports other types of checksums such as sha256, etc.

The BareMetalHost.Spec's checksum string value is expanded to specify other checksum algorithms and its value in the form of: "sha256:abcdef...", "md5:xyzabc...", etc

Address #148

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

This pull-request has been approved by: *<a href="https://github.com/metal3-io/baremetal-operator/pull/401#" title="Author self-approved">kirankt</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **russellb**
You can assign the PR to them by writing `/assign @russellb` in a comment when ready.

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

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

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

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["russellb"]} -->
metal3-io-bot: Hi @kirankt. Thanks for your PR.

I'm waiting for a [metal3-io](https://github.com/orgs/metal3-io/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://github.com/orgs/metal3-io/people) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=metal3-io%2Fbaremetal-operator).

<details>

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>

hardys: /ok-to-test
hardys: /test-integration
zaneb: /approve
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/401#" title="Author self-approved">kirankt</a>*, *<a href="https://github.com/metal3-io/baremetal-operator/pull/401#issuecomment-577751925" title="Approved">zaneb</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)~~ [zaneb]

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: @kirankt: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
markdownlint | 08c8e6346216c094c036dac5c1b067db9d89acab | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/markdownlint/1220732634271846402) | `/test markdownlint`



<details>

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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
kirankt: I need your input for the following items:

1. What are your thoughts regarding adding a dedicated checkum algo field in spec.image. Having image.url, image.hash_algo and image.hash_value makes validation simpler while using image.checksum is tricky.

2. Is the value of image.checksum is just a hash or an URL or both. Ironic docs don't mention URL but the BMO doc does.
zaneb: 1. I am in favour of a separate field for the algorithm type.
2. It can be either a checksum or a URL to a checksum. The latter capability was added in Ironic only relatively recently; prior to that we were downloading the URL here in the BMO.
metal3-io-bot: @kirankt: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
unit | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/unit/1245464150302265344) | `/test unit`



<details>

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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
metal3-io-bot: @kirankt: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
unit | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/unit/1245464150302265344) | `/test unit`
govet | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/govet/1245464150302265345) | `/test govet`



<details>

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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
metal3-io-bot: @kirankt: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
unit | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/unit/1245464150302265344) | `/test unit`
govet | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/govet/1245464150302265345) | `/test govet`
gosec | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/gosec/1245464150302265346) | `/test gosec`



<details>

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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
metal3-io-bot: @kirankt: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
unit | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/unit/1245464150302265344) | `/test unit`
govet | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/govet/1245464150302265345) | `/test govet`
gosec | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/gosec/1245464150302265346) | `/test gosec`
gofmt | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/gofmt/1245464150302265347) | `/test gofmt`



<details>

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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
metal3-io-bot: @kirankt: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
unit | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/unit/1245464150302265344) | `/test unit`
govet | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/govet/1245464150302265345) | `/test govet`
gosec | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/gosec/1245464150302265346) | `/test gosec`
gofmt | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/gofmt/1245464150302265347) | `/test gofmt`
markdownlint | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/markdownlint/1245464150302265348) | `/test markdownlint`



<details>

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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
metal3-io-bot: @kirankt: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
unit | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/unit/1245464150302265344) | `/test unit`
govet | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/govet/1245464150302265345) | `/test govet`
gosec | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/gosec/1245464150302265346) | `/test gosec`
gofmt | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/gofmt/1245464150302265347) | `/test gofmt`
markdownlint | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/markdownlint/1245464150302265348) | `/test markdownlint`
shellcheck | a6ee995fe75fc7a21a0ff9e711cecb15bb0b248b | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/shellcheck/1245464150302265349) | `/test shellcheck`



<details>

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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
kirankt: @dhellmann Would you mind taking another look at this PR, please?
metal3-io-bot: @kirankt: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gofmt | a02b93a4f8b2864922df039b8781a8af8ce240e7 | [link](https://prow.apps.ci.metal3.io/view/gcs/metal3-prow-artifacts/pr-logs/pull/metal3-io_baremetal-operator/401/gofmt/1257369074833297413) | `/test gofmt`



<details>

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. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
zaneb: /approve
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/401#" title="Author self-approved">kirankt</a>*, *<a href="https://github.com/metal3-io/baremetal-operator/pull/401#issuecomment-623706793" title="Approved">zaneb</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)~~ [zaneb]

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":[]} -->

Patch:
diff --git a/deploy/crds/metal3.io_baremetalhosts_crd.yaml b/deploy/crds/metal3.io_baremetalhosts_crd.yaml
index e25a9996..b3b4b390 100644
--- a/deploy/crds/metal3.io_baremetalhosts_crd.yaml
+++ b/deploy/crds/metal3.io_baremetalhosts_crd.yaml
@@ -149,6 +149,14 @@ spec:
                 checksum:
                   description: Checksum is the checksum for the image.
                   type: string
+                checksumType:
+                  description: ChecksumType is the checksum algorithm for the image.
+                    e.g md5, sha256, sha512
+                  enum:
+                  - md5
+                  - sha256
+                  - sha512
+                  type: string
                 url:
                   description: URL is a location of an image to deploy.
                   type: string
@@ -530,6 +538,14 @@ spec:
                     checksum:
                       description: Checksum is the checksum for the image.
                       type: string
+                    checksumType:
+                      description: ChecksumType is the checksum algorithm for the
+                        image. e.g md5, sha256, sha512
+                      enum:
+                      - md5
+                      - sha256
+                      - sha512
+                      type: string
                     url:
                       description: URL is a location of an image to deploy.
                       type: string
diff --git a/docs/api.md b/docs/api.md
index 382c22e9..b92c75c6 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -73,6 +73,9 @@ mainly, but not only, provisioning details.
   * *url* -- The URL of an image to deploy to the host.
   * *checksum* -- The actual checksum or a URL to a file containing
     the checksum for the image at *image.url*.
+  * *checksumType* -- Checksum algorithms can be specified. Currently
+    only `md5`, `sha256`, `sha512` are recognized. If nothing is specified
+    `md5` is assumed.
 
 * *userData* -- A reference to the Secret containing the cloudinit user data
   and its namespace, so it can be attached to the host before it boots
diff --git a/go.mod b/go.mod
index d5d51808..a72aa878 100644
--- a/go.mod
+++ b/go.mod
@@ -20,7 +20,7 @@ require (
 	golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
 	golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
 	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
-	golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 // indirect
+	golang.org/x/tools v0.0.0-20200430192856-2840dafb9ee1 // indirect
 	k8s.io/api v0.17.4
 	k8s.io/apimachinery v0.17.4
 	k8s.io/client-go v12.0.0+incompatible
diff --git a/go.sum b/go.sum
index 2cdb7990..22bf7ac5 100644
--- a/go.sum
+++ b/go.sum
@@ -1090,6 +1090,8 @@ golang.org/x/tools v0.0.0-20200417140056-c07e33ef3290 h1:NXNmtp0ToD36cui5IqWy95L
 golang.org/x/tools v0.0.0-20200417140056-c07e33ef3290/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 h1:Xvf3ZQTm5bjXPxhI7g+dwqsCqadK1rcNtwtszuatetk=
 golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200430192856-2840dafb9ee1 h1:OlmCHPqCyX+EpIpxG55cfMJuINAFd7HHTdWwA3yyelQ=
+golang.org/x/tools v0.0.0-20200430192856-2840dafb9ee1/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
diff --git a/pkg/apis/metal3/v1alpha1/baremetalhost_types.go b/pkg/apis/metal3/v1alpha1/baremetalhost_types.go
index 1d7f62b7..138f3054 100644
--- a/pkg/apis/metal3/v1alpha1/baremetalhost_types.go
+++ b/pkg/apis/metal3/v1alpha1/baremetalhost_types.go
@@ -201,6 +201,21 @@ type BareMetalHostSpec struct {
 	ExternallyProvisioned bool `json:"externallyProvisioned,omitempty"`
 }
 
+// Checksum Algorithm Type
+// +kubebuilder:validation:Enum=md5;sha256;sha512
+type ChecksumType string
+
+const (
+	// MD5 checksum type
+	MD5 ChecksumType = "md5"
+
+	// SHA256 checksum type
+	SHA256 ChecksumType = "sha256"
+
+	// SHA512 checksum type
+	SHA512 ChecksumType = "sha512"
+)
+
 // Image holds the details of an image either to provisioned or that
 // has been provisioned.
 type Image struct {
@@ -209,6 +224,10 @@ type Image struct {
 
 	// Checksum is the checksum for the image.
 	Checksum string `json:"checksum"`
+
+	// ChecksumType is the checksum algorithm for the image.
+	// e.g md5, sha256, sha512
+	ChecksumType ChecksumType `json:"checksumType,omitempty"`
 }
 
 // FIXME(dhellmann): We probably want some other module to own these
@@ -747,6 +766,27 @@ func (host *BareMetalHost) OperationMetricForState(operation ProvisioningState)
 	return
 }
 
+// GetImageChecksum returns the hash value and its algo.
+func (host *BareMetalHost) GetImageChecksum() (string, string, bool) {
+	checksum := host.Spec.Image.Checksum
+	checksumType := host.Spec.Image.ChecksumType
+
+	if checksum == "" {
+		// Return empty if checksum is not provided
+		return "", "", false
+	}
+	if checksumType == "" {
+		// If only checksum is specified. Assume type is md5
+		return checksum, string(MD5), true
+	}
+	switch checksumType {
+	case MD5, SHA256, SHA512:
+		return checksum, string(checksumType), true
+	default:
+		return "", "", false
+	}
+}
+
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
 // BareMetalHostList contains a list of BareMetalHost
diff --git a/pkg/provisioner/ironic/ironic.go b/pkg/provisioner/ironic/ironic.go
index 761fda5b..ecc3c271 100644
--- a/pkg/provisioner/ironic/ironic.go
+++ b/pkg/provisioner/ironic/ironic.go
@@ -279,12 +279,13 @@ func (p *ironicProvisioner) ValidateManagementAccess(credentialsChanged bool) (r
 			}
 		}
 
-		if p.host.Spec.Image != nil && p.host.Spec.Image.URL != "" {
-			checksum := p.host.Spec.Image.Checksum
+		checksum, checksumType, ok := p.host.GetImageChecksum()
 
+		if ok {
 			p.log.Info("setting instance info",
 				"image_source", p.host.Spec.Image.URL,
-				"checksum", checksum,
+				"image_os_hash_value", checksum,
+				"image_os_hash_algo", checksumType,
 			)
 
 			updates := nodes.UpdateOpts{
@@ -295,9 +296,14 @@ func (p *ironicProvisioner) ValidateManagementAccess(credentialsChanged bool) (r
 				},
 				nodes.UpdateOperation{
 					Op:    nodes.AddOp,
-					Path:  "/instance_info/image_checksum",
+					Path:  "/instance_info/image_os_hash_value",
 					Value: checksum,
 				},
+				nodes.UpdateOperation{
+					Op:    nodes.AddOp,
+					Path:  "/instance_info/image_os_hash_algo",
+					Value: checksumType,
+				},
 				nodes.UpdateOperation{
 					Op:    nodes.ReplaceOp,
 					Path:  "/instance_uuid",
@@ -676,7 +682,7 @@ func (p *ironicProvisioner) UpdateHardwareState() (result provisioner.Result, er
 	return result, nil
 }
 
-func (p *ironicProvisioner) getUpdateOptsForNode(ironicNode *nodes.Node, checksum string) (updates nodes.UpdateOpts, err error) {
+func (p *ironicProvisioner) getUpdateOptsForNode(ironicNode *nodes.Node) (updates nodes.UpdateOpts, err error) {
 
 	hwProf, err := hardware.GetProfile(p.host.HardwareProfile())
 	if err != nil {
@@ -703,19 +709,38 @@ func (p *ironicProvisioner) getUpdateOptsForNode(ironicNode *nodes.Node, checksu
 		},
 	)
 
-	// image_checksum
-	if _, ok := ironicNode.InstanceInfo["image_checksum"]; !ok {
+	checksum, checksumType, _ := p.host.GetImageChecksum()
+
+	// image_os_hash_algo
+	if _, ok := ironicNode.InstanceInfo["image_os_hash_algo"]; !ok {
+		op = nodes.AddOp
+		p.log.Info("adding image_os_hash_algo")
+	} else {
+		op = nodes.ReplaceOp
+		p.log.Info("updating image_os_hash_algo")
+	}
+	updates = append(
+		updates,
+		nodes.UpdateOperation{
+			Op:    op,
+			Path:  "/instance_info/image_os_hash_algo",
+			Value: checksumType,
+		},
+	)
+
+	// image_os_hash_value
+	if _, ok := ironicNode.InstanceInfo["image_os_hash_value"]; !ok {
 		op = nodes.AddOp
-		p.log.Info("adding image_checksum")
+		p.log.Info("adding image_os_hash_value")
 	} else {
 		op = nodes.ReplaceOp
-		p.log.Info("updating image_checksum")
+		p.log.Info("updating image_os_hash_value")
 	}
 	updates = append(
 		updates,
 		nodes.UpdateOperation{
 			Op:    op,
-			Path:  "/instance_info/image_checksum",
+			Path:  "/instance_info/image_os_hash_value",
 			Value: checksum,
 		},
 	)
@@ -822,11 +847,11 @@ func (p *ironicProvisioner) getUpdateOptsForNode(ironicNode *nodes.Node, checksu
 	return updates, nil
 }
 
-func (p *ironicProvisioner) startProvisioning(ironicNode *nodes.Node, checksum string, hostConf provisioner.HostConfigData) (result provisioner.Result, err error) {
+func (p *ironicProvisioner) startProvisioning(ironicNode *nodes.Node, hostConf provisioner.HostConfigData) (result provisioner.Result, err error) {
 
 	p.log.Info("starting provisioning")
 
-	updates, err := p.getUpdateOptsForNode(ironicNode, checksum)
+	updates, err := p.getUpdateOptsForNode(ironicNode)
 	_, err = nodes.Update(p.client, ironicNode.UUID, updates).Extract()
 	switch err.(type) {
 	case nil:
@@ -933,16 +958,18 @@ func (p *ironicProvisioner) Provision(hostConf provisioner.HostConfigData) (resu
 
 	p.log.Info("provisioning image to host", "state", ironicNode.ProvisionState)
 
-	checksum := p.host.Spec.Image.Checksum
+	checksum, checksumType, _ := p.host.GetImageChecksum()
 
 	// Local variable to make it easier to test if ironic is
 	// configured with the same image we are trying to provision to
 	// the host.
 	ironicHasSameImage := (ironicNode.InstanceInfo["image_source"] == p.host.Spec.Image.URL &&
-		ironicNode.InstanceInfo["image_checksum"] == checksum)
+		ironicNode.InstanceInfo["image_os_hash_algo"] == checksumType &&
+		ironicNode.InstanceInfo["image_os_hash_value"] == checksum)
 	p.log.Info("checking image settings",
 		"source", ironicNode.InstanceInfo["image_source"],
-		"checksum", checksum,
+		"image_os_hash_algo", checksumType,
+		"image_os_has_value", checksum,
 		"same", ironicHasSameImage,
 		"provisionState", ironicNode.ProvisionState)
 
@@ -971,10 +998,10 @@ func (p *ironicProvisioner) Provision(hostConf provisioner.HostConfigData) (resu
 			return result, nil
 		}
 		p.log.Info("recovering from previous failure")
-		return p.startProvisioning(ironicNode, checksum, hostConf)
+		return p.startProvisioning(ironicNode, hostConf)
 
 	case nodes.Manageable:
-		return p.startProvisioning(ironicNode, checksum, hostConf)
+		return p.startProvisioning(ironicNode, hostConf)
 
 	case nodes.Available:
 		// After it is available, we need to start provisioning by
diff --git a/tools/run_local_ironic.sh b/tools/run_local_ironic.sh
index 124835a6..27e7e5e1 100755
--- a/tools/run_local_ironic.sh
+++ b/tools/run_local_ironic.sh
@@ -81,10 +81,6 @@ sudo "${CONTAINER_RUNTIME}" run -d --net host --privileged --name ironic \
      --env "MARIADB_PASSWORD=$mariadb_password" \
      -v "$IRONIC_DATA_DIR:/shared" "${IRONIC_IMAGE}"
 
-# Let Ironic start properly before starting inspector, to avoid inspector
-# failing to start properly because ironic is not ready
-sleep 30
-
 # Start Ironic Inspector
 # shellcheck disable=SC2086
 sudo "${CONTAINER_RUNTIME}" run -d --net host --privileged --name ironic-inspector \


Test patch:
diff --git a/pkg/apis/metal3/v1alpha1/baremetalhost_types_test.go b/pkg/apis/metal3/v1alpha1/baremetalhost_types_test.go
index 9037fd95..127bd173 100644
--- a/pkg/apis/metal3/v1alpha1/baremetalhost_types_test.go
+++ b/pkg/apis/metal3/v1alpha1/baremetalhost_types_test.go
@@ -529,3 +529,128 @@ func TestCredentialStatusMatch(t *testing.T) {
 		})
 	}
 }
+
+func TestGetImageChecksum(t *testing.T) {
+	for _, tc := range []struct {
+		Scenario string
+		Host     BareMetalHost
+		Expected bool
+	}{
+		{
+			Scenario: "both checksum value and type specified",
+			Host: BareMetalHost{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "myhost",
+					Namespace: "myns",
+				},
+				Spec: BareMetalHostSpec{
+					Image: &Image{
+						Checksum:     "md5hash",
+						ChecksumType: MD5,
+					},
+				},
+			},
+			Expected: true,
+		},
+		{
+			Scenario: "checksum value specified but not type",
+			Host: BareMetalHost{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "myhost",
+					Namespace: "myns",
+				},
+				Spec: BareMetalHostSpec{
+					Image: &Image{
+						Checksum: "md5hash",
+					},
+				},
+			},
+			Expected: true,
+		},
+		{
+			Scenario: "sha256 checksum value and type specified",
+			Host: BareMetalHost{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "myhost",
+					Namespace: "myns",
+				},
+				Spec: BareMetalHostSpec{
+					Image: &Image{
+						Checksum:     "sha256hash",
+						ChecksumType: SHA256,
+					},
+				},
+			},
+			Expected: true,
+		},
+		{
+			Scenario: "sha512 checksum value and type specified",
+			Host: BareMetalHost{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "myhost",
+					Namespace: "myns",
+				},
+				Spec: BareMetalHostSpec{
+					Image: &Image{
+						Checksum:     "sha512hash",
+						ChecksumType: SHA512,
+					},
+				},
+			},
+			Expected: true,
+		},
+		{
+			Scenario: "checksum value not specified",
+			Host: BareMetalHost{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "myhost",
+					Namespace: "myns",
+				},
+				Spec: BareMetalHostSpec{
+					Image: &Image{
+						ChecksumType: SHA512,
+					},
+				},
+			},
+			Expected: false,
+		},
+		{
+			Scenario: "neither checksum value nor hash specified",
+			Host: BareMetalHost{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "myhost",
+					Namespace: "myns",
+				},
+				Spec: BareMetalHostSpec{
+					Image: &Image{
+						URL: "someurl",
+					},
+				},
+			},
+			Expected: false,
+		},
+		{
+			Scenario: "wrong checksum hash specified",
+			Host: BareMetalHost{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "myhost",
+					Namespace: "myns",
+				},
+				Spec: BareMetalHostSpec{
+					Image: &Image{
+						Checksum:     "somehash",
+						ChecksumType: "boondoggle",
+					},
+				},
+			},
+			Expected: false,
+		},
+	} {
+		t.Run(tc.Scenario, func(t *testing.T) {
+			_, _, actual := tc.Host.GetImageChecksum()
+			if actual != tc.Expected {
+				t.Errorf("expected %v but got %v", tc.Expected, actual)
+			}
+		})
+	}
+}
diff --git a/pkg/provisioner/ironic/ironic_test.go b/pkg/provisioner/ironic/ironic_test.go
index 556a5f6c..98254973 100644
--- a/pkg/provisioner/ironic/ironic_test.go
+++ b/pkg/provisioner/ironic/ironic_test.go
@@ -27,7 +27,9 @@ func TestGetUpdateOptsForNodeVirtual(t *testing.T) {
 		},
 		Spec: metal3v1alpha1.BareMetalHostSpec{
 			Image: &metal3v1alpha1.Image{
-				URL: "not-empty",
+				URL:          "not-empty",
+				Checksum:     "checksum",
+				ChecksumType: metal3v1alpha1.MD5,
 			},
 			Online: true,
 		},
@@ -44,7 +46,7 @@ func TestGetUpdateOptsForNodeVirtual(t *testing.T) {
 	prov, err := newProvisioner(host, bmc.Credentials{}, eventPublisher)
 	ironicNode := &nodes.Node{}
 
-	patches, err := prov.getUpdateOptsForNode(ironicNode, "checksum")
+	patches, err := prov.getUpdateOptsForNode(ironicNode)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -63,7 +65,11 @@ func TestGetUpdateOptsForNodeVirtual(t *testing.T) {
 			Value: "not-empty",
 		},
 		{
-			Path:  "/instance_info/image_checksum",
+			Path:  "/instance_info/image_os_hash_algo",
+			Value: "md5",
+		},
+		{
+			Path:  "/instance_info/image_os_hash_value",
 			Value: "checksum",
 		},
 		{
@@ -113,7 +119,9 @@ func TestGetUpdateOptsForNodeDell(t *testing.T) {
 		},
 		Spec: metal3v1alpha1.BareMetalHostSpec{
 			Image: &metal3v1alpha1.Image{
-				URL: "not-empty",
+				URL:          "not-empty",
+				Checksum:     "checksum",
+				ChecksumType: metal3v1alpha1.MD5,
 			},
 			Online: true,
 		},
@@ -130,7 +138,7 @@ func TestGetUpdateOptsForNodeDell(t *testing.T) {
 	prov, err := newProvisioner(host, bmc.Credentials{}, eventPublisher)
 	ironicNode := &nodes.Node{}
 
-	patches, err := prov.getUpdateOptsForNode(ironicNode, "checksum")
+	patches, err := prov.getUpdateOptsForNode(ironicNode)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -149,7 +157,11 @@ func TestGetUpdateOptsForNodeDell(t *testing.T) {
 			Value: "not-empty",
 		},
 		{
-			Path:  "/instance_info/image_checksum",
+			Path:  "/instance_info/image_os_hash_algo",
+			Value: "md5",
+		},
+		{
+			Path:  "/instance_info/image_os_hash_value",
 			Value: "checksum",
 		},
 		{