Kubernetes controller that manages bare metal hosts via OpenStack Ironic. Watches HostLease CRs (defined in bare-metal-fulfillment-operator) and reconciles power state with Ironic.
This controller filters HostLease CRs where spec.hostClass == "openstack" and uses spec.externalID as the Ironic node UUID. It reconciles the desired power state (spec.poweredOn) against the actual Ironic node power state, polling until they match.
Key behaviors:
spec.poweredOn = true— powers on the node via Ironicspec.poweredOn = false— powers off the node via Ironicspec.poweredOn = nil— unmanaged; skips power reconciliation- Sets
status.conditions[PowerSynced]to reflect sync state - Requeues with a configurable interval (
HOST_RECHECK_INTERVAL, default 60s) until power state matches
# Run all unit tests
go test ./internal/... ./cmd/...
# Run controller tests only
go test ./internal/controller/ -v
# Run ironic client tests only
go test ./internal/ironic/ -vRun the controller on your machine and point it at your Ironic API. You need a Kubernetes API (e.g. a kind cluster) so the controller can watch HostLease CRs.
kind create cluster --name host-mgmt-testThe HostLease CR is defined in the bare-metal-fulfillment-operator.
kubectl apply -f <path-to-bare-metal-fulfillment-operator>/config/crd/bases/osac.openshift.io_hostleases.yamlThe controller uses standard OpenStack authentication via OS_CLOUD (or OS_* env vars). Configure a clouds.yaml with your Ironic endpoint, then:
OS_CLOUD=<your-cloud-name> make runIn another terminal:
kubectl apply -f config/samples/v1alpha1_hostlease.yaml# Check HostLease status
kubectl get hostlease hostlease-sample -n osac-namespace -o yaml
# Watch controller logs for reconciliation- go version v1.25.0+
- podman (or docker)
- kubectl version v1.11.3+
- Access to a Kubernetes v1.11.3+ cluster
- Access to an OpenStack Ironic endpoint
Build and push your image to the location specified by IMG:
make image-build image-push IMG=<some-registry>/host-management-openstack:tagInstall the HostLease CRD (from bare-metal-fulfillment-operator):
kubectl apply -f <path-to-bare-metal-fulfillment-operator>/config/crd/bases/osac.openshift.io_hostleases.yamlDeploy the Manager to the cluster with the image specified by IMG:
make deploy IMG=<some-registry>/host-management-openstack:tagNOTE: If you encounter RBAC errors, you may need to grant yourself cluster-admin privileges or be logged in as admin.
Create instances of your solution You can apply the samples (examples) from the config/sample:
kubectl apply -k config/samples/Delete the instances (CRs) from the cluster:
kubectl delete -k config/samples/UnDeploy the controller from the cluster:
make undeployNOTE: Run make help for more information on all potential make targets
More information can be found via the Kubebuilder Documentation
Copyright 2026.
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.