Repository: metal3-io/baremetal-operator
Pull request #1656 (2024-04-08 07:57:01)

🌱 E2E: Prepare for emulator based on protocol
**What this PR does / why we need it**:

In CI we currently specify the emulator to use (sushy-tools or VBMC) and can in addition specify the protocol for sushy-tools. This change is a preparation to switch to specifying the protocol instead and picking the emulator based on it.

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #


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 ask for approval from [lentzi90](https://github.com/lentzi90). 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":["lentzi90"]} -->
lentzi90: /test metal3-bmo-e2e-test-pull
mquhuy: lgtm
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/1656#pullrequestreview-1986263150" title="Approved">kashifest</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/main/OWNERS)~~ [kashifest]

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/.github/workflows/pr-gh-workflow-approve.yaml b/.github/workflows/pr-gh-workflow-approve.yaml
deleted file mode 100644
index f00e6c6c..00000000
--- a/.github/workflows/pr-gh-workflow-approve.yaml
+++ /dev/null
@@ -1,42 +0,0 @@
-# adapted from github.com/kubernetes-sigs/cluster-api/.github/workflows/pr-gh-workflow-approve.yaml
-# this workflow approves workflows if the PR has /ok-to-test
-# related Prow feature request https://github.com/kubernetes/test-infra/issues/25210
-
-name: Approve GH Workflows
-
-on:
-  pull_request_target:
-    types: [opened, edited, reopened, synchronize]
-
-jobs:
-  approve:
-    name: Approve on ok-to-test
-    runs-on: ubuntu-latest
-
-    permissions:
-      actions: write
-
-    if: contains(github.event.pull_request.labels.*.name, 'ok-to-test')
-    steps:
-    - name: Update PR
-      uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
-      continue-on-error: true
-      with:
-        github-token: ${{ secrets.GITHUB_TOKEN }}
-        script: |
-          const result = await github.rest.actions.listWorkflowRunsForRepo({
-            owner: context.repo.owner,
-            repo: context.repo.repo,
-            event: "pull_request",
-            status: "action_required",
-            head_sha: context.payload.pull_request.head.sha,
-            per_page: 100
-          });
-
-          for (var run of result.data.workflow_runs) {
-            await github.rest.actions.approveWorkflowRun({
-              owner: context.repo.owner,
-              repo: context.repo.repo,
-              run_id: run.id
-            });
-          }
diff --git a/PROJECT b/PROJECT
index 192a6021..01f6bffc 100644
--- a/PROJECT
+++ b/PROJECT
@@ -64,11 +64,10 @@ resources:
 - api:
     crdVersion: v1
     namespaced: true
-  controller: true
   domain: metal3.io
   group: metal3.io
   kind: HostFirmwareComponents
-  path: github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1
+  path: github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha
   version: v1alpha1
 - api:
     crdVersion: v1
diff --git a/apis/metal3.io/v1alpha1/hostfirmwarecomponents_types.go b/apis/metal3.io/v1alpha1/hostfirmwarecomponents_types.go
index 4cd10143..c4d3ad5f 100644
--- a/apis/metal3.io/v1alpha1/hostfirmwarecomponents_types.go
+++ b/apis/metal3.io/v1alpha1/hostfirmwarecomponents_types.go
@@ -22,6 +22,8 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
+
 // FirmwareUpdate defines a firmware update specification.
 type FirmwareUpdate struct {
 	Component string `json:"component"`
@@ -32,9 +34,9 @@ type FirmwareUpdate struct {
 type FirmwareComponentStatus struct {
 	Component          string      `json:"component"`
 	InitialVersion     string      `json:"initialVersion"`
-	CurrentVersion     string      `json:"currentVersion,omitempty"`
-	LastVersionFlashed string      `json:"lastVersionFlashed,omitempty"`
-	UpdatedAt          metav1.Time `json:"updatedAt,omitempty"`
+	CurrentVersion     string      `json:"currentVersion"`
+	LastVersionFlashed string      `json:"lastVersionFlashed"`
+	UpdatedAt          metav1.Time `json:"updatedAt"`
 }
 
 type UpdatesConditionType string
@@ -75,6 +77,7 @@ type HostFirmwareComponentsStatus struct {
 }
 
 //+kubebuilder:object:root=true
+//+kubebuilder:resource:shortName=hfc
 //+kubebuilder:subresource:status
 
 // HostFirmwareComponents is the Schema for the hostfirmwarecomponents API.
diff --git a/config/base/crds/bases/metal3.io_hostfirmwarecomponents.yaml b/config/base/crds/bases/metal3.io_hostfirmwarecomponents.yaml
index 095763de..292348e5 100644
--- a/config/base/crds/bases/metal3.io_hostfirmwarecomponents.yaml
+++ b/config/base/crds/bases/metal3.io_hostfirmwarecomponents.yaml
@@ -11,6 +11,8 @@ spec:
     kind: HostFirmwareComponents
     listKind: HostFirmwareComponentsList
     plural: hostfirmwarecomponents
+    shortNames:
+    - hfc
     singular: hostfirmwarecomponents
   scope: Namespaced
   versions:
@@ -75,7 +77,10 @@ spec:
                       type: string
                   required:
                   - component
+                  - currentVersion
                   - initialVersion
+                  - lastVersionFlashed
+                  - updatedAt
                   type: object
                 type: array
               conditions:
diff --git a/config/base/crds/kustomization.yaml b/config/base/crds/kustomization.yaml
index 7912eb81..3aae0699 100644
--- a/config/base/crds/kustomization.yaml
+++ b/config/base/crds/kustomization.yaml
@@ -3,7 +3,6 @@
 # It should be run by config/default
 resources:
 - bases/metal3.io_baremetalhosts.yaml
-- bases/metal3.io_hostfirmwarecomponents.yaml
 - bases/metal3.io_hostfirmwaresettings.yaml
 - bases/metal3.io_firmwareschemas.yaml
 - bases/metal3.io_preprovisioningimages.yaml
@@ -16,7 +15,6 @@ patches:
 # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
 # patches here are for enabling the conversion webhook for each CRD
 #- patches/webhook_in_baremetalhosts.yaml
-#- patches/webhook_in_hostfirmwarecomponents.yaml
 #- patches/webhook_in_hostfirmwaresettings.yaml
 #- patches/webhook_in_firmwareschemas.yaml
 #- patches/webhook_in_preprovisioningimages.yaml
@@ -28,7 +26,6 @@ patches:
 # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
 # patches here are for enabling the CA injection for each CRD
 - path: patches/cainjection_in_baremetalhosts.yaml
-#- patches/cainjection_in_hostfirmwarecomponents.yaml
 #- patches/cainjection_in_hostfirmwaresettings.yaml
 #- patches/cainjection_in_firmwareschemas.yaml
 #- patches/cainjection_in_preprovisioningimages.yaml
diff --git a/config/base/crds/patches/cainjection_in_hostfirmwarecomponents.yaml b/config/base/crds/patches/cainjection_in_hostfirmwarecomponents.yaml
deleted file mode 100644
index cb970cf5..00000000
--- a/config/base/crds/patches/cainjection_in_hostfirmwarecomponents.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-# The following patch adds a directive for certmanager to inject CA into the CRD
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
-  name: hostfirmwarecomponents.metal3.io
diff --git a/config/base/crds/patches/webhook_in_hostfirmwarecomponents.yaml b/config/base/crds/patches/webhook_in_hostfirmwarecomponents.yaml
deleted file mode 100644
index e77b92c7..00000000
--- a/config/base/crds/patches/webhook_in_hostfirmwarecomponents.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-# The following patch enables a conversion webhook for the CRD
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  name: hostfirmwarecomponents.metal3.io
-spec:
-  conversion:
-    strategy: Webhook
-    webhook:
-      clientConfig:
-        service:
-          namespace: system
-          name: webhook-service
-          path: /convert
-      conversionReviewVersions:
-      - v1
diff --git a/config/base/rbac/hostfirmwarecomponents_editor_role.yaml b/config/base/rbac/hostfirmwarecomponents_editor_role.yaml
index 1646a289..ae97a230 100644
--- a/config/base/rbac/hostfirmwarecomponents_editor_role.yaml
+++ b/config/base/rbac/hostfirmwarecomponents_editor_role.yaml
@@ -2,13 +2,6 @@
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
-  labels:
-    app.kubernetes.io/name: clusterrole
-    app.kubernetes.io/instance: hostfirmwarecomponents-editor-role
-    app.kubernetes.io/component: rbac
-    app.kubernetes.io/created-by: baremetal-operator
-    app.kubernetes.io/part-of: baremetal-operator
-    app.kubernetes.io/managed-by: kustomize
   name: hostfirmwarecomponents-editor-role
 rules:
 - apiGroups:
@@ -16,16 +9,16 @@ rules:
   resources:
   - hostfirmwarecomponents
   verbs:
-  - create
-  - delete
   - get
   - list
-  - patch
-  - update
   - watch
+  - create
+  - update
+  - patch
+  - delete
 - apiGroups:
   - metal3.io
   resources:
   - hostfirmwarecomponents/status
   verbs:
-  - get
+  - get
\ No newline at end of file
diff --git a/config/base/rbac/hostfirmwarecomponents_viewer_role.yaml b/config/base/rbac/hostfirmwarecomponents_viewer_role.yaml
index a511d3a3..05cd38c6 100644
--- a/config/base/rbac/hostfirmwarecomponents_viewer_role.yaml
+++ b/config/base/rbac/hostfirmwarecomponents_viewer_role.yaml
@@ -1,14 +1,7 @@
-# permissions for end users to view hostfirmwarecomponents.
+# permissions for end users to edit hostfirmwarecomponents.
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
-  labels:
-    app.kubernetes.io/name: clusterrole
-    app.kubernetes.io/instance: hostfirmwarecomponents-viewer-role
-    app.kubernetes.io/component: rbac
-    app.kubernetes.io/created-by: baremetal-operator
-    app.kubernetes.io/part-of: baremetal-operator
-    app.kubernetes.io/managed-by: kustomize
   name: hostfirmwarecomponents-viewer-role
 rules:
 - apiGroups:
@@ -24,4 +17,4 @@ rules:
   resources:
   - hostfirmwarecomponents/status
   verbs:
-  - get
+  - get
\ No newline at end of file
diff --git a/config/base/rbac/role.yaml b/config/base/rbac/role.yaml
index 0094daea..837707e7 100644
--- a/config/base/rbac/role.yaml
+++ b/config/base/rbac/role.yaml
@@ -109,32 +109,6 @@ rules:
   - patch
   - update
   - watch
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwarecomponents
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwarecomponents/finalizers
-  verbs:
-  - update
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwarecomponents/status
-  verbs:
-  - get
-  - patch
-  - update
 - apiGroups:
   - metal3.io
   resources:
diff --git a/config/render/capm3.yaml b/config/render/capm3.yaml
index 518a174d..1f5ea863 100644
--- a/config/render/capm3.yaml
+++ b/config/render/capm3.yaml
@@ -1601,187 +1601,6 @@ spec:
 ---
 apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.12.1
-  name: hostfirmwarecomponents.metal3.io
-spec:
-  group: metal3.io
-  names:
-    kind: HostFirmwareComponents
-    listKind: HostFirmwareComponentsList
-    plural: hostfirmwarecomponents
-    singular: hostfirmwarecomponents
-  scope: Namespaced
-  versions:
-  - name: v1alpha1
-    schema:
-      openAPIV3Schema:
-        description: HostFirmwareComponents is the Schema for the hostfirmwarecomponents
-          API.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: HostFirmwareComponentsSpec defines the desired state of HostFirmwareComponents.
-            properties:
-              updates:
-                items:
-                  description: FirmwareUpdate defines a firmware update specification.
-                  properties:
-                    component:
-                      type: string
-                    url:
-                      type: string
-                  required:
-                  - component
-                  - url
-                  type: object
-                type: array
-            required:
-            - updates
-            type: object
-          status:
-            description: HostFirmwareComponentsStatus defines the observed state of
-              HostFirmwareComponents.
-            properties:
-              components:
-                description: Components is the list of all available firmware components
-                  and their information.
-                items:
-                  description: FirmwareComponentStatus defines the status of a firmware
-                    component.
-                  properties:
-                    component:
-                      type: string
-                    currentVersion:
-                      type: string
-                    initialVersion:
-                      type: string
-                    lastVersionFlashed:
-                      type: string
-                    updatedAt:
-                      format: date-time
-                      type: string
-                  required:
-                  - component
-                  - initialVersion
-                  type: object
-                type: array
-              conditions:
-                description: Track whether updates stored in the spec are valid based
-                  on the schema
-                items:
-                  description: "Condition contains details for one aspect of the current
-                    state of this API Resource. --- This struct is intended for direct
-                    use as an array at the field path .status.conditions.  For example,
-                    \n type FooStatus struct{ // Represents the observations of a
-                    foo's current state. // Known .status.conditions.type are: \"Available\",
-                    \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
-                    // +listType=map // +listMapKey=type Conditions []metav1.Condition
-                    `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
-                    protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
-                  properties:
-                    lastTransitionTime:
-                      description: lastTransitionTime is the last time the condition
-                        transitioned from one status to another. This should be when
-                        the underlying condition changed.  If that is not known, then
-                        using the time when the API field changed is acceptable.
-                      format: date-time
-                      type: string
-                    message:
-                      description: message is a human readable message indicating
-                        details about the transition. This may be an empty string.
-                      maxLength: 32768
-                      type: string
-                    observedGeneration:
-                      description: observedGeneration represents the .metadata.generation
-                        that the condition was set based upon. For instance, if .metadata.generation
-                        is currently 12, but the .status.conditions[x].observedGeneration
-                        is 9, the condition is out of date with respect to the current
-                        state of the instance.
-                      format: int64
-                      minimum: 0
-                      type: integer
-                    reason:
-                      description: reason contains a programmatic identifier indicating
-                        the reason for the condition's last transition. Producers
-                        of specific condition types may define expected values and
-                        meanings for this field, and whether the values are considered
-                        a guaranteed API. The value should be a CamelCase string.
-                        This field may not be empty.
-                      maxLength: 1024
-                      minLength: 1
-                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
-                      type: string
-                    status:
-                      description: status of the condition, one of True, False, Unknown.
-                      enum:
-                      - "True"
-                      - "False"
-                      - Unknown
-                      type: string
-                    type:
-                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
-                        --- Many .condition.type values are consistent across resources
-                        like Available, but because arbitrary conditions can be useful
-                        (see .node.status.conditions), the ability to deconflict is
-                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
-                      maxLength: 316
-                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
-                      type: string
-                  required:
-                  - lastTransitionTime
-                  - message
-                  - reason
-                  - status
-                  - type
-                  type: object
-                type: array
-                x-kubernetes-list-map-keys:
-                - type
-                x-kubernetes-list-type: map
-              lastUpdated:
-                description: Time that the status was last updated
-                format: date-time
-                type: string
-              updates:
-                description: Updates is the list of all firmware components that should
-                  be updated they are specified via name and url fields.
-                items:
-                  description: FirmwareUpdate defines a firmware update specification.
-                  properties:
-                    component:
-                      type: string
-                    url:
-                      type: string
-                  required:
-                  - component
-                  - url
-                  type: object
-                type: array
-            required:
-            - components
-            - updates
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
 metadata:
   annotations:
     controller-gen.kubebuilder.io/version: v0.12.1
@@ -2284,32 +2103,6 @@ rules:
   - patch
   - update
   - watch
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwarecomponents
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwarecomponents/finalizers
-  verbs:
-  - update
-- apiGroups:
-  - metal3.io
-  resources:
-  - hostfirmwarecomponents/status
-  verbs:
-  - get
-  - patch
-  - update
 - apiGroups:
   - metal3.io
   resources:
diff --git a/config/samples/metal3.io_v1alpha1_hostfirmwarecomponents.yaml b/config/samples/metal3.io_v1alpha1_hostfirmwarecomponents.yaml
index f5b2537d..3283a8c7 100644
--- a/config/samples/metal3.io_v1alpha1_hostfirmwarecomponents.yaml
+++ b/config/samples/metal3.io_v1alpha1_hostfirmwarecomponents.yaml
@@ -1,13 +1,7 @@
 apiVersion: metal3.io/v1alpha1
 kind: HostFirmwareComponents
 metadata:
-  labels:
-    app.kubernetes.io/name: hostfirmwarecomponents
-    app.kubernetes.io/instance: hostfirmwarecomponents-sample
-    app.kubernetes.io/part-of: baremetal-operator
-    app.kubernetes.io/managed-by: kustomize
-    app.kubernetes.io/created-by: baremetal-operator
-  name: hostfirmwarecomponents-sample
+  namespace: host3firmwarecomponents.metal3.io
 spec:
   updates:
   - name: bios
diff --git a/controllers/metal3.io/baremetalhost_controller.go b/controllers/metal3.io/baremetalhost_controller.go
index 8dd6d9e4..7b9d8346 100644
--- a/controllers/metal3.io/baremetalhost_controller.go
+++ b/controllers/metal3.io/baremetalhost_controller.go
@@ -93,11 +93,10 @@ func (info *reconcileInfo) publishEvent(reason, message string) {
 // +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;update;delete
 // +kubebuilder:rbac:groups="",resources=events,verbs=get;list;watch;create;update;patch
 
-// Allow for managing hostfirmwaresettings, firmwareschema, bmceventsubscriptions and hostfirmwarecomponents
+// Allow for managing hostfirmwaresettings and firmwareschema
 //+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwaresettings,verbs=get;list;watch;create;update;patch
 //+kubebuilder:rbac:groups=metal3.io,resources=firmwareschemas,verbs=get;list;watch;create;update;patch
 //+kubebuilder:rbac:groups=metal3.io,resources=bmceventsubscriptions,verbs=get;list;watch;create;update;patch
-//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwarecomponents,verbs=get;list;watch;create;update;patch
 
 // Reconcile handles changes to BareMetalHost resources.
 func (r *BareMetalHostReconciler) Reconcile(ctx context.Context, request ctrl.Request) (result ctrl.Result, err error) {
diff --git a/controllers/metal3.io/hostfirmwarecomponents_controller.go b/controllers/metal3.io/hostfirmwarecomponents_controller.go
deleted file mode 100644
index 3e6eedf0..00000000
--- a/controllers/metal3.io/hostfirmwarecomponents_controller.go
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
-
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package controllers
-
-import (
-	"context"
-	"fmt"
-	"reflect"
-
-	corev1 "k8s.io/api/core/v1"
-	k8serrors "k8s.io/apimachinery/pkg/api/errors"
-	"k8s.io/apimachinery/pkg/api/meta"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/controller"
-	"sigs.k8s.io/controller-runtime/pkg/event"
-	"sigs.k8s.io/controller-runtime/pkg/predicate"
-
-	"github.com/go-logr/logr"
-	metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/metal3-io/baremetal-operator/pkg/provisioner"
-)
-
-// HostFirmwareComponentsReconciler reconciles a HostFirmwareComponents object.
-type HostFirmwareComponentsReconciler struct {
-	client.Client
-	Log                logr.Logger
-	ProvisionerFactory provisioner.Factory
-}
-
-// rhfcInfo is used to simplify the pass or arguments.
-type rhfcInfo struct {
-	ctx    context.Context
-	log    logr.Logger
-	hfc    *metal3api.HostFirmwareComponents
-	bmh    *metal3api.BareMetalHost
-	events []corev1.Event
-}
-
-type conditionReasonHFC string
-
-const (
-	reasonInvalidComponent conditionReasonHFC = "InvalidComponent"
-	reasonValidComponent   conditionReasonHFC = "OK"
-)
-
-func (info *rhfcInfo) publishEvent(reason, message string) {
-	t := metav1.Now()
-	hfcEvent := corev1.Event{
-		ObjectMeta: metav1.ObjectMeta{
-			GenerateName: reason + "-",
-			Namespace:    info.hfc.ObjectMeta.Namespace,
-		},
-		InvolvedObject: corev1.ObjectReference{
-			Kind:       info.hfc.Kind,
-			Namespace:  info.hfc.Namespace,
-			Name:       info.hfc.Name,
-			UID:        info.hfc.UID,
-			APIVersion: metal3api.GroupVersion.String(),
-		},
-		Reason:  reason,
-		Message: message,
-		Source: corev1.EventSource{
-			Component: "metal3-hostfirmwarecomponents-controller",
-		},
-		FirstTimestamp:      t,
-		LastTimestamp:       t,
-		Count:               1,
-		Type:                corev1.EventTypeNormal,
-		ReportingController: "metal3.io/hostfirmwarecomponents-controller",
-	}
-
-	info.events = append(info.events, hfcEvent)
-}
-
-//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwarecomponents,verbs=get;list;watch;create;update;patch;delete
-//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwarecomponents/status,verbs=get;update;patch
-//+kubebuilder:rbac:groups=metal3.io,resources=hostfirmwarecomponents/finalizers,verbs=update
-
-// Reconcile handles changes to HostFirmwareComponents resources.
-func (r *HostFirmwareComponentsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) {
-	reqLogger := r.Log.WithValues("hostfirmwarecomponents", req.NamespacedName)
-	reqLogger.Info("start")
-
-	// Get the corresponding baremetalhost in this namespace, if one doesn't exist don't continue processing
-	bmh := &metal3api.BareMetalHost{}
-	err = r.Get(ctx, req.NamespacedName, bmh)
-	if err != nil {
-		if k8serrors.IsNotFound(err) {
-			return ctrl.Result{}, nil
-		}
-		reqLogger.Error(err, "could not get baremetal host, not running hostfirmwarecomponents reconciler")
-		return ctrl.Result{Requeue: true, RequeueAfter: resourceNotAvailableRetryDelay}, err
-	}
-
-	if hasDetachedAnnotation(bmh) {
-		reqLogger.Info("the host is detached, not running hostfirmwarecomponents reconciler")
-		return ctrl.Result{Requeue: true, RequeueAfter: unmanagedRetryDelay}, nil
-	}
-	// If the reconciliation is paused, requeue
-	annotations := bmh.GetAnnotations()
-
-	if _, ok := annotations[metal3api.PausedAnnotation]; ok {
-		reqLogger.Info("host is paused, no work to do")
-		return ctrl.Result{Requeue: true, RequeueAfter: subResourceNotReadyRetryDelay}, nil
-	}
-
-	// Fetch the HostFirmwareComponents
-	hfc := &metal3api.HostFirmwareComponents{}
-	info := &rhfcInfo{ctx: ctx, log: reqLogger, hfc: hfc, bmh: bmh}
-	if err = r.Get(ctx, req.NamespacedName, hfc); err != nil {
-		// The HFC resource may have been deleted
-		if k8serrors.IsNotFound(err) {
-			reqLogger.Info("HostFirmwareComponents not found")
-			return ctrl.Result{Requeue: false}, err
-		}
-		// Error reading the object - requeue the request.
-		return ctrl.Result{}, fmt.Errorf("could not load hostFirmwareComponents: %w", err)
-	}
-
-	// Create a provisioner to access Ironic API
-	prov, err := r.ProvisionerFactory.NewProvisioner(ctx, provisioner.BuildHostDataNoBMC(*bmh), info.publishEvent)
-	if err != nil {
-		return ctrl.Result{}, fmt.Errorf("failed to create provisioner: %w", err)
-	}
-
-	ready, err := prov.TryInit()
-	if err != nil || !ready {
-		var msg string
-		if err == nil {
-			msg = "not ready"
-		} else {
-			msg = err.Error()
-		}
-		reqLogger.Info("provisioner is not ready", "Error", msg, "RequeueAfter", provisionerRetryDelay)
-		return ctrl.Result{Requeue: true, RequeueAfter: provisionerRetryDelay}, nil
-	}
-
-	newStatus, err := r.updateHostFirmware(info)
-	if err != nil {
-		return ctrl.Result{}, fmt.Errorf("could not update hostfirmwarecomponents: %w", err)
-	}
-
-	// Check ironic for the components information if possible
-	components, err := prov.GetFirmwareComponents()
-	info.log.Info("retrieving firmware components and saving to resource", "Node", bmh.Status.Provisioning.ID)
-
-	if err != nil {
-		reqLogger.Error(err, "provisioner returns error", "RequeueAfter", provisionerRetryDelay)
-		setUpdatesCondition(info.hfc.GetGeneration(), &newStatus, info, metal3api.HostFirmwareComponentsValid, metav1.ConditionFalse, reasonInvalidComponent, err.Error())
-		return ctrl.Result{Requeue: true, RequeueAfter: provisionerRetryDelay}, err
-	}
-
-	if err = r.updateHostFirmwareComponents(newStatus, components, info); err != nil {
-		return ctrl.Result{Requeue: false}, err
-	}
-
-	for _, e := range info.events {
-		r.publishEvent(info.ctx, req, e)
-	}
-
-	if meta.IsStatusConditionTrue(info.hfc.Status.Conditions, string(metal3api.HostFirmwareComponentsChangeDetected)) {
-		return ctrl.Result{Requeue: true, RequeueAfter: reconcilerRequeueDelayChangeDetected}, nil
-	}
-	return ctrl.Result{Requeue: true, RequeueAfter: reconcilerRequeueDelay}, nil
-}
-
-// Update the HostFirmwareComponents resource using the components from provisioner.
-func (r *HostFirmwareComponentsReconciler) updateHostFirmware(info *rhfcInfo) (newStatus metal3api.HostFirmwareComponentsStatus, err error) {
-	dirty := false
-
-	// change the Updates in Status
-	newStatus.Updates = info.hfc.Spec.Updates
-
-	// Check if the updates in the Spec are different than Status
-	updatesMismatch := !reflect.DeepEqual(info.hfc.Status.Updates, info.hfc.Spec.Updates)
-
-	reason := reasonValidComponent
-	generation := info.hfc.GetGeneration()
-
-	if updatesMismatch {
-		if setUpdatesCondition(generation, &newStatus, info, metal3api.HostFirmwareComponentsChangeDetected, metav1.ConditionTrue, reason, "") {
-			dirty = true
-		}
-
-		err := r.validateHostFirmwareComponents(info)
-		if err != nil {
-			info.publishEvent("ValidationFailed", fmt.Sprintf("Invalid Firmware Components: %s", err))
-			reason = reasonInvalidComponent
-			if setUpdatesCondition(generation, &newStatus, info, metal3api.HostFirmwareComponentsValid, metav1.ConditionFalse, reason, fmt.Sprintf("Invalid Firmware Components: %s", err)) {
-				dirty = true
-			}
-		} else if setUpdatesCondition(generation, &newStatus, info, metal3api.HostFirmwareComponentsValid, metav1.ConditionTrue, reason, "") {
-			dirty = true
-		}
-	} else {
-		if setUpdatesCondition(generation, &newStatus, info, metal3api.HostFirmwareComponentsValid, metav1.ConditionTrue, reason, "") {
-			dirty = true
-		}
-		if setUpdatesCondition(generation, &newStatus, info, metal3api.HostFirmwareComponentsChangeDetected, metav1.ConditionFalse, reason, "") {
-			dirty = true
-		}
-	}
-
-	// Update Status if has changed
-	if dirty {
-		info.log.Info("Status for HostFirmwareComponents changed")
-		info.hfc.Status = *newStatus.DeepCopy()
-
-		t := metav1.Now()
-		info.hfc.Status.LastUpdated = &t
-		return newStatus, r.Status().Update(info.ctx, info.hfc)
-	}
-	return newStatus, nil
-}
-
-// Update the HostFirmwareComponents resource using the components from provisioner.
-func (r *HostFirmwareComponentsReconciler) updateHostFirmwareComponents(newStatus metal3api.HostFirmwareComponentsStatus, components []metal3api.FirmwareComponentStatus, info *rhfcInfo) (err error) {
-	dirty := false
-	// change the Components in Status
-	newStatus.Components = components
-	// Check if the components information we retrieved is different from the one in Status
-	componentsInfoMismatch := !reflect.DeepEqual(components, info.hfc.Status.Components)
-	reason := reasonValidComponent
-	generation := info.hfc.GetGeneration()
-	// Log the components we have
-	info.log.Info("firmware components for node", "components", components, "bmh", info.bmh.Name)
-	if componentsInfoMismatch {
-		setUpdatesCondition(generation, &newStatus, info, metal3api.HostFirmwareComponentsChangeDetected, metav1.ConditionTrue, reason, "")
-		dirty = true
-	}
-	if dirty {
-		info.log.Info("Components Status for HostFirmwareComponents changed")
-		info.hfc.Status = *newStatus.DeepCopy()
-
-		t := metav1.Now()
-		info.hfc.Status.LastUpdated = &t
-		return r.Status().Update(info.ctx, info.hfc)
-	}
-	return nil
-}
-
-// SetupWithManager sets up the controller with the Manager.
-func (r *HostFirmwareComponentsReconciler) SetupWithManager(mgr ctrl.Manager, maxConcurrentReconcile int) error {
-	return ctrl.NewControllerManagedBy(mgr).
-		For(&metal3api.HostFirmwareComponents{}).
-		WithOptions(controller.Options{MaxConcurrentReconciles: maxConcurrentReconcile}).
-		WithEventFilter(
-			predicate.Funcs{
-				UpdateFunc: r.updateEventHandler,
-			}).
-		Complete(r)
-}
-
-func (r *HostFirmwareComponentsReconciler) updateEventHandler(e event.UpdateEvent) bool {
-	r.Log.Info("hostfirmwarecomponents in event handler")
-
-	return e.ObjectNew.GetGeneration() != e.ObjectOld.GetGeneration()
-}
-
-func (r *HostFirmwareComponentsReconciler) validateHostFirmwareComponents(info *rhfcInfo) []error {
-	var errors []error
-	allowedNames := map[string]struct{}{"bmc": {}, "bios": {}}
-	for _, update := range info.hfc.Spec.Updates {
-		componentName := update.Component
-		if _, ok := allowedNames[componentName]; !ok {
-			errors = append(errors, fmt.Errorf("component %s is invalid, only 'bmc' or 'bios' are allowed as update names", componentName))
-		}
-		if len(errors) == 0 {
-			componentInStatus := false
-			for _, componentStatus := range info.hfc.Status.Components {
-				if componentName == componentStatus.Component {
-					componentInStatus = true
-					break
-				}
-			}
-			if !componentInStatus {
-				errors = append(errors, fmt.Errorf("component %s is invalid because is not present in status", componentName))
-			}
-		}
-	}
-
-	return errors
-}
-
-func (r *HostFirmwareComponentsReconciler) publishEvent(ctx context.Context, request ctrl.Request, event corev1.Event) {
-	reqLogger := r.Log.WithValues("hostfirmwarecomponents", request.NamespacedName)
-	reqLogger.Info("publishing event", "reason", event.Reason, "message", event.Message)
-	err := r.Create(ctx, &event)
-	if err != nil {
-		reqLogger.Info("failed to record event, ignoring",
-			"reason", event.Reason, "message", event.Message, "error", err)
-	}
-}
-
-func setUpdatesCondition(generation int64, status *metal3api.HostFirmwareComponentsStatus, info *rhfcInfo,
-	cond metal3api.UpdatesConditionType, newStatus metav1.ConditionStatus,
-	reason conditionReasonHFC, message string) bool {
-	newCondition := metav1.Condition{
-		Type:               string(cond),
-		Status:             newStatus,
-		ObservedGeneration: generation,
-		Reason:             string(reason),
-		Message:            message,
-	}
-	currCond := meta.FindStatusCondition(info.hfc.Status.Conditions, string(cond))
-	meta.SetStatusCondition(&status.Conditions, newCondition)
-
-	if currCond == nil || currCond.Status != newStatus {
-		return true
-	}
-	return false
-}
diff --git a/ironic-deployment/base/ironic.yaml b/ironic-deployment/base/ironic.yaml
index 54cfb249..2af30f05 100644
--- a/ironic-deployment/base/ironic.yaml
+++ b/ironic-deployment/base/ironic.yaml
@@ -67,7 +67,7 @@ spec:
         - /bin/runironic
         livenessProbe:
           exec:
-            command: ["/bin/ironic-liveness"]
+            command: ["sh", "-c", "curl -sSf http://127.0.0.1:6385 || curl -sSfk https://127.0.0.1:6385"]
           initialDelaySeconds: 30
           periodSeconds: 30
           timeoutSeconds: 10
@@ -75,7 +75,7 @@ spec:
           failureThreshold: 10
         readinessProbe:
           exec:
-            command: ["/bin/ironic-readiness"]
+            command: ["sh", "-c", "curl -sSf http://127.0.0.1:6385 || curl -sSfk https://127.0.0.1:6385"]
           initialDelaySeconds: 30
           periodSeconds: 30
           timeoutSeconds: 10
diff --git a/ironic-deployment/components/tls/tls.yaml b/ironic-deployment/components/tls/tls.yaml
index fa50a59b..491eb7ea 100644
--- a/ironic-deployment/components/tls/tls.yaml
+++ b/ironic-deployment/components/tls/tls.yaml
@@ -7,6 +7,12 @@ spec:
     spec:
       containers:
       - name: ironic
+        readinessProbe:
+         exec:
+           command: ["sh", "-c", "curl -sSf http://127.0.0.1:6388"]
+        livenessProbe:
+         exec:
+           command: ["sh", "-c", "curl -sSf http://127.0.0.1:6388"]
         env:
         - name: IRONIC_REVERSE_PROXY_SETUP
           value: "true"
diff --git a/main.go b/main.go
index b5aa8d05..47ce07e4 100644
--- a/main.go
+++ b/main.go
@@ -291,15 +291,6 @@ func main() {
 		os.Exit(1)
 	}
 
-	if err = (&metal3iocontroller.HostFirmwareComponentsReconciler{
-		Client:             mgr.GetClient(),
-		Log:                ctrl.Log.WithName("controllers").WithName("HostFirmwareComponents"),
-		ProvisionerFactory: provisionerFactory,
-	}).SetupWithManager(mgr, maxConcurrency); err != nil {
-		setupLog.Error(err, "unable to create controller", "controller", "HostFirmwareComponents")
-		os.Exit(1)
-	}
-
 	setupChecks(mgr)
 
 	if enableWebhook {
diff --git a/pkg/provisioner/demo/demo.go b/pkg/provisioner/demo/demo.go
index 77e61b02..f6741975 100644
--- a/pkg/provisioner/demo/demo.go
+++ b/pkg/provisioner/demo/demo.go
@@ -302,7 +302,3 @@ func (p *demoProvisioner) AddBMCEventSubscriptionForNode(_ *metal3api.BMCEventSu
 func (p *demoProvisioner) RemoveBMCEventSubscriptionForNode(_ metal3api.BMCEventSubscription) (result provisioner.Result, err error) {
 	return result, nil
 }
-
-func (p *demoProvisioner) GetFirmwareComponents() (components []metal3api.FirmwareComponentStatus, err error) {
-	return components, nil
-}
diff --git a/pkg/provisioner/fixture/fixture.go b/pkg/provisioner/fixture/fixture.go
index 6b004a31..8005d07a 100644
--- a/pkg/provisioner/fixture/fixture.go
+++ b/pkg/provisioner/fixture/fixture.go
@@ -349,7 +349,3 @@ func (p *fixtureProvisioner) AddBMCEventSubscriptionForNode(_ *metal3api.BMCEven
 func (p *fixtureProvisioner) RemoveBMCEventSubscriptionForNode(_ metal3api.BMCEventSubscription) (result provisioner.Result, err error) {
 	return result, nil
 }
-
-func (p *fixtureProvisioner) GetFirmwareComponents() (components []metal3api.FirmwareComponentStatus, err error) {
-	return components, nil
-}
diff --git a/pkg/provisioner/ironic/ironic.go b/pkg/provisioner/ironic/ironic.go
index a9e6c793..5fe505e8 100644
--- a/pkg/provisioner/ironic/ironic.go
+++ b/pkg/provisioner/ironic/ironic.go
@@ -1152,53 +1152,6 @@ func (p *ironicProvisioner) GetFirmwareSettings(includeSchema bool) (settings me
 	return settings, schema, nil
 }
 
-// GetFirmwareComponents gets all available firmware components for a node and return a list.
-func (p *ironicProvisioner) GetFirmwareComponents() ([]metal3api.FirmwareComponentStatus, error) {
-	ironicNode, err := p.getNode()
-	if err != nil {
-		return nil, fmt.Errorf("could not get node to retrieve firmware components: %w", err)
-	}
-
-	if !p.availableFeatures.HasFirmwareUpdates() {
-		return nil, fmt.Errorf("current ironic version does not support firmware updates")
-	}
-	// Get the components from Ironic via Gophercloud
-	componentList, componentListErr := nodes.ListFirmware(p.ctx, p.client, ironicNode.UUID).Extract()
-
-	if componentListErr != nil {
-		bmcAccess, _ := p.bmcAccess()
-		if bmcAccess.FirmwareInterface() == "no-firmware" {
-			return nil, fmt.Errorf("node %s is using firmware interface %s: %w", ironicNode.UUID, bmcAccess.FirmwareInterface(), componentListErr)
-		}
-
-		return nil, fmt.Errorf("could not get firmware components for node %s: %w", ironicNode.UUID, componentListErr)
-	}
-
-	// Setting to 2 since we only support bmc and bios
-	componentsInfo := make([]metal3api.FirmwareComponentStatus, 0, 2)
-
-	// Iterate over the list of components to extract their information and update the list.
-	for _, fwc := range componentList {
-		if fwc.Component != "bios" && fwc.Component != "bmc" {
-			p.log.Info("ignoring firmware component for node", "component", fwc.Component, "node", ironicNode.UUID)
-			continue
-		}
-		component := metal3api.FirmwareComponentStatus{
-			Component:          fwc.Component,
-			InitialVersion:     fwc.InitialVersion,
-			CurrentVersion:     fwc.CurrentVersion,
-			LastVersionFlashed: fwc.LastVersionFlashed,
-			UpdatedAt: metav1.Time{
-				Time: *fwc.UpdatedAt,
-			},
-		}
-		componentsInfo = append(componentsInfo, component)
-		p.log.Info("firmware component added for node", "component", fwc.Component, "node", ironicNode.UUID)
-	}
-
-	return componentsInfo, componentListErr
-}
-
 // We can't just replace the capabilities because we need to keep the
 // values provided by inspection. We can't replace only the boot_mode
 // because the API isn't fine-grained enough for that. So we have to
diff --git a/pkg/provisioner/provisioner.go b/pkg/provisioner/provisioner.go
index 7a43209f..29a15d54 100644
--- a/pkg/provisioner/provisioner.go
+++ b/pkg/provisioner/provisioner.go
@@ -200,9 +200,6 @@ type Provisioner interface {
 
 	// RemoveBMCEventSubscriptionForNode delete the subscription
 	RemoveBMCEventSubscriptionForNode(subscription metal3api.BMCEventSubscription) (result Result, err error)
-
-	// GetFirmwareComponents gets all firmware components available from a note
-	GetFirmwareComponents() (components []metal3api.FirmwareComponentStatus, err error)
 }
 
 // Result holds the response from a call in the Provsioner API.


Test patch:
diff --git a/apis/metal3.io/v1alpha1/hostfirmwarecomponents_types_test.go b/apis/metal3.io/v1alpha1/hostfirmwarecomponents_types_test.go
index 649a4933..e3b3ab85 100644
--- a/apis/metal3.io/v1alpha1/hostfirmwarecomponents_types_test.go
+++ b/apis/metal3.io/v1alpha1/hostfirmwarecomponents_types_test.go
@@ -24,6 +24,7 @@ func TestValidateHostFirmwareComponents(t *testing.T) {
 					Component:      "bios",
 					InitialVersion: "1.0",
 					CurrentVersion: "1.0",
+					UpdatedAt:      metav1.NewTime(time.Now()),
 				},
 				{
 					Component:          "bmc",
diff --git a/controllers/metal3.io/host_state_machine_test.go b/controllers/metal3.io/host_state_machine_test.go
index 987a134d..fd02ecd2 100644
--- a/controllers/metal3.io/host_state_machine_test.go
+++ b/controllers/metal3.io/host_state_machine_test.go
@@ -1397,10 +1397,6 @@ func (m *mockProvisioner) RemoveBMCEventSubscriptionForNode(_ metal3api.BMCEvent
 	return result, nil
 }
 
-func (p *mockProvisioner) GetFirmwareComponents() (components []metal3api.FirmwareComponentStatus, err error) {
-	return components, nil
-}
-
 func TestUpdateBootModeStatus(t *testing.T) {
 	testCases := []struct {
 		Scenario       string
diff --git a/controllers/metal3.io/hostfirmwarecomponents_test.go b/controllers/metal3.io/hostfirmwarecomponents_test.go
deleted file mode 100644
index 1998d1a7..00000000
--- a/controllers/metal3.io/hostfirmwarecomponents_test.go
+++ /dev/null
@@ -1,550 +0,0 @@
-package controllers
-
-import (
-	"context"
-	"testing"
-
-	metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
-	"github.com/stretchr/testify/assert"
-
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
-	logf "sigs.k8s.io/controller-runtime/pkg/log"
-)
-
-// Test support for HostFirmwareComponents in the HostFirmwareComponentsReconciler.
-func getTestHFCReconciler(host *metal3api.HostFirmwareComponents) *HostFirmwareComponentsReconciler {
-	c := fakeclient.NewClientBuilder().WithRuntimeObjects(host).WithStatusSubresource(host).Build()
-
-	reconciler := &HostFirmwareComponentsReconciler{
-		Client: c,
-		Log:    ctrl.Log.WithName("test_reconciler").WithName("HostFirmwareComponents"),
-	}
-
-	return reconciler
-}
-
-func getMockHFCProvisioner(components []metal3api.FirmwareComponentStatus) *hfcMockProvisioner {
-	return &hfcMockProvisioner{
-		Components: components,
-		Error:      nil,
-	}
-}
-
-type hfcMockProvisioner struct {
-	Components []metal3api.FirmwareComponentStatus
-	Error      error
-}
-
-func (m *hfcMockProvisioner) GetFirmwareComponents() (components []metal3api.FirmwareComponentStatus, err error) {
-	return m.Components, m.Error
-}
-
-// Mock components to return from provisioner.
-func getCurrentComponents(updatedComponents string) []metal3api.FirmwareComponentStatus {
-	var components []metal3api.FirmwareComponentStatus
-	switch updatedComponents {
-	case "bmc":
-		components = []metal3api.FirmwareComponentStatus{
-			{
-				Component:          "bmc",
-				InitialVersion:     "1.0.0",
-				CurrentVersion:     "1.1.0",
-				LastVersionFlashed: "1.1.0",
-			},
-			{
-				Component:      "bios",
-				InitialVersion: "1.0.1",
-				CurrentVersion: "1.0.1",
-			},
-		}
-	case "bios":
-		components = []metal3api.FirmwareComponentStatus{
-			{
-				Component:      "bmc",
-				InitialVersion: "1.0.0",
-				CurrentVersion: "1.0.0",
-			},
-			{
-				Component:          "bios",
-				InitialVersion:     "1.0.1",
-				CurrentVersion:     "1.1.10",
-				LastVersionFlashed: "1.1.10",
-			},
-		}
-	default:
-		components = []metal3api.FirmwareComponentStatus{
-			{
-				Component:          "bmc",
-				InitialVersion:     "1.0.0",
-				CurrentVersion:     "1.1.0",
-				LastVersionFlashed: "1.1.0",
-			},
-			{
-				Component:          "bios",
-				InitialVersion:     "1.0.1",
-				CurrentVersion:     "1.1.10",
-				LastVersionFlashed: "1.1.10",
-			},
-		}
-	}
-
-	return components
-}
-
-// Create the baremetalhost reconciler and use that to create bmh in same namespace.
-func createBaremetalHostHFC() *metal3api.BareMetalHost {
-	bmh := &metal3api.BareMetalHost{}
-	bmh.ObjectMeta = metav1.ObjectMeta{Name: "hostName", Namespace: "hostNamespace"}
-	c := fakeclient.NewFakeClient(bmh)
-
-	reconciler := &BareMetalHostReconciler{
-		Client:             c,
-		ProvisionerFactory: nil,
-		Log:                ctrl.Log.WithName("bmh_reconciler").WithName("BareMetalHost"),
-	}
-	reconciler.Create(context.TODO(), bmh)
-
-	return bmh
-}
-
-// Create and HFC with input spec components.
-func getHFC(spec metal3api.HostFirmwareComponentsSpec) *metal3api.HostFirmwareComponents {
-	hfc := &metal3api.HostFirmwareComponents{}
-
-	hfc.Status = metal3api.HostFirmwareComponentsStatus{
-		Components: []metal3api.FirmwareComponentStatus{
-			{
-				Component:      "bmc",
-				InitialVersion: "1.0.0",
-				CurrentVersion: "1.0.0",
-			},
-			{
-				Component:      "bios",
-				InitialVersion: "1.0.1",
-				CurrentVersion: "1.0.1",
-			},
-		},
-	}
-
-	hfc.TypeMeta = metav1.TypeMeta{
-		Kind:       "HostFirmwareComponents",
-		APIVersion: "metal3.io/v1alpha1"}
-	hfc.ObjectMeta = metav1.ObjectMeta{
-		Name:      hostName,
-		Namespace: hostNamespace}
-
-	hfc.Spec = spec
-	return hfc
-}
-
-// Test the hostfirmwarecomponents reconciler functions.
-func TestStoreHostFirmwareComponents(t *testing.T) {
-	testCases := []struct {
-		Scenario           string
-		UpdatedComponents  string
-		CurrentHFCResource *metal3api.HostFirmwareComponents
-		ExpectedComponents *metal3api.HostFirmwareComponents
-	}{
-		{
-			Scenario:          "update bmc",
-			UpdatedComponents: "bmc",
-			CurrentHFCResource: &metal3api.HostFirmwareComponents{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "HostFirmwareComponents",
-					APIVersion: "metal3.io/v1alpha1"},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:            "hostName",
-					Namespace:       "hostNamespace",
-					ResourceVersion: "1"},
-				Spec: metal3api.HostFirmwareComponentsSpec{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bmc",
-							URL:       "https://myurl/newbmcfirmware",
-						},
-					},
-				},
-				Status: metal3api.HostFirmwareComponentsStatus{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bmc",
-							URL:       "https://myurls/newbmcfirmware",
-						},
-					},
-					Components: []metal3api.FirmwareComponentStatus{
-						{
-							Component:          "bmc",
-							InitialVersion:     "1.0.0",
-							CurrentVersion:     "1.1.0",
-							LastVersionFlashed: "1.1.0",
-						},
-						{
-							Component:      "bios",
-							InitialVersion: "1.0.1",
-							CurrentVersion: "1.0.1",
-						},
-					},
-				},
-			},
-			ExpectedComponents: &metal3api.HostFirmwareComponents{
-				Spec: metal3api.HostFirmwareComponentsSpec{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bmc",
-							URL:       "https://myurl/newbmcfirmware",
-						},
-					},
-				},
-				Status: metal3api.HostFirmwareComponentsStatus{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bmc",
-							URL:       "https://myurl/newbmcfirmware",
-						},
-					},
-					Components: []metal3api.FirmwareComponentStatus{
-						{
-							Component:          "bmc",
-							InitialVersion:     "1.0.0",
-							CurrentVersion:     "1.1.0",
-							LastVersionFlashed: "1.1.0",
-						},
-						{
-							Component:      "bios",
-							InitialVersion: "1.0.1",
-							CurrentVersion: "1.0.1",
-						},
-					},
-					Conditions: []metav1.Condition{
-						{Type: "ChangeDetected", Status: "True", Reason: "OK"},
-						{Type: "Valid", Status: "True", Reason: "OK"},
-					},
-				},
-			},
-		},
-		{
-			Scenario:          "update bios",
-			UpdatedComponents: "bios",
-			CurrentHFCResource: &metal3api.HostFirmwareComponents{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "HostFirmwareComponents",
-					APIVersion: "metal3.io/v1alpha1"},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:            "hostName",
-					Namespace:       "hostNamespace",
-					ResourceVersion: "1"},
-				Spec: metal3api.HostFirmwareComponentsSpec{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bios",
-							URL:       "https://myurl/newbiosfirmware",
-						},
-					},
-				},
-				Status: metal3api.HostFirmwareComponentsStatus{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bios",
-							URL:       "https://myurls/newbiosfirmware",
-						},
-					},
-					Components: []metal3api.FirmwareComponentStatus{
-						{
-							Component:      "bmc",
-							InitialVersion: "1.0.0",
-							CurrentVersion: "1.0.0",
-						},
-						{
-							Component:          "bios",
-							InitialVersion:     "1.0.1",
-							CurrentVersion:     "1.1.10",
-							LastVersionFlashed: "1.1.10",
-						},
-					},
-				},
-			},
-			ExpectedComponents: &metal3api.HostFirmwareComponents{
-				Spec: metal3api.HostFirmwareComponentsSpec{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bios",
-							URL:       "https://myurl/newbiosfirmware",
-						},
-					},
-				},
-				Status: metal3api.HostFirmwareComponentsStatus{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bios",
-							URL:       "https://myurl/newbiosfirmware",
-						},
-					},
-					Components: []metal3api.FirmwareComponentStatus{
-						{
-							Component:      "bmc",
-							InitialVersion: "1.0.0",
-							CurrentVersion: "1.0.0",
-						},
-						{
-							Component:          "bios",
-							InitialVersion:     "1.0.1",
-							CurrentVersion:     "1.1.10",
-							LastVersionFlashed: "1.1.10",
-						},
-					},
-					Conditions: []metav1.Condition{
-						{Type: "ChangeDetected", Status: "True", Reason: "OK"},
-						{Type: "Valid", Status: "True", Reason: "OK"},
-					},
-				},
-			},
-		},
-		{
-			Scenario:          "update all",
-			UpdatedComponents: "all",
-			CurrentHFCResource: &metal3api.HostFirmwareComponents{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       "HostFirmwareComponents",
-					APIVersion: "metal3.io/v1alpha1"},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:            "hostName",
-					Namespace:       "hostNamespace",
-					ResourceVersion: "1"},
-				Spec: metal3api.HostFirmwareComponentsSpec{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bmc",
-							URL:       "https://myurl/newbmcfirmware",
-						},
-						{
-							Component: "bios",
-							URL:       "https://myurl/newbiosfirmware",
-						},
-					},
-				},
-				Status: metal3api.HostFirmwareComponentsStatus{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bmc",
-							URL:       "https://myurl/newbmcfirmware",
-						},
-						{
-							Component: "bios",
-							URL:       "https://myurls/newbiosfirmware",
-						},
-					},
-					Components: []metal3api.FirmwareComponentStatus{
-						{
-							Component:          "bmc",
-							InitialVersion:     "1.0.0",
-							CurrentVersion:     "1.1.0",
-							LastVersionFlashed: "1.1.0",
-						},
-						{
-							Component:          "bios",
-							InitialVersion:     "1.0.1",
-							CurrentVersion:     "1.1.10",
-							LastVersionFlashed: "1.1.10",
-						},
-					},
-				},
-			},
-			ExpectedComponents: &metal3api.HostFirmwareComponents{
-				Spec: metal3api.HostFirmwareComponentsSpec{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bmc",
-							URL:       "https://myurl/newbmcfirmware",
-						},
-						{
-							Component: "bios",
-							URL:       "https://myurl/newbiosfirmware",
-						},
-					},
-				},
-				Status: metal3api.HostFirmwareComponentsStatus{
-					Updates: []metal3api.FirmwareUpdate{
-						{
-							Component: "bmc",
-							URL:       "https://myurl/newbmcfirmware",
-						},
-						{
-							Component: "bios",
-							URL:       "https://myurl/newbiosfirmware",
-						},
-					},
-					Components: []metal3api.FirmwareComponentStatus{
-						{
-							Component:          "bmc",
-							InitialVersion:     "1.0.0",
-							CurrentVersion:     "1.1.0",
-							LastVersionFlashed: "1.1.0",
-						},
-						{
-							Component:          "bios",
-							InitialVersion:     "1.0.1",
-							CurrentVersion:     "1.1.10",
-							LastVersionFlashed: "1.1.10",
-						},
-					},
-					Conditions: []metav1.Condition{
-						{Type: "ChangeDetected", Status: "True", Reason: "OK"},
-						{Type: "Valid", Status: "True", Reason: "OK"},
-					},
-				},
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.Scenario, func(t *testing.T) {
-			ctx := context.TODO()
-			prov := getMockHFCProvisioner(getCurrentComponents(tc.UpdatedComponents))
-
-			tc.ExpectedComponents.TypeMeta = metav1.TypeMeta{
-				Kind:       "HostFirmwareComponents",
-				APIVersion: "metal3.io/v1alpha1"}
-			tc.ExpectedComponents.ObjectMeta = metav1.ObjectMeta{
-				Name:            "hostName",
-				Namespace:       "hostNamespace",
-				ResourceVersion: "2"}
-
-			hfc := tc.CurrentHFCResource
-			r := getTestHFCReconciler(hfc)
-			// Create a bmh resource needed by hfc reconciler
-			bmh := createBaremetalHostHFC()
-
-			info := &rhfcInfo{
-				ctx: ctx,
-				log: logf.Log.WithName("controllers").WithName("HostFirmwareComponents"),
-				hfc: tc.CurrentHFCResource,
-				bmh: bmh,
-			}
-
-			currentStatus, err := r.updateHostFirmware(info)
-			assert.NoError(t, err)
-
-			components, err := prov.GetFirmwareComponents()
-			assert.NoError(t, err)
-			err = r.updateHostFirmwareComponents(currentStatus, components, info)
-			assert.NoError(t, err)
-
-			// Check that resources get created or updated
-			key := client.ObjectKey{
-				Namespace: hfc.ObjectMeta.Namespace, Name: hfc.ObjectMeta.Name}
-			actual := &metal3api.HostFirmwareComponents{}
-			err = r.Client.Get(ctx, key, actual)
-			assert.Equal(t, nil, err)
-
-			// Ensure ExpectedComponents matches actual
-			assert.Equal(t, tc.ExpectedComponents.Spec.Updates, actual.Spec.Updates)
-			assert.Equal(t, tc.ExpectedComponents.Status.Components, actual.Status.Components)
-			assert.Equal(t, tc.ExpectedComponents.Status.Updates, actual.Status.Updates)
-			currentTime := metav1.Now()
-			tc.ExpectedComponents.Status.LastUpdated = &currentTime
-			actual.Status.LastUpdated = &currentTime
-			for i := range tc.ExpectedComponents.Status.Conditions {
-				tc.ExpectedComponents.Status.Conditions[i].LastTransitionTime = currentTime
-				actual.Status.Conditions[i].LastTransitionTime = currentTime
-			}
-			assert.Equal(t, tc.ExpectedComponents.Status.LastUpdated, actual.Status.LastUpdated)
-			assert.Equal(t, tc.ExpectedComponents.Status.Conditions, actual.Status.Conditions)
-		})
-	}
-}
-
-// Test the function to validate the components in the Spec.
-func TestValidadeHostFirmwareComponents(t *testing.T) {
-	testCases := []struct {
-		Scenario       string
-		SpecUpdates    metal3api.HostFirmwareComponentsSpec
-		ExpectedErrors []string
-	}{
-		{
-			Scenario: "valid spec - all components",
-			SpecUpdates: metal3api.HostFirmwareComponentsSpec{
-				Updates: []metal3api.FirmwareUpdate{
-					{Component: "bmc", URL: "https://myurl/mybmcfw"},
-					{Component: "bios", URL: "https://myurl/mybiosfw"},
-				},
-			},
-			ExpectedErrors: []string{""},
-		},
-		{
-			Scenario: "valid spec - only bios",
-			SpecUpdates: metal3api.HostFirmwareComponentsSpec{
-				Updates: []metal3api.FirmwareUpdate{
-					{Component: "bios", URL: "https://myurl/mybiosfw"},
-				},
-			},
-			ExpectedErrors: []string{""},
-		},
-		{
-			Scenario: "valid spec - only bmc",
-			SpecUpdates: metal3api.HostFirmwareComponentsSpec{
-				Updates: []metal3api.FirmwareUpdate{
-					{Component: "bmc", URL: "https://myurl/mybmcfw"},
-				},
-			},
-			ExpectedErrors: []string{""},
-		},
-		{
-			Scenario: "invalid nic component",
-			SpecUpdates: metal3api.HostFirmwareComponentsSpec{
-				Updates: []metal3api.FirmwareUpdate{
-					{Component: "nic", URL: "https://myurl/mynicfw"},
-				},
-			},
-			ExpectedErrors: []string{"component nic is invalid, only 'bmc' or 'bios' are allowed as update names"},
-		},
-		{
-			Scenario: "invalid nic component with other valid components",
-			SpecUpdates: metal3api.HostFirmwareComponentsSpec{
-				Updates: []metal3api.FirmwareUpdate{
-					{Component: "bmc", URL: "https://myurl/mybmcfw"},
-					{Component: "bios", URL: "https://myurl/mybiosfw"},
-					{Component: "nic", URL: "https://myurl/mynicfw"},
-				},
-			},
-			ExpectedErrors: []string{"component nic is invalid, only 'bmc' or 'bios' are allowed as update names"},
-		},
-		{
-			Scenario: "component not in lowercase",
-			SpecUpdates: metal3api.HostFirmwareComponentsSpec{
-				Updates: []metal3api.FirmwareUpdate{
-					{Component: "BMC", URL: "https://myurl/mybmcfw"},
-					{Component: "BIOS", URL: "https://myurl/mybiosfw"},
-				},
-			},
-			ExpectedErrors: []string{
-				"component BMC is invalid, only 'bmc' or 'bios' are allowed as update names",
-				"component BIOS is invalid, only 'bmc' or 'bios' are allowed as update names",
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.Scenario, func(t *testing.T) {
-			ctx := context.TODO()
-			hfc := getHFC(tc.SpecUpdates)
-			r := getTestHFCReconciler(hfc)
-			info := rhfcInfo{
-				ctx: ctx,
-				log: logf.Log.WithName("controllers").WithName("HostFirmwareComponents"),
-				hfc: hfc,
-			}
-			errors := r.validateHostFirmwareComponents(&info)
-			if len(errors) == 0 {
-				assert.Equal(t, tc.ExpectedErrors[0], "")
-			} else {
-				for i := range errors {
-					assert.Equal(t, tc.ExpectedErrors[i], errors[i].Error())
-				}
-			}
-		})
-	}
-}
diff --git a/hack/ci-e2e.sh b/hack/ci-e2e.sh
index f828f088..e0b7d0a0 100755
--- a/hack/ci-e2e.sh
+++ b/hack/ci-e2e.sh
@@ -18,12 +18,37 @@ REPO_ROOT=$(realpath "$(dirname "${BASH_SOURCE[0]}")/..")
 
 cd "${REPO_ROOT}" || exit 1
 
-# BMO_E2E_EMULATOR can be set to either "vbmc" or "sushy-tools"
-BMO_E2E_EMULATOR=${BMO_E2E_EMULATOR:-"sushy-tools"}
-# We can choose to use redfish-virtualmedia or redfish as the protocol when using sushy-tools
-SUSHY_TOOLS_PROTOCOL=${SUSHY_TOOLS_PROTOCOL:-"redfish-virtualmedia"}
+# CI originally specified BMO_E2E_EMULATOR only. To avoid breaking it,
+# we need to set BMC_PROTOCOL based on this variable.
+# TODO(lentzi90): Change this to just set the BMO_E2E_EMULATOR based on the
+# BMC_PROTOCOL once CI has been adapted to use it.
+if [[ -z "${BMC_PROTOCOL:-}" ]]; then
+  # If no protocol is specified, we set it based on the emulator.
+  BMO_E2E_EMULATOR=${BMO_E2E_EMULATOR:-"sushy-tools"}
+  if [[ "${BMO_E2E_EMULATOR}" == "sushy-tools" ]]; then
+    BMC_PROTOCOL=${BMC_PROTOCOL:-${SUSHY_TOOLS_PROTOCOL:-"redfish-virtualmedia"}}
+  elif [[ "${BMO_E2E_EMULATOR}" == "vbmc" ]]; then
+    BMC_PROTOCOL=${BMC_PROTOCOL:-"ipmi"}
+  else
+    echo "FATAL: Invalid e2e emulator specified: ${BMO_E2E_EMULATOR}"
+    exit 1
+  fi
+else
+  # The protocol is set. Pick emulator based on it.
+  if [[ "${BMC_PROTOCOL}" == "redfish" ]] || [[ "${BMC_PROTOCOL}" == "redfish-virtualmedia" ]]; then
+    BMO_E2E_EMULATOR="sushy-tools"
+  elif [[ "${BMC_PROTOCOL}" == "ipmi" ]]; then
+    BMO_E2E_EMULATOR="vbmc"
+  else
+    echo "FATAL: Invalid BMC protocol specified: ${BMC_PROTOCOL}"
+    exit 1
+  fi
+fi
+echo "BMC_PROTOCOL=${BMC_PROTOCOL}"
+echo "BMO_E2E_EMULATOR=${BMO_E2E_EMULATOR}"
 
 export E2E_CONF_FILE="${REPO_ROOT}/test/e2e/config/ironic.yaml"
+export E2E_BMCS_CONF_FILE="${REPO_ROOT}/test/e2e/config/bmcs-${BMC_PROTOCOL}.yaml"
 
 case "${GINKGO_FOCUS:-}" in
   *upgrade*)
@@ -74,8 +99,6 @@ rm /tmp/bmo-e2e.tar
 IP_ADDRESS="192.168.222.1"
 
 if [[ "${BMO_E2E_EMULATOR}" == "vbmc" ]]; then
-  BMC_PROTOCOL="ipmi"
-  export E2E_BMCS_CONF_FILE="${REPO_ROOT}/test/e2e/config/bmcs-ipmi.yaml"
   # Start VBMC
   docker run --name vbmc --network host -d \
     -v /var/run/libvirt/libvirt-sock:/var/run/libvirt/libvirt-sock \
@@ -84,11 +107,8 @@ if [[ "${BMO_E2E_EMULATOR}" == "vbmc" ]]; then
 
 
 elif [[ "${BMO_E2E_EMULATOR}" == "sushy-tools" ]]; then
-  BMC_PROTOCOL=${SUSHY_TOOLS_PROTOCOL}
-  export E2E_BMCS_CONF_FILE="${REPO_ROOT}/test/e2e/config/bmcs-${SUSHY_TOOLS_PROTOCOL}.yaml"
   # Sushy-tools variables
   SUSHY_EMULATOR_FILE="${REPO_ROOT}"/test/e2e/sushy-tools/sushy-emulator.conf
-
   # Start sushy-tools
   docker run --name sushy-tools -d --network host \
     -v "${SUSHY_EMULATOR_FILE}":/etc/sushy/sushy-emulator.conf:Z \
@@ -97,7 +117,7 @@ elif [[ "${BMO_E2E_EMULATOR}" == "sushy-tools" ]]; then
     quay.io/metal3-io/sushy-tools:latest sushy-emulator
 
 else
-  echo "Invalid e2e emulator specified: ${BMO_E2E_EMULATOR}"
+  echo "FATAL: Invalid e2e emulator specified: ${BMO_E2E_EMULATOR}"
   exit 1
 fi