Skip to content

Commit 84f9add

Browse files
bogdandoopenshift-merge-bot[bot]
authored andcommitted
[multiple] extract bm sno into its own role
Rename: cifmw_reproducer_bm_ocp -> cifmw_bm_sno cifmw_devscripts_bm_nodes -> cifmw_bm_nodes Change defaults: openshift version, and auto-enable usb boot on target server BIOS. Also extract injection into a separate task, and cover with tests. Make sure no creds are leaking. Fix ejectinig already inserted image. On iDRAC 9 (fw 4.x), EjectMedia sets Inserted=false but the Image URL and internal Remote File Share connection linger indefinitely. Redfish PATCH on VirtualMedia/CD returns 405 (only GET,HEAD allowed), and no amount of waiting releases the stale RFS -- InsertMedia keeps failing with "already connected" (RH BZ#1910739). Work around this iDRAC limitation by SSH-ing into the BMC and running racadm directly, when Image persists after the Redfish eject. Generated-by: claude-4.6-opus-high Signed-off-by: Bohdan Dobrelia <bdobreli@redhat.com>
1 parent 5cd1ba9 commit 84f9add

35 files changed

Lines changed: 385 additions & 246 deletions

roles/bm_sno/README.md

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# bm_sno
2+
3+
Agent-based bare metal OCP SNO deployment via iDRAC Redfish APIs.
4+
5+
This role is included by the `reproducer` role when
6+
`cifmw_bm_sno: true`. It performs an agent-based installation on a
7+
physical bare metal host managed via iDRAC Redfish APIs. The workflow generates
8+
a self-contained agent ISO on the Zuul controller, pushes it to the target
9+
host's iDRAC via Redfish VirtualMedia, and waits for the host to self-install.
10+
11+
## Privilege escalation
12+
13+
Bare metal deployment requires privilege escalation for `/etc/hosts`
14+
management and running the ISO HTTP server via podman.
15+
16+
## Exposed tags
17+
18+
* `bm_ocp_layout`: Agent-based bare metal OCP layout tasks.
19+
20+
## Network architecture
21+
22+
Three routed isolated networks (no shared L2 domain required):
23+
24+
| Network | Purpose |
25+
| --- | --- |
26+
| BMC management | iDRAC interfaces; controller reaches iDRAC via routing |
27+
| BMO provision | Node's 1st NIC, OS interface IP; VirtualMedia boot |
28+
| Controller | Zuul controller; serves the agent ISO to iDRAC |
29+
30+
A 2nd NIC on the node carries isolated MetalLB networks for RHOSO EDPM
31+
services (ctlplane, internalapi, storage, tenant) via VLANs.
32+
33+
The `api` and `*.apps` DNS names resolve directly to the node's BMO
34+
provision IP via `/etc/hosts` entries managed by the role.
35+
36+
## Parameters
37+
38+
### Required (typically set in the scenario's vars.yaml)
39+
40+
| Parameter | Type | Description |
41+
| --- | --- | --- |
42+
| `cifmw_bm_agent_cluster_name` | str | OpenShift cluster name |
43+
| `cifmw_bm_agent_base_domain` | str | Base domain for the cluster |
44+
| `cifmw_bm_agent_machine_network` | str | BMO provision network CIDR |
45+
| `cifmw_bm_agent_node_ip` | str | Node IP on the BMO provision network |
46+
| `cifmw_bm_agent_node_iface` | str | RHCOS interface name on the BMO provision network |
47+
| `cifmw_bm_agent_bmc_host` | str | iDRAC hostname or IP on the BMC management network |
48+
| `cifmw_bm_nodes` | list | Single-element list with `mac` and `root_device` keys |
49+
| `cifmw_bm_agent_openshift_version` | str | OCP version (e.g. `"4.18.3"`); or set `cifmw_bm_agent_release_image` instead |
50+
51+
### Optional (have defaults or are auto-discovered)
52+
53+
| Parameter | Type | Default | Description |
54+
| --- | --- | --- | --- |
55+
| `cifmw_bm_agent_release_image` | str | `$OPENSHIFT_RELEASE_IMAGE` | Alternative to version: extract `openshift-install` from a release image |
56+
| `cifmw_bm_agent_iso_http_port` | int | `80` | Port for the podman HTTP server that serves the agent ISO (only a privileged port may accept external traffic on Zuul controllers) |
57+
| `cifmw_bm_agent_installer_timeout` | int | `7200` | Total seconds before the installer times out (split between bootstrap and install phases) |
58+
| `cifmw_manage_secrets_pullsecret_file` | str | `~/pull-secret` | Path to the pull secret JSON file |
59+
| `cifmw_bmc_credentials_file` | str | `~/secrets/idrac_access.yaml` | Path to a YAML file with `username` and `password` keys for iDRAC |
60+
| `cifmw_bm_agent_enable_usb_boot` | bool | `false` | Allow the role to automatically enable `GenericUsbBoot` in BIOS (requires a power cycle) |
61+
| `cifmw_bm_agent_vmedia_uefi_path` | str | auto-discovered | UEFI device path for the Virtual Optical Drive; auto-discovered from UEFI boot options if omitted |
62+
| `cifmw_bm_agent_core_password` | str || Set a `core` user password post-install via MachineConfig |
63+
| `cifmw_bm_agent_live_debug` | bool | `false` | Patch the agent ISO with password, autologin, and systemd debug shell on `tty6` for discovery-phase console access (requires `cifmw_bm_agent_core_password`) |
64+
65+
## Secrets management
66+
67+
The bare metal path requires two secret files:
68+
69+
### BMC credentials
70+
71+
A YAML file at `cifmw_bmc_credentials_file` (default `~/secrets/idrac_access.yaml`)
72+
with the following structure:
73+
74+
```yaml
75+
username: root
76+
password: <idrac-password>
77+
```
78+
79+
### Pull secret
80+
81+
The OCP pull secret JSON at `cifmw_manage_secrets_pullsecret_file`
82+
(default `~/pull-secret`).
83+
84+
## Task files
85+
86+
The agent-based deployment is composed of reusable task files under
87+
`tasks/`:
88+
89+
| Task file | Description |
90+
| --- | --- |
91+
| `main.yml` | Main orchestrator: validates variables, generates ISO, serves it via HTTP, manages VirtualMedia, waits for install completion |
92+
| `bm_power_on.yml` | Idempotent power-on via Redfish with POST wait (retries 30x at 10s intervals) |
93+
| `bm_power_off.yml` | Idempotent force power-off via Redfish with confirmation wait |
94+
| `bm_check_usb_boot.yml` | Reads `GenericUsbBoot` BIOS attribute and fails if disabled |
95+
| `bm_ensure_usb_boot.yml` | Wraps `bm_check_usb_boot.yml`; if disabled and `cifmw_bm_agent_enable_usb_boot` is true, sets the BIOS attribute, creates a config job, and power-cycles to apply |
96+
| `bm_eject_vmedia.yml` | Ejects VirtualMedia from the iDRAC Virtual Optical Drive |
97+
| `bm_discover_vmedia_target.yml` | Discovers or validates the UEFI device path for VirtualMedia, clears pending iDRAC config jobs, and sets a one-time boot override |
98+
| `bm_patch_agent_iso.yml` | Patches the agent ISO ignition with core password, autologin, and debug shell (used when `cifmw_bm_agent_live_debug` is true) |
99+
| `bm_core_password_machineconfig.yml` | Generates a MachineConfig manifest to set the core user password hash post-install |
100+
101+
## openshift-install acquisition
102+
103+
The `openshift-install` binary is obtained automatically via one of two
104+
methods, depending on which variable is set:
105+
106+
* **By version** (`cifmw_bm_agent_openshift_version`): downloads the tarball
107+
from `https://mirror.openshift.com/pub/openshift-v4/clients/ocp/<version>/openshift-install-linux.tar.gz`
108+
and extracts it.
109+
* **By release image** (`cifmw_bm_agent_release_image` or
110+
`OPENSHIFT_RELEASE_IMAGE` env var): runs
111+
`oc adm release extract --command=openshift-install` against the image.
112+
113+
If the binary already exists in the working directory it is reused.
114+
115+
## Deployment workflow
116+
117+
1. Validate required variables
118+
2. Ensure `GenericUsbBoot` is enabled in BIOS (auto-enable with power cycle if allowed)
119+
3. Power off the host
120+
4. Generate SSH keys, template `install-config.yaml` and `agent-config.yaml`
121+
5. Acquire `openshift-install` binary (see above) and run `openshift-install agent create image` to build the agent ISO
122+
6. Optionally patch the ISO for discovery-phase console access
123+
7. Serve the ISO via a root podman httpd container (rootless podman cannot use privileged ports)
124+
8. Eject any existing VirtualMedia, then insert the agent ISO
125+
9. Discover the Virtual Optical Drive UEFI path and set a one-time boot override
126+
10. Power on the host
127+
11. Verify BIOS `GenericUsbBoot` is enabled after POST
128+
12. Add `/etc/hosts` entries for `api`/`api-int` and `*.apps` domains
129+
13. Wait for bootstrap and install to complete
130+
14. Copy kubeconfig and kubeadmin-password to the dev-scripts-compatible auth directory
131+
15. Eject VirtualMedia and stop the HTTP server
132+
133+
## Molecule tests
134+
135+
### bm_redfish scenario
136+
137+
The `bm_redfish` Molecule scenario validates the bare metal Redfish task files
138+
(`bm_power_on`, `bm_power_off`, `bm_check_usb_boot`, `bm_ensure_usb_boot`,
139+
`bm_eject_vmedia`, `bm_discover_vmedia_target`) against a stateful Python
140+
mock iDRAC server that simulates Redfish API responses over HTTPS.
141+
142+
The mock server (`molecule/bm_redfish/files/mock_idrac.py`) provides:
143+
144+
* Stateful GET/POST/PATCH handlers for power, BIOS, VirtualMedia, boot
145+
override, and job queue Redfish endpoints
146+
* A `/test/reset` admin endpoint to set mock state between test cases
147+
* A `/test/state` endpoint to query current mock state for assertions
148+
* Self-signed TLS certificates generated during `prepare.yml`
149+
150+
Test coverage:
151+
152+
| Test file | Scenarios |
153+
| --- | --- |
154+
| `test_power_off.yml` | Already off (idempotent), On -> Off |
155+
| `test_power_on.yml` | Already on (idempotent), Off -> On |
156+
| `test_check_usb_boot.yml` | Enabled (succeeds), Disabled (expected failure) |
157+
| `test_ensure_usb_boot.yml` | Already enabled (no cycle), Disabled + auto-enable (BIOS change + cycle), Disabled + no auto-enable (expected failure) |
158+
| `test_eject_vmedia.yml` | Inserted (ejects), Not inserted (idempotent) |
159+
| `test_discover_vmedia.yml` | Auto-discover, user-provided valid path, user-provided invalid path (expected failure) |
160+
161+
## Examples
162+
163+
Minimal vars.yaml for a bare metal SNO deployment:
164+
165+
```YAML
166+
cifmw_bm_sno: true
167+
cifmw_bm_agent_cluster_name: ocp
168+
cifmw_bm_agent_base_domain: example.com
169+
cifmw_bm_agent_machine_network: "192.168.10.0/24"
170+
cifmw_bm_agent_node_ip: "192.168.10.50"
171+
cifmw_bm_agent_node_iface: eno12399np0
172+
cifmw_bm_agent_bmc_host: idrac.mgmt.example.com
173+
cifmw_bm_agent_openshift_version: "4.18.3"
174+
cifmw_bm_agent_enable_usb_boot: true
175+
176+
cifmw_bm_nodes:
177+
- mac: "b0:7b:25:xx:yy:zz"
178+
root_device: /dev/sda
179+
```
180+
181+
## References
182+
183+
* [ci-framework reproducer documentation](https://ci-framework.readthedocs.io/en/latest/roles/reproducer.html)
184+
* [Redfish API specification](https://www.dmtf.org/standards/redfish)
185+
* [Dell iDRAC Redfish API Guide](https://developer.dell.com/apis/2978/versions/6.xx/reference)

roles/bm_sno/defaults/main.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
cifmw_bm_agent_iso_http_port: 80
3+
cifmw_bm_agent_installer_timeout: 7200
4+
cifmw_bm_agent_openshift_version: "4.18.3"
5+
cifmw_bm_agent_core_password: "redhat"
6+
cifmw_bm_agent_live_debug: false
7+
cifmw_bm_agent_vmedia_uefi_path: ""
8+
cifmw_bm_agent_enable_usb_boot: true

roles/bm_sno/meta/main.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
galaxy_info:
3+
author: "Red Hat"
4+
description: >-
5+
Agent-based bare metal OCP SNO deployment via iDRAC Redfish APIs.
6+
license: "Apache-2.0"
7+
min_ansible_version: "2.11"
8+
9+
dependencies: []
File renamed without changes.
File renamed without changes.

roles/reproducer/molecule/bm_redfish/files/mock_idrac.py renamed to roles/bm_sno/molecule/bm_redfish/files/mock_idrac.py

File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)