Repository: metal3-io/baremetal-operator
Pull request #1305 (2023-06-29 13:05:27)

⚠️ Change iBMC to use iPXE instead of PXE
All other drivers use either iPXE or virtual media. Our ironic-image
does not even configure plain PXE properly, so it's not usable.
In any case, all in-tree network booting drivers should use iPXE
for consistent user experience.


Patch:
diff --git a/.github/workflows/kubesec.yml b/.github/workflows/kubesec.yml
index 7aa7c678..b280e7c2 100644
--- a/.github/workflows/kubesec.yml
+++ b/.github/workflows/kubesec.yml
@@ -19,7 +19,7 @@ jobs:
       contents: read
     steps:
       - name: Checkout code
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+        uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0
 
       - name: Collect all yaml
         id: list_yaml
@@ -42,7 +42,7 @@ jobs:
         value: ${{ fromJson(needs.setup.outputs.matrix) }}
     steps:
       - name: Checkout code
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+        uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0
 
       - name: Run kubesec scanner
         uses: controlplaneio/kubesec-action@43d0ddff5ffee89a6bb9f29b64cd865411137b14
@@ -59,6 +59,6 @@ jobs:
 
       - name: Upload Kubesec scan results to GitHub Security tab
         if: ${{ steps.save_result.outputs.result != '[]' }}
-        uses: github/codeql-action/upload-sarif@6c089f53dd51dc3fc7e599c3cb5356453a52ca9e # v2.20.0
+        uses: github/codeql-action/upload-sarif@a34ca99b4610d924e04c68db79e503e1f79f9f02 # v2.1.39
         with:
           sarif_file: ${{ matrix.value }}.sarif
diff --git a/.github/workflows/lint-docs.yaml b/.github/workflows/lint-docs.yaml
index 5fbb25f5..85f68ab6 100644
--- a/.github/workflows/lint-docs.yaml
+++ b/.github/workflows/lint-docs.yaml
@@ -17,7 +17,7 @@ jobs:
     if: github.repository == 'metal3-io/baremetal-operator'
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+    - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
     - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1
       with:
         use-quiet-mode: 'yes'
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 8270f273..78a43330 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -21,11 +21,11 @@ jobs:
       - name: Export RELEASE_TAG var
         run:  echo "RELEASE_TAG=${GITHUB_REF:10}" >> $GITHUB_ENV
       - name: checkout code
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+        uses: actions/checkout@dc323e67f16fb5f7663d20ff7941f27f5809e9b6 # v2.6.0
         with:
           fetch-depth: 0
       - name: Install go
-        uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
+        uses: actions/setup-go@bfdd3570ce990073878bf10f6b2d79082de49492 # v2.2.0
         with:
           go-version: '1.19'
       - name: Generate release notes
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a92298e9..2cc772a6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -44,8 +44,7 @@ own, file and fix any/all issues that come up, including gaps in documentation!
 
 ### Codebase
 
-Baremetal Operator doesn't follow release cadence and versioning of upstream
-Kubernetes semantic versioning. This codebase guarantees the following:
+Baremetal Operator doesn't follow release cadence and versioning of upstream Kubernetes semantic versioning. This codebase guarantees the following:
 
 - A (*minor*) release CAN include:
    - Introduction of new API versions, or new Kinds.
@@ -62,18 +61,25 @@ Types and functions not in public APIs are not considered part of the guarantee.
 
 #### Backporting
 
-We only accept backports of critical bugs, security issues, or bugs without
-easy workarounds, any
+**Note: At present we only have main branch, there is no other release branch. As such backporting is not
+an option currently. Once we have release branches the following should be considered.**
+
+We only accept backports of critical bugs, security issues, or bugs without easy workarounds, any
 backport MUST not be breaking for either API or behavioral changes.
 We generally do not accept PRs against older release branches.
 
 ## Branches
 
+Baremetal Operator has only the *main* branch currently.
+
+The goal is to have two types of branches in future: the *main* branch and *release-X* branches.
+
 The *main* branch is where development happens. All the latest and
-greatest code, including breaking changes, happens on main.
+greatest code, including breaking changes, happens on main. Currently patch releases are done from this branch
+only.
 
-The *release-X.Y* branches will contain stable, backwards compatible code. On
-every major or minor release, a new branch will be created. It is from these
+The *release-X* branches will contain stable, backwards compatible code. On every
+major or minor release, a new branch will be created. It is from these
 branches that minor and patch releases will be tagged. In some cases, it may
 be necessary to open PRs for bugfixes directly against stable branches, but
 this should generally not be the case.
