Repository: metal3-io/baremetal-operator
Pull request #1441 (2023-11-10 16:21:24)

✨ Expose  FirmwareInterface in Node/BMC
Ironic introduced a new interface called Firmware Interface This commit aims to addapt existing code to support creating nodes with the new field.

- Rename "firmwareUpgrades" to "firmwareUpdates", since this
  can be used for upgrades and downgrades.
- gophercloud updated to a newer version
* go get -v github.com/gophercloud/gophercloud@master
* go mod tidy
- All BMCs have now FirmwareInterface() with default values
- Ironic provisioner updated to receive FirmwareInterface when creating a node


**What this PR does / why we need it**:
Exposes the firmware interface field that was introduced in ironic and will help in future work of  metal3-io/metal3-docs#364


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

This pull-request has been approved by:
**Once this PR has been reviewed and has the lgtm label**, please assign [dtantsur](https://github.com/dtantsur) for approval. For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

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/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["dtantsur"]} -->
iurygregory: /test-centos-e2e-integration-main
/test-ubuntu-integration-main
iurygregory: /test-centos-e2e-integration-main
iurygregory: /test-centos-e2e-integration-main
iurygregory: /test-ubuntu-integration-main
metal3-io-bot: @iurygregory: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
golint | 325b5fcc1531e5a3017e83abe2bdea9633bdfbd1 | [link](https://prow.apps.test.metal3.io/view/s3/prow-logs/pr-logs/pull/metal3-io_baremetal-operator/1441/golint/1726936954206949376) | true | `/test golint`

[Full PR test history](https://prow.apps.test.metal3.io/pr-history?org=metal3-io&repo=baremetal-operator&pr=1441). [Your PR dashboard](https://prow.apps.test.metal3.io/pr?query=is:pr+state:open+author:iurygregory).

<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 -->
iurygregory: /test golint
Seems like a timeout from the logs
iurygregory: /test-centos-e2e-integration-main
/test-ubuntu-integration-main
iurygregory: /retest
to trigger another run for E2E Fixture Test
iurygregory: /test-centos-e2e-integration-main
/test-ubuntu-integration-main
iurygregory: /test-centos-e2e-integration-main
/test-ubuntu-integration-main

Patch:
diff --git a/go.mod b/go.mod
index c4b8dfba..69f0b396 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.20
 require (
 	github.com/go-logr/logr v1.3.0
 	github.com/google/safetext v0.0.0-20230106111101-7156a760e523
-	github.com/gophercloud/gophercloud v1.5.1-0.20231106162611-af1813efe0d1
+	github.com/gophercloud/gophercloud v1.5.1-0.20231117122435-08456f7fe42e
 	github.com/metal3-io/baremetal-operator/apis v0.4.0
 	github.com/metal3-io/baremetal-operator/pkg/hardwareutils v0.4.0
 	github.com/onsi/gomega v1.30.0
@@ -62,7 +62,7 @@ require (
 	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
 	golang.org/x/net v0.17.0 // indirect
 	golang.org/x/oauth2 v0.8.0 // indirect
-	golang.org/x/sys v0.13.0 // indirect
+	golang.org/x/sys v0.14.0 // indirect
 	golang.org/x/term v0.13.0 // indirect
 	golang.org/x/text v0.13.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
diff --git a/go.sum b/go.sum
index 6571f6ed..c470351e 100644
--- a/go.sum
+++ b/go.sum
@@ -73,8 +73,8 @@ github.com/google/safetext v0.0.0-20230106111101-7156a760e523 h1:i4NsbmB9pD5+Ggp
 github.com/google/safetext v0.0.0-20230106111101-7156a760e523/go.mod h1:mJNEy0r5YPHC7ChQffpOszlGB4L1iqjXWpIEKcFpr9s=
 github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
 github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gophercloud/gophercloud v1.5.1-0.20231106162611-af1813efe0d1 h1:4crYiUFYzhxv60/bsLnyc7esUsOqQl3DgErAGNsOgL8=
-github.com/gophercloud/gophercloud v1.5.1-0.20231106162611-af1813efe0d1/go.mod h1:99P1GdytPKaSR7/ugQJo1dX6th5FlHdXXvKqvRJQfO4=
+github.com/gophercloud/gophercloud v1.5.1-0.20231117122435-08456f7fe42e h1:acHzJUXVfS+GImmi+yyM2+AOiaO94Z4KaTTFVU6Ov9U=
+github.com/gophercloud/gophercloud v1.5.1-0.20231117122435-08456f7fe42e/go.mod h1:ecnaHbFxBunc2UeAONDQbkQacv6WP1syeZ02TgAB7kA=
 github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
 github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
@@ -197,8 +197,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
-golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
+golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
 golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
diff --git a/pkg/hardwareutils/bmc/access.go b/pkg/hardwareutils/bmc/access.go
index 960b9eff..f00770f6 100644
--- a/pkg/hardwareutils/bmc/access.go
+++ b/pkg/hardwareutils/bmc/access.go
@@ -74,6 +74,9 @@ type AccessDetails interface {
 	RAIDInterface() string
 	VendorInterface() string
 
+	// Firmware interface to set
+	FirmwareInterface() string
+
 	// Whether the driver supports changing secure boot state.
 	SupportsSecureBoot() bool
 
diff --git a/pkg/hardwareutils/bmc/ibmc.go b/pkg/hardwareutils/bmc/ibmc.go
index 7cb4b9af..01e85d8d 100644
--- a/pkg/hardwareutils/bmc/ibmc.go
+++ b/pkg/hardwareutils/bmc/ibmc.go
@@ -87,6 +87,10 @@ func (a *ibmcAccessDetails) BootInterface() string {
 	return "ipxe"
 }
 
+func (a *ibmcAccessDetails) FirmwareInterface() string {
+	return ""
+}
+
 func (a *ibmcAccessDetails) ManagementInterface() string {
 	return "ibmc"
 }
diff --git a/pkg/hardwareutils/bmc/idrac.go b/pkg/hardwareutils/bmc/idrac.go
index b7b8cb84..bddc0267 100644
--- a/pkg/hardwareutils/bmc/idrac.go
+++ b/pkg/hardwareutils/bmc/idrac.go
@@ -82,6 +82,10 @@ func (a *iDracAccessDetails) BootInterface() string {
 	return "ipxe"
 }
 
+func (a *iDracAccessDetails) FirmwareInterface() string {
+	return ""
+}
+
 func (a *iDracAccessDetails) ManagementInterface() string {
 	return ""
 }
diff --git a/pkg/hardwareutils/bmc/idrac_virtualmedia.go b/pkg/hardwareutils/bmc/idrac_virtualmedia.go
index a30a2a20..79ffa57e 100644
--- a/pkg/hardwareutils/bmc/idrac_virtualmedia.go
+++ b/pkg/hardwareutils/bmc/idrac_virtualmedia.go
@@ -76,6 +76,10 @@ func (a *redfishiDracVirtualMediaAccessDetails) BootInterface() string {
 	return "idrac-redfish-virtual-media"
 }
 
+func (a *redfishiDracVirtualMediaAccessDetails) FirmwareInterface() string {
+	return "redfish"
+}
+
 func (a *redfishiDracVirtualMediaAccessDetails) ManagementInterface() string {
 	return "idrac-redfish"
 }
diff --git a/pkg/hardwareutils/bmc/ilo4.go b/pkg/hardwareutils/bmc/ilo4.go
index bff98bc6..6ccc68b1 100644
--- a/pkg/hardwareutils/bmc/ilo4.go
+++ b/pkg/hardwareutils/bmc/ilo4.go
@@ -94,6 +94,10 @@ func (a *iLOAccessDetails) BootInterface() string {
 	}
 }
 
+func (a *iLOAccessDetails) FirmwareInterface() string {
+	return ""
+}
+
 func (a *iLOAccessDetails) ManagementInterface() string {
 	return ""
 }
diff --git a/pkg/hardwareutils/bmc/ilo5.go b/pkg/hardwareutils/bmc/ilo5.go
index 2cfbee1f..e79bf442 100644
--- a/pkg/hardwareutils/bmc/ilo5.go
+++ b/pkg/hardwareutils/bmc/ilo5.go
@@ -78,6 +78,10 @@ func (a *iLO5AccessDetails) BootInterface() string {
 	return "ilo-ipxe"
 }
 
+func (a *iLO5AccessDetails) FirmwareInterface() string {
+	return ""
+}
+
 func (a *iLO5AccessDetails) ManagementInterface() string {
 	return ""
 }
diff --git a/pkg/hardwareutils/bmc/ipmi.go b/pkg/hardwareutils/bmc/ipmi.go
index c4a29d00..eb30a35f 100644
--- a/pkg/hardwareutils/bmc/ipmi.go
+++ b/pkg/hardwareutils/bmc/ipmi.go
@@ -97,6 +97,10 @@ func (a *ipmiAccessDetails) BootInterface() string {
 	return "ipxe"
 }
 
+func (a *ipmiAccessDetails) FirmwareInterface() string {
+	return ""
+}
+
 func (a *ipmiAccessDetails) ManagementInterface() string {
 	return ""
 }
diff --git a/pkg/hardwareutils/bmc/irmc.go b/pkg/hardwareutils/bmc/irmc.go
index a9c0b789..f87c7147 100644
--- a/pkg/hardwareutils/bmc/irmc.go
+++ b/pkg/hardwareutils/bmc/irmc.go
@@ -78,6 +78,10 @@ func (a *iRMCAccessDetails) BootInterface() string {
 	return "ipxe"
 }
 
+func (a *iRMCAccessDetails) FirmwareInterface() string {
+	return ""
+}
+
 func (a *iRMCAccessDetails) ManagementInterface() string {
 	return ""
 }
diff --git a/pkg/hardwareutils/bmc/redfish.go b/pkg/hardwareutils/bmc/redfish.go
index 30328189..21222598 100644
--- a/pkg/hardwareutils/bmc/redfish.go
+++ b/pkg/hardwareutils/bmc/redfish.go
@@ -107,6 +107,10 @@ func (a *redfishAccessDetails) BootInterface() string {
 	return "ipxe"
 }
 
+func (a *redfishAccessDetails) FirmwareInterface() string {
+	return "redfish"
+}
+
 func (a *redfishAccessDetails) ManagementInterface() string {
 	return ""
 }
@@ -155,6 +159,10 @@ func (a *redfishiDracAccessDetails) BootInterface() string {
 	return "ipxe"
 }
 
+func (a *redfishiDracAccessDetails) FirmwareInterface() string {
+	return "redfish"
+}
+
 func (a *redfishiDracAccessDetails) ManagementInterface() string {
 	return "idrac-redfish"
 }
diff --git a/pkg/hardwareutils/bmc/redfish_virtualmedia.go b/pkg/hardwareutils/bmc/redfish_virtualmedia.go
index bd319d17..bb66b6f4 100644
--- a/pkg/hardwareutils/bmc/redfish_virtualmedia.go
+++ b/pkg/hardwareutils/bmc/redfish_virtualmedia.go
@@ -75,6 +75,10 @@ func (a *redfishVirtualMediaAccessDetails) BootInterface() string {
 	return "redfish-virtual-media"
 }
 
+func (a *redfishVirtualMediaAccessDetails) FirmwareInterface() string {
+	return "redfish"
+}
+
 func (a *redfishVirtualMediaAccessDetails) ManagementInterface() string {
 	return ""
 }
diff --git a/pkg/provisioner/ironic/clients/features.go b/pkg/provisioner/ironic/clients/features.go
index 46452d65..b98cc65c 100644
--- a/pkg/provisioner/ironic/clients/features.go
+++ b/pkg/provisioner/ironic/clients/features.go
@@ -41,15 +41,15 @@ func (af AvailableFeatures) Log(logger logr.Logger) {
 	logger.Info("supported Ironic API features",
 		"maxVersion", fmt.Sprintf("1.%d", af.MaxVersion),
 		"chosenVersion", af.ChooseMicroversion(),
-		"firmwareUpgrades", af.HasFirmwareUpgrades())
+		"firmwareUpdates", af.HasFirmwareUpdates())
 }
 
-func (af AvailableFeatures) HasFirmwareUpgrades() bool {
+func (af AvailableFeatures) HasFirmwareUpdates() bool {
 	return af.MaxVersion >= 86
 }
 
 func (af AvailableFeatures) ChooseMicroversion() string {
-	if af.HasFirmwareUpgrades() {
+	if af.HasFirmwareUpdates() {
 		return "1.86"
 	}
 
diff --git a/pkg/provisioner/ironic/ironic.go b/pkg/provisioner/ironic/ironic.go
index 6d8d7e21..58eadceb 100644
--- a/pkg/provisioner/ironic/ironic.go
+++ b/pkg/provisioner/ironic/ironic.go
@@ -367,24 +367,28 @@ func (p *ironicProvisioner) ValidateManagementAccess(data provisioner.Management
 			return
 		}
 
-		ironicNode, err = nodes.Create(
-			p.client,
-			nodes.CreateOpts{
-				Driver:              bmcAccess.Driver(),
-				BIOSInterface:       bmcAccess.BIOSInterface(),
-				BootInterface:       bmcAccess.BootInterface(),
-				Name:                ironicNodeName(p.objectMeta),
-				DriverInfo:          driverInfo,
-				DeployInterface:     p.deployInterface(data),
-				InspectInterface:    "inspector",
-				ManagementInterface: bmcAccess.ManagementInterface(),
-				PowerInterface:      bmcAccess.PowerInterface(),
-				RAIDInterface:       bmcAccess.RAIDInterface(),
-				VendorInterface:     bmcAccess.VendorInterface(),
-				Properties: map[string]interface{}{
-					"capabilities": bootModeCapabilities[data.BootMode],
-				},
-			}).Extract()
+		nodeCreateOpts := nodes.CreateOpts{
+			Driver:              bmcAccess.Driver(),
+			BIOSInterface:       bmcAccess.BIOSInterface(),
+			BootInterface:       bmcAccess.BootInterface(),
+			Name:                ironicNodeName(p.objectMeta),
+			DriverInfo:          driverInfo,
+			DeployInterface:     p.deployInterface(data),
+			InspectInterface:    "inspector",
+			ManagementInterface: bmcAccess.ManagementInterface(),
+			PowerInterface:      bmcAccess.PowerInterface(),
+			RAIDInterface:       bmcAccess.RAIDInterface(),
+			VendorInterface:     bmcAccess.VendorInterface(),
+			Properties: map[string]interface{}{
+				"capabilities": bootModeCapabilities[data.BootMode],
+			},
+		}
+
+		if p.availableFeatures.HasFirmwareUpdates() {
+			nodeCreateOpts.FirmwareInterface = bmcAccess.FirmwareInterface()
+		}
+
+		ironicNode, err = nodes.Create(p.client, nodeCreateOpts).Extract()
 		switch err.(type) {
 		case nil:
 			p.publisher("Registered", "Registered new host")


Test patch:
diff --git a/pkg/hardwareutils/bmc/access_test.go b/pkg/hardwareutils/bmc/access_test.go
index b0f5ac1a..2ed2a319 100644
--- a/pkg/hardwareutils/bmc/access_test.go
+++ b/pkg/hardwareutils/bmc/access_test.go
@@ -464,6 +464,7 @@ func TestStaticDriverInfo(t *testing.T) {
 		driver     string
 		bios       string
 		boot       string
+		firmware   string
 		management string
 		power      string
 		vendor     string
@@ -475,6 +476,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "ipmi",
 			bios:       "",
 			boot:       "ipxe",
+			firmware:   "",
 			management: "",
 			power:      "",
 		},
@@ -486,6 +488,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "ipmi",
 			bios:       "",
 			boot:       "ipxe",
+			firmware:   "",
 			management: "",
 			power:      "",
 		},
@@ -497,6 +500,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "idrac",
 			bios:       "",
 			boot:       "ipxe",
+			firmware:   "",
 			management: "",
 			power:      "",
 		},
@@ -508,6 +512,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "irmc",
 			bios:       "",
 			boot:       "ipxe",
+			firmware:   "",
 			management: "",
 			power:      "",
 		},
@@ -519,6 +524,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "redfish",
 			bios:       "",
 			boot:       "ipxe",
+			firmware:   "redfish",
 			management: "",
 			power:      "",
 		},
@@ -530,6 +536,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "redfish",
 			bios:       "",
 			boot:       "redfish-virtual-media",
+			firmware:   "redfish",
 			management: "",
 			power:      "",
 		},
@@ -541,6 +548,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "redfish",
 			bios:       "",
 			boot:       "redfish-virtual-media",
+			firmware:   "redfish",
 			management: "",
 			power:      "",
 		},
@@ -552,6 +560,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "redfish",
 			bios:       "",
 			boot:       "redfish-virtual-media",
+			firmware:   "redfish",
 			management: "",
 			power:      "",
 		},