@@ -108,13 +114,15 @@ mistakes](https://github.com/golang/go/wiki/CodeReviewComments) in your PRs.
 
 ## Backporting a Patch
 
-Baremetal Operator will maintain older versions through `release-X.Y` branches.
-We accept backports of bug fixes to the most recent
-release branch. For example, if the most recent branch is `release-0.3`, and the
+Baremetal Operator does not yet maintain branches other than `main`. However, in future there will be
+release branches as well.
+
+Once we will have release branches in future, Baremetal Operator will maintain older versions through `release-X.Y` branches. We accept backports of bug fixes to the most recent
+release branch. For example, if the most recent branch is `release-0.2`, and the
 `main` branch is under active
-development for v0.4.0, a bug fix that merged to `main` that also affects
-`v0.3.x` may be considered for backporting
-to `release-0.3`. We generally do not accept PRs against older release branches.
+development for v0.3.0, a bug fix that merged to `main` that also affects
+`v0.2.x` may be considered for backporting
+to `release-0.2`. We generally do not accept PRs against older release branches.
 
 ## Breaking Changes
 
@@ -134,8 +142,7 @@ Examples of breaking changes include:
 - Removing or renaming a CRD
 - Removing or renaming an exported constant, variable, type, or function
 - Updating the version of critical libraries such as controller-runtime,
-  client-go, apimachinery, etc. (patch versions of these libraries are not
-  considered as breaking change)
+  client-go, apimachinery, etc. (patch versions of these libraries are not considered as breaking change)
 - Some version updates may be acceptable, for picking up bug fixes, but
   maintainers must exercise caution when reviewing.
 
@@ -169,10 +176,8 @@ Metal3 maintainers can assign you an issue or pull request by leaving a
 ### Commands and Workflow
 
 Baremetal Operator follows the standard Kubernetes workflow: any PR
-needs `lgtm` and `approved` labels, and PRs must pass the tests before being
-merged. See
-[the contributor docs](https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#the-testing-and-merge-workflow)
-for more info.
+needs `lgtm` and `approved` labels, and PRs must pass the tests before being merged.
+See [the contributor docs](https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#the-testing-and-merge-workflow) for more info.
 
 We use the same priority and kind labels as Kubernetes. See the labels
 tab in GitHub for the full list.
@@ -197,4 +202,4 @@ PRs until a later date.
 
 ### Exact Steps
 
-Refer to the [releasing document](./docs/releasing.md) for the exact steps.
+Refer to the [releasing document](./docs/releasing.md) for the exact steps.
\ No newline at end of file
diff --git a/apis/go.mod b/apis/go.mod
index e5c4725d..feacfa35 100644
--- a/apis/go.mod
+++ b/apis/go.mod
@@ -6,8 +6,7 @@ require (
 	github.com/google/uuid v1.3.0
 	github.com/metal3-io/baremetal-operator/pkg/hardwareutils v0.2.0
 	github.com/pkg/errors v0.9.1
-	github.com/stretchr/testify v1.8.4
-	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
+	github.com/stretchr/testify v1.8.1
 	k8s.io/api v0.27.2
 	k8s.io/apimachinery v0.27.2
 	sigs.k8s.io/controller-runtime v0.15.0
diff --git a/apis/go.sum b/apis/go.sum
index 8c870f2d..0489a5ba 100644
--- a/apis/go.sum
+++ b/apis/go.sum
@@ -109,9 +109,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
@@ -121,8 +120,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
-golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
diff --git a/apis/metal3.io/v1alpha1/baremetalhost_types.go b/apis/metal3.io/v1alpha1/baremetalhost_types.go
index fe4d46ee..c92e92a2 100644
--- a/apis/metal3.io/v1alpha1/baremetalhost_types.go
+++ b/apis/metal3.io/v1alpha1/baremetalhost_types.go
@@ -47,19 +47,6 @@ const (
 	// annotation is present and status is empty, BMO will reconstruct BMH Status
 	// from the status annotation.
 	StatusAnnotation = "baremetalhost.metal3.io/status"
-
-	// RebootAnnotation is the annotation which tells the host which mode to use
-	// when rebooting - hard/soft
-	RebootAnnotationPrefix = "reboot.metal3.io"
-
-	// InspectAnnotation is used to specify if automatic introspection carried out
-	// during registration of BMH is enabled or disabled
-	InspectAnnotation = "inspect.metal3.io"
-
-	// HardwareDetailsAnnotation provides the hardware details for the host
-	// in case its not already part of the host status and when introspection
-	// is disabed
-	HardwareDetailsAnnotation = "inspect.metal3.io/hardwaredetails"
 )
 
 // RootDeviceHints holds the hints for specifying the storage location
@@ -144,9 +131,6 @@ const (
 	OperationalStatusDetached OperationalStatus = "detached"
 )
 
-// OperationalStatusAllowed represents the allowed values of OperationalStatus
-var OperationalStatusAllowed = []string{"", string(OperationalStatusOK), string(OperationalStatusDiscovered), string(OperationalStatusError), string(OperationalStatusDelayed), string(OperationalStatusDetached)}
-
 // ErrorType indicates the class of problem that has caused the Host resource
 // to enter an error state.
 type ErrorType string
@@ -176,9 +160,6 @@ const (
 	DetachError ErrorType = "detach error"
 )
 
-// ErrorTypeAllowed represents the allowed values of ErrorType
-var ErrorTypeAllowed = []string{"", string(ProvisionedRegistrationError), string(RegistrationError), string(InspectionError), string(PreparationError), string(ProvisioningError), string(PowerManagementError)}
-
 // ProvisioningState defines the states the provisioner will report
 // the host has having.
 type ProvisioningState string
diff --git a/apis/metal3.io/v1alpha1/baremetalhost_validation.go b/apis/metal3.io/v1alpha1/baremetalhost_validation.go
index b45dd2c2..c2039c96 100644
--- a/apis/metal3.io/v1alpha1/baremetalhost_validation.go
+++ b/apis/metal3.io/v1alpha1/baremetalhost_validation.go
@@ -1,7 +1,6 @@
 package v1alpha1
 
 import (
-	"encoding/json"
 	"fmt"
 	"net"
 	"net/url"
@@ -10,7 +9,6 @@ import (
 
 	"github.com/google/uuid"
 	"github.com/pkg/errors"
-	"golang.org/x/exp/slices"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 
 	"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
@@ -57,10 +55,6 @@ func (host *BareMetalHost) validateHost() []error {
 		}
 	}
 
-	if annotationErrors := validateAnnotations(host); annotationErrors != nil {
-		errs = append(errs, annotationErrors...)
-	}
-
 	return errs
 }
 
@@ -181,52 +175,6 @@ func validateDNSName(hostaddress string) error {
 	return nil
 }
 
-func validateAnnotations(host *BareMetalHost) []error {
-	var errs []error
-	var err error
-
-	for annotation, value := range host.Annotations {
-
-		switch {
-		case annotation == StatusAnnotation:
-			err = validateStatusAnnotation(value)
-		case strings.HasPrefix(annotation, RebootAnnotationPrefix+"/") || annotation == RebootAnnotationPrefix:
-			err = validateRebootAnnotation(value)
-		case annotation == InspectAnnotation:
-			err = validateInspectAnnotation(value)
-		case annotation == HardwareDetailsAnnotation:
-			inspect := host.Annotations[InspectAnnotation]
-			err = validateHwdDetailsAnnotation(value, inspect)
-		default:
-			err = nil
-		}
-		if err != nil {
-			errs = append(errs, err)
-		}
-	}
-
-	return errs
-}
-
-func validateStatusAnnotation(statusAnnotation string) error {
-	if statusAnnotation != "" {
-
-		objBMHStatus := &BareMetalHostStatus{}
-
-		deco := json.NewDecoder(strings.NewReader(statusAnnotation))
-		deco.DisallowUnknownFields()
-		if err := deco.Decode(objBMHStatus); err != nil {
-			return fmt.Errorf("error decoding status annotation, error=%w", err)
-		}
-
-		if err := checkStatusAnnotation(objBMHStatus); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
 func validateImageURL(imageURL string) error {
 
 	_, err := url.ParseRequestURI(imageURL)
@@ -253,71 +201,3 @@ func validateRootDeviceHints(rdh *RootDeviceHints) error {
 	}
 	return nil
 }
-
-// When making changes to this function for operationalstatus and errortype,
-// also make the corresponding changes in the OperationalStatus and
-// ErrorType fields in the struct definition of BareMetalHostStatus in
-// the file baremetalhost_types.go
-func checkStatusAnnotation(bmhStatus *BareMetalHostStatus) error {
-
-	if !slices.Contains(OperationalStatusAllowed, string(bmhStatus.OperationalStatus)) {
-		return fmt.Errorf("invalid OperationalStatus='%s' in StatusAnnotation", string(bmhStatus.OperationalStatus))
-	}
-
-	if !slices.Contains(ErrorTypeAllowed, string(bmhStatus.ErrorType)) {
-		return fmt.Errorf("invalid ErrorType='%s' in StatusAnnotation", string(bmhStatus.ErrorType))
-	}
-
-	return nil
-}
-
-func validateHwdDetailsAnnotation(hwdDetAnnotation string, inspect string) error {
-	if hwdDetAnnotation == "" {
-		return nil
-	}
-
-	if inspect != "disabled" {
-		return fmt.Errorf("inspection has to be disabled for HardwareDetailsAnnotation, check if {'inspect.metal3.io' : 'disabled'}")
-	}
-
-	objHwdDet := &HardwareDetails{}
-
-	deco := json.NewDecoder(strings.NewReader(hwdDetAnnotation))
-	deco.DisallowUnknownFields()
-	if err := deco.Decode(objHwdDet); err != nil {
-		return fmt.Errorf("error decoding hardware details annotation, error=%w", err)
-	}
-
-	return nil
-}
-
-func validateInspectAnnotation(inspectAnnotation string) error {
-
-	inspectAnnotationAllowed := []string{"disabled", ""}
-
-	if !slices.Contains(inspectAnnotationAllowed, inspectAnnotation) {
-		return fmt.Errorf("invalid value for Inspect Annotation")
-	}
-
-	return nil
-}
-
-func validateRebootAnnotation(rebootAnnotation string) error {
-	if rebootAnnotation == "" {
-		return nil
-	}
-
-	objStatus := &RebootAnnotationArguments{}
-	err := json.Unmarshal([]byte(rebootAnnotation), objStatus)
-	if err != nil {
-		return fmt.Errorf("failed to fetch Reboot from annotation, %w", err)
-	}
-
-	supportedRebootModes := []string{"hard", "soft", ""}
-
-	if !slices.Contains(supportedRebootModes, string(objStatus.Mode)) {
-		return fmt.Errorf("invalid RebootMode in RebootAnnotation")
-	}
-
-	return nil
-}
diff --git a/docs/releasing.md b/docs/releasing.md
index 215c25c6..ee53e530 100644
--- a/docs/releasing.md
+++ b/docs/releasing.md
@@ -19,7 +19,6 @@ Things you should do before making a release:
 Creating a release requires repository `write` permissions for:
 
 - Tag pushing
-- Branch creation
 - GitHub Release publishing
 
 These permissions are implicit for the org admins and repository admins.
@@ -31,7 +30,7 @@ should not be given permissions directly.
 
 ## Process
 
-BMO uses [semantic versioning](https://semver.org). For version `v0.x.y`:
+BMO uses [semantic versioning](https://semver.org).
 
 ### Repository setup
 
@@ -41,17 +40,11 @@ Clone the repository:
 or if using existing repository, verify your intended remote is set to
 `metal3-io`: `git remote -v`. For this document, we assume it is `origin`.
 
-- If creating a new minor branch, identify the commit you wish to create the
-  branch from, and create a branch `release-0.x`:
-  `git checkout <sha> -b release-0.x` and push it to remote:
-  `git push origin release-0.x` to create it
-- If creating a new patch release, use existing branch `release-0.x`:
-  `git checkout origin/release-0.x`
-
 ### Tags
 
-First we create a primary release tag, that triggers release note creation and
-image building processes.
+BMO does not have release branches. Release is created by tagging a commit off
+the main branch. First we create a primary release tag, that triggers release
+note creation and image building processes.
 
 - Create a signed, annotated tag with: `git tag -s -a v0.x.y -m v0.x.y`
 - Push the tags to the GitHub repository: `git push origin v0.x.y`
@@ -68,8 +61,7 @@ We also need to create one or more tags for the Go modules ecosystem:
 - For any subdirectory with `go.mod` in it (excluding `hack/tools`), create
   another Git tag with directory prefix, ie.
   `git tag -s api/v0.x.y -m api/v0.x.y`.
-  For BMO, these directories are `api` and `pkg/hardwareutils`. This enables
-  the tags to be used as a Go module version for any downstream users.
+  For BMO, these directories are `api` and `pkg/hardwareutils`.
   **NOTE**: Do not create annotated tags for go modules.
 
 ### Release artifacts
@@ -85,11 +77,8 @@ Git tags pushed:
 Container images built and tagged at Quay registry:
 
 - [baremetal-operator:v0.x.y](https://quay.io/repository/metal3-io/baremetal-operator?tab=tags)
-- [keepalived:v0.x.y](https://quay.io/repository/metal3-io/keepalived?tab=tags)
-
-Files included in the release page:
 
-- Source code
+BMO release in GitHub will only contain source code as artifact.
 
 ### Release notes
 
@@ -108,35 +97,9 @@ Next step is to clean up the release note manually.
 - If it is a release candidate (RC) or a pre-release, tick pre-release box.
 - Publish the release.
 
-## Post-release actions for new release branches
-
-Some post-release actions are needed if new minor or major branch was created.
-
-### Branch protection rules
-
-Branch protection rules need to be applied to the new release branch. Copy the
-settings after the previous release branch, with the exception of
-`Required tests` selection. Required tests can only be selected after new
-keywords are implemented in Jenkins JJB, and project-infra, and have been run
-at least once in the PR targeting the branch in question.
-
-### Update README.md and build badges
-
-Update `README.md` with release specific information, both on `main` and
-in the new `release-0.x` branch as necessary.
-
-<!-- No example PR yet. To be added when first release from branch is made
-[Example](https://github.com/metal3-io/cluster-api-provider-metal3/pull/949) -->
-
-In the `release-0.x` branch, update the build badges in the `README.md` to point
-to correct Jenkins jobs, so the build statuses of the release branch are
-visible.
-
-<!-- No example PR yet. To be added when first release from branch is made
-[Example](https://github.com/metal3-io/cluster-api-provider-metal3/pull/951) -->
-
-## Additional actions outside this repository
+## Impact on Metal3
 
-Further additional actions are required in the Metal3 project after BMO
-release. For that, please continue following the instructions provided in
+Release process is complete, but further additional actions are required
+in the Metal3 project to take in the new major/minor release. These steps are
+documented in
 [Metal3 release process](https://github.com/metal3-io/metal3-docs/blob/main/processes/releasing.md)
diff --git a/go.mod b/go.mod
index fd10a005..9ab59e97 100644
--- a/go.mod
+++ b/go.mod
@@ -5,13 +5,13 @@ go 1.19
 require (
 	github.com/go-logr/logr v1.2.4
 	github.com/google/safetext v0.0.0-20230106111101-7156a760e523
-	github.com/gophercloud/gophercloud v1.4.1-0.20230614092438-44d55f08cdc0
+	github.com/gophercloud/gophercloud v1.3.0
 	github.com/metal3-io/baremetal-operator/apis v0.2.0
 	github.com/metal3-io/baremetal-operator/pkg/hardwareutils v0.2.0
 	github.com/pkg/errors v0.9.1
-	github.com/prometheus/client_golang v1.16.0
-	github.com/stretchr/testify v1.8.4
-	go.etcd.io/etcd/client/pkg/v3 v3.5.9
+	github.com/prometheus/client_golang v1.15.1
+	github.com/stretchr/testify v1.8.1
+	go.etcd.io/etcd/client/pkg/v3 v3.5.7
 	go.uber.org/zap v1.24.0
 	k8s.io/api v0.27.2
 	k8s.io/apimachinery v0.27.2
@@ -51,11 +51,10 @@ require (
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/prometheus/client_model v0.4.0 // indirect
 	github.com/prometheus/common v0.42.0 // indirect
-	github.com/prometheus/procfs v0.10.1 // indirect
+	github.com/prometheus/procfs v0.9.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
-	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
 	golang.org/x/net v0.10.0 // indirect
 	golang.org/x/oauth2 v0.5.0 // indirect
 	golang.org/x/sys v0.8.0 // indirect
diff --git a/go.sum b/go.sum
index 0a377071..d8ba3395 100644
--- a/go.sum
+++ b/go.sum
@@ -71,8 +71,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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gophercloud/gophercloud v1.4.1-0.20230614092438-44d55f08cdc0 h1:TNfpghMRzEdmU8xPrmMsNZ4Qhx7im/d8BSh9XufBwG8=
-github.com/gophercloud/gophercloud v1.4.1-0.20230614092438-44d55f08cdc0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
+github.com/gophercloud/gophercloud v1.3.0 h1:RUKyCMiZoQR3VlVR5E3K7PK1AC3/qppsWYo6dtBiqs8=
+github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
 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/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@@ -108,15 +108,15 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
-github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
+github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
+github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
 github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
 github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
 github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
-github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
-github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
+github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
+github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -129,14 +129,13 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE=
-go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
+go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg=
+go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY=
 go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
@@ -150,8 +149,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
-golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
diff --git a/pkg/hardwareutils/bmc/ibmc.go b/pkg/hardwareutils/bmc/ibmc.go
index ba8185b3..7cb4b9af 100644
--- a/pkg/hardwareutils/bmc/ibmc.go
+++ b/pkg/hardwareutils/bmc/ibmc.go
@@ -84,7 +84,7 @@ func (a *ibmcAccessDetails) BIOSInterface() string {
 }
 
 func (a *ibmcAccessDetails) BootInterface() string {
-	return "pxe"
+	return "ipxe"
 }
 
 func (a *ibmcAccessDetails) ManagementInterface() string {
diff --git a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go b/pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go
index 6c312889..9d07744e 100644
--- a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go
+++ b/pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go
@@ -14,10 +14,10 @@ import (
 // GetHardwareDetails converts Ironic introspection data into BareMetalHost HardwareDetails.
 func GetHardwareDetails(data *introspection.Data) *metal3api.HardwareDetails {
 	details := new(metal3api.HardwareDetails)
-	details.Firmware = getFirmwareDetails(data.Inventory.SystemVendor.Firmware)
+	details.Firmware = getFirmwareDetails(data.Extra.Firmware)
 	details.SystemVendor = getSystemVendorDetails(data.Inventory.SystemVendor)
 	details.RAMMebibytes = data.MemoryMB
-	details.NIC = getNICDetails(data.Inventory.Interfaces, data.AllInterfaces)
+	details.NIC = getNICDetails(data.Inventory.Interfaces, data.AllInterfaces, data.Extra.Network)
 	details.Storage = getStorageDetails(data.Inventory.Disks)
 	details.CPU = getCPUDetails(&data.Inventory.CPU)
 	details.Hostname = data.Inventory.Hostname
@@ -47,8 +47,18 @@ func getVLANs(intf introspection.BaseInterfaceType) (vlans []metal3api.VLAN, vla
 	return
 }
 
+func getNICSpeedGbps(intfExtradata introspection.ExtraHardwareData) (speedGbps int) {
+	if speed, ok := intfExtradata["speed"].(string); ok {
+		if strings.HasSuffix(speed, "Gbps") {
+			fmt.Sscanf(speed, "%d", &speedGbps)
+		}
+	}
+	return
+}
+
 func getNICDetails(ifdata []introspection.InterfaceType,
-	basedata map[string]introspection.BaseInterfaceType) []metal3api.NIC {
+	basedata map[string]introspection.BaseInterfaceType,
+	extradata introspection.ExtraHardwareDataSection) []metal3api.NIC {
 	var nics []metal3api.NIC
 	for _, intf := range ifdata {
 		baseIntf := basedata[intf.Name]
@@ -64,7 +74,7 @@ func getNICDetails(ifdata []introspection.InterfaceType,
 				IP:        intf.IPV4Address,
 				VLANs:     vlans,
 				VLANID:    vlanid,
-				SpeedGbps: intf.SpeedMbps / 1000,
+				SpeedGbps: getNICSpeedGbps(extradata[intf.Name]),
 				PXE:       baseIntf.PXE,
 			})
 		}
@@ -77,7 +87,7 @@ func getNICDetails(ifdata []introspection.InterfaceType,
 				IP:        intf.IPV6Address,
 				VLANs:     vlans,
 				VLANID:    vlanid,
-				SpeedGbps: intf.SpeedMbps / 1000,
+				SpeedGbps: getNICSpeedGbps(extradata[intf.Name]),
 				PXE:       baseIntf.PXE,
 			})
 		}
@@ -145,12 +155,22 @@ func getCPUDetails(cpudata *introspection.CPUType) metal3api.CPU {
 	return cpu
 }
 
-func getFirmwareDetails(firmwaredata introspection.SystemFirmwareType) metal3api.Firmware {
+func getFirmwareDetails(firmwaredata introspection.ExtraHardwareDataSection) metal3api.Firmware {
+
+	// handle bios optionally
+	var bios metal3api.BIOS
+
+	if biosdata, ok := firmwaredata["bios"]; ok {
+		// we do not know if all fields will be supplied
+		// as this is not a structured response
+		// so we must handle each field conditionally
+		bios.Vendor, _ = biosdata["vendor"].(string)
+		bios.Version, _ = biosdata["version"].(string)
+		bios.Date, _ = biosdata["date"].(string)
+	}
+
 	return metal3api.Firmware{
-		BIOS: metal3api.BIOS{
-			Vendor:  firmwaredata.Vendor,
-			Version: firmwaredata.Version,
-			Date:    firmwaredata.BuildDate,
-		},
+		BIOS: bios,
 	}
+
 }


Test patch:
diff --git a/apis/metal3.io/v1alpha1/baremetalhost_validation_test.go b/apis/metal3.io/v1alpha1/baremetalhost_validation_test.go
index 72ce030c..b8132f8a 100644
--- a/apis/metal3.io/v1alpha1/baremetalhost_validation_test.go
+++ b/apis/metal3.io/v1alpha1/baremetalhost_validation_test.go
@@ -42,7 +42,6 @@ func TestValidateCreate(t *testing.T) {
 		Name:      "07564256-96ae-4315-ab03-8d34ece60fbb",
 		Namespace: "test-namespace",
 	}
-
 	enable := true
 
 	// for RAID validation test cases
@@ -512,172 +511,6 @@ func TestValidateCreate(t *testing.T) {
 			oldBMH:    nil,
 			wantedErr: "Image URL test1 is an invalid URL",
 		},
-		{
-			name: "validStatusAnnotation",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						StatusAnnotation: `{"operationalStatus": "OK"}`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "",
-		},
-		{
-			name: "invalidFieldStatusAnnotation",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						StatusAnnotation: `{"InvalidField":"NotOK"}`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "error decoding status annotation, error=json: unknown field \"InvalidField\"",
-		},
-		{
-			name: "invalidOpstatusStatusAnnotation",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						StatusAnnotation: `{"operationalStatus":"NotOK"}`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "invalid OperationalStatus='NotOK' in StatusAnnotation",
-		},
-		{
-			name: "invalidErrtypeStatusAnnotation",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						StatusAnnotation: `{"errorType":"No Error"}`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "invalid ErrorType='No Error' in StatusAnnotation",
-		},
-		{
-			name: "invalidFormatStatusAnnotation",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						StatusAnnotation: `{"operationalStatus":"OK"`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "error decoding status annotation, error=unexpected EOF",
-		},
-		{
-			name: "invalidValueRebootAnnotationPrefix",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						RebootAnnotationPrefix: `{"mode":"medium"}`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "invalid RebootMode in RebootAnnotation",
-		},
-		{
-			name: "invalidValueRebootAnnotationWithKey",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						RebootAnnotationPrefix + "/my-key": `{"mode":"medium"}`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "invalid RebootMode in RebootAnnotation",
-		},
-		{
-			name: "inspectionNotDisabledHardwareDetailsAnnotation",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						HardwareDetailsAnnotation: `{"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}],"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":["foo"],"count":4},"hostname":"hwdAnnotation-0"}`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "inspection has to be disabled for HardwareDetailsAnnotation, check if {'inspect.metal3.io' : 'disabled'}",
-		},
-		{
-			name: "invalidFieldHardwareDetailsAnnotation",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						InspectAnnotation:         "disabled",
-						HardwareDetailsAnnotation: `{"INVALIDField":{"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}],"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":["foo"],"count":4},"hostname":"hwdAnnotation-0"}`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "error decoding hardware details annotation, error=json: unknown field \"INVALIDField\"",
-		},
-		{
-			name: "invalidJsonHardwareDetailsAnnotation",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm, ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						InspectAnnotation:         "disabled",
-						HardwareDetailsAnnotation: `{"INVALIDField":{"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}],"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":["foo"],"count":4},"hostname":"hwdAnnotation-0"`,
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "error decoding hardware details annotation, error=unexpected EOF",
-		},
-		{
-			name: "invalidValueInspectAnnotation",
-			newBMH: &BareMetalHost{
-				TypeMeta: tm,
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      "test",
-					Namespace: "test-namespace",
-					Annotations: map[string]string{
-						InspectAnnotation: "enabled",
-					},
-				},
-			},
-			oldBMH:    nil,
-			wantedErr: "invalid value for Inspect Annotation",
-		},
 	}
 
 	for _, tt := range tests {
diff --git a/pkg/hardwareutils/bmc/access_test.go b/pkg/hardwareutils/bmc/access_test.go
index b69e58be..b0f5ac1a 100644
--- a/pkg/hardwareutils/bmc/access_test.go
+++ b/pkg/hardwareutils/bmc/access_test.go
@@ -637,7 +637,7 @@ func TestStaticDriverInfo(t *testing.T) {
 			needsMac:   true,
 			driver:     "ibmc",
 			bios:       "",
-			boot:       "pxe",
+			boot:       "ipxe",
 			management: "ibmc",
 			power:      "ibmc",
 		},
diff --git a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go b/pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go
index 14ad04bf..540febba 100644
--- a/pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go
+++ b/pkg/provisioner/ironic/hardwaredetails/hardwaredetails_test.go
@@ -158,8 +158,7 @@ func TestGetNICDetails(t *testing.T) {
 			{
 				Name:        "eth1",
 				IPV6Address: "2001:db8::1",
-				MACAddress:  "66:77:88:99:aa:bb",
-				SpeedMbps:   1000},
+				MACAddress:  "66:77:88:99:aa:bb"},
 			{
 				Name:        "eth46",
 				IPV6Address: "2001:db8::2",
@@ -181,6 +180,11 @@ func TestGetNICDetails(t *testing.T) {
 					"switch_port_untagged_vlan_id": 1,
 				},
 			},
+		},
+		introspection.ExtraHardwareDataSection{
+			"eth1": introspection.ExtraHardwareData{
+				"speed": "1Gbps",
+			},
 		})
 
 	// 5 expected because eth46 results in two items
@@ -229,16 +233,74 @@ func TestGetNICDetails(t *testing.T) {
 	}
 }
 
+func TestGetNICSpeedGbps(t *testing.T) {
+	s1 := getNICSpeedGbps(introspection.ExtraHardwareData{
+		"speed": "25Gbps",
+	})
+	if s1 != 25 {
+		t.Errorf("Expected speed 25, got %d", s1)
+	}
+
+	s2 := getNICSpeedGbps(introspection.ExtraHardwareData{
+		"speed": "100Mbps",
+	})
+	if s2 != 0 {
+		t.Errorf("Expected speed 0, got %d", s2)
+	}
+
+	s3 := getNICSpeedGbps(introspection.ExtraHardwareData{
+		"speed": 10,
+	})
+	if s3 != 0 {
+		t.Errorf("Expected speed 0, got %d", s3)
+	}
+
+	s4 := getNICSpeedGbps(introspection.ExtraHardwareData{})
+	if s4 != 0 {
+		t.Errorf("Expected speed 0, got %d", s4)
+	}
+}
+
 func TestGetFirmwareDetails(t *testing.T) {
 	// Test full (known) firmware payload
-	firmware := getFirmwareDetails(introspection.SystemFirmwareType{
-		Vendor:    "foobar",
-		Version:   "1.2.3",
-		BuildDate: "2019-07-10",
+	firmware := getFirmwareDetails(introspection.ExtraHardwareDataSection{
+		"bios": {
+			"vendor":  "foobar",
+			"version": "1.2.3",
+			"date":    "2019-07-10",
+		},
 	})
 
 	if firmware.BIOS.Vendor != "foobar" {
 		t.Errorf("Expected firmware BIOS vendor to be foobar, but got: %s", firmware)
 	}
 
+	// Ensure we can handle partial firmware/bios data
+	firmware = getFirmwareDetails(introspection.ExtraHardwareDataSection{
+		"bios": {
+			"vendor":  "foobar",
+			"version": "1.2.3",
+		},
+	})
+
+	if firmware.BIOS.Date != "" {
+		t.Errorf("Expected firmware BIOS date to be empty but got: %s", firmware)
+	}
+
+	// Ensure we can handle unexpected types
+	firmware = getFirmwareDetails(introspection.ExtraHardwareDataSection{
+		"bios": {
+			"vendor":  3,
+			"version": []int{2, 1},
+			"date":    map[string]string{"year": "2019", "month": "07", "day": "10"},
+		},
+	})
+
+	// Finally, ensure we can handle completely empty firmware data
+	firmware = getFirmwareDetails(introspection.ExtraHardwareDataSection{})
+
+	if (firmware != metal3api.Firmware{}) {
+		t.Errorf("Expected firmware data to be empty but got: %s", firmware)
+	}
+
 }