@@ -563,6 +572,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "idrac",
 			bios:       "idrac-redfish",
 			boot:       "ipxe",
+			firmware:   "redfish",
 			management: "idrac-redfish",
 			power:      "idrac-redfish",
 			vendor:     "idrac-redfish",
@@ -575,6 +585,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:   "redfish",
 			bios:     "",
 			boot:     "redfish-virtual-media",
+			firmware: "redfish",
 		},
 
 		{
@@ -584,6 +595,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:   "redfish",
 			bios:     "",
 			boot:     "redfish-virtual-media",
+			firmware: "redfish",
 		},
 
 		{
@@ -593,6 +605,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:   "redfish",
 			bios:     "",
 			boot:     "redfish-virtual-media",
+			firmware: "redfish",
 		},
 
 		{
@@ -602,6 +615,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "idrac",
 			bios:       "idrac-redfish",
 			boot:       "idrac-redfish-virtual-media",
+			firmware:   "redfish",
 			management: "idrac-redfish",
 			power:      "idrac-redfish",
 			vendor:     "idrac-redfish",
@@ -614,6 +628,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "idrac",
 			bios:       "idrac-redfish",
 			boot:       "idrac-redfish-virtual-media",
+			firmware:   "redfish",
 			management: "idrac-redfish",
 			power:      "idrac-redfish",
 			vendor:     "idrac-redfish",
@@ -626,6 +641,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "idrac",
 			bios:       "idrac-redfish",
 			boot:       "idrac-redfish-virtual-media",
+			firmware:   "redfish",
 			management: "idrac-redfish",
 			power:      "idrac-redfish",
 			vendor:     "idrac-redfish",
@@ -638,6 +654,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "ibmc",
 			bios:       "",
 			boot:       "ipxe",
+			firmware:   "",
 			management: "ibmc",
 			power:      "ibmc",
 		},
@@ -649,6 +666,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "ilo",
 			bios:       "",
 			boot:       "ilo-ipxe",
+			firmware:   "",
 			management: "",
 			power:      "",
 		},
@@ -660,6 +678,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "ilo",
 			bios:       "",
 			boot:       "ilo-virtual-media",
+			firmware:   "",
 			management: "",
 			power:      "",
 		},
@@ -671,6 +690,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			driver:     "ilo5",
 			bios:       "",
 			boot:       "ilo-ipxe",
+			firmware:   "",
 			management: "",
 			power:      "",
 		},
@@ -694,6 +714,10 @@ func TestStaticDriverInfo(t *testing.T) {
 				t.Fatalf("Unexpected bios interface %q, expected %q",
 					acc.BIOSInterface(), tc.bios)
 			}
+			if acc.FirmwareInterface() != tc.firmware {
+				t.Fatalf("Unexpected firmware interface %q, expected %q",
+					acc.FirmwareInterface(), tc.firmware)
+			}
 			if acc.VendorInterface() != tc.vendor {
 				t.Fatalf("Unexpected vendor interface %q, expected %q",
 					acc.VendorInterface(), tc.vendor)
diff --git a/pkg/provisioner/ironic/prepare_test.go b/pkg/provisioner/ironic/prepare_test.go
index 1ae1c5b7..ca24f9ea 100644
--- a/pkg/provisioner/ironic/prepare_test.go
+++ b/pkg/provisioner/ironic/prepare_test.go
@@ -25,6 +25,7 @@ func (r *RAIDTestBMC) DriverInfo(bmc.Credentials) (i map[string]interface{}) { r
 func (r *RAIDTestBMC) SupportsISOPreprovisioningImage() bool                 { return false }
 func (r *RAIDTestBMC) BIOSInterface() string                                 { return "" }
 func (r *RAIDTestBMC) BootInterface() string                                 { return "" }
+func (r *RAIDTestBMC) FirmwareInterface() string                             { return "" }
 func (r *RAIDTestBMC) ManagementInterface() string                           { return "" }
 func (r *RAIDTestBMC) PowerInterface() string                                { return "" }
 func (r *RAIDTestBMC) RAIDInterface() string                                 { return "" }
diff --git a/pkg/provisioner/ironic/testbmc/testbmc.go b/pkg/provisioner/ironic/testbmc/testbmc.go
index 50a900a1..500cd97a 100644
--- a/pkg/provisioner/ironic/testbmc/testbmc.go
+++ b/pkg/provisioner/ironic/testbmc/testbmc.go
@@ -70,6 +70,10 @@ func (a *testAccessDetails) BootInterface() string {
 	return "ipxe"
 }
 
+func (a *testAccessDetails) FirmwareInterface() string {
+	return ""
+}
+
 func (a *testAccessDetails) ManagementInterface() string {
 	return ""
 }