Skip to content

Commit ab52bb0

Browse files
configure ironic inspection notifications for nautobot integration
1 parent fd94efc commit ab52bb0

File tree

13 files changed

+1601
-76
lines changed

13 files changed

+1601
-76
lines changed

components/site-workflows/sensors/sensor-ironic-oslo-event.yaml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ metadata:
1313
Resulting code should be very similar to:
1414
1515
```
16-
argo -n argo-events submit --from workflowtemplate/ironic-oslo-event \
16+
argo -n argo-events submit --from workflowtemplate/openstack-oslo-event \
1717
-p event-json "JSON-payload" -p device_id=<UUID> -p project_id=<UUID>
1818
```
1919
20-
Defined in `workflows/argo-events/sensors/sensor-ironic-oslo-event.yaml`
20+
Defined in `components/site-workflows/sensors/sensor-ironic-oslo-event.yaml`
2121
spec:
2222
dependencies:
2323
- eventName: openstack
@@ -43,6 +43,7 @@ spec:
4343
type: "string"
4444
value:
4545
- "deploying"
46+
- "inspecting"
4647
template:
4748
serviceAccountName: sensor-submit-workflow
4849
triggers:
@@ -64,6 +65,10 @@ spec:
6465
src:
6566
dataKey: body.ironic_object.lessee
6667
dependencyName: ironic-dep
68+
- dest: spec.arguments.parameters.3.value # previous_provision_state
69+
src:
70+
dataKey: body.ironic_object.previous_provision_state
71+
dependencyName: ironic-dep
6772
source:
6873
# create a workflow in argo-events prefixed with ironic-prov-
6974
resource:
@@ -81,6 +86,7 @@ spec:
8186
- name: event-json
8287
- name: device_id
8388
- name: project_id
89+
- name: previous_provision_state
8490
templates:
8591
- name: main
8692
steps:
@@ -93,6 +99,7 @@ spec:
9399
- name: event-json
94100
value: "{{workflow.parameters.event-json}}"
95101
- name: convert-project-id
102+
when: "\"{{workflow.parameters.previous_provision_state}}\" == deploying"
96103
inline:
97104
script:
98105
image: python:alpine
@@ -102,7 +109,7 @@ spec:
102109
project_id_without_dashes = "{{workflow.parameters.project_id}}"
103110
print(str(uuid.UUID(project_id_without_dashes)))
104111
- - name: ansible-storage-update
105-
when: "\"{{steps.oslo-events.outputs.parameters.storage}}\" == wanted"
112+
when: "\"{{steps.oslo-events.outputs.parameters.storage}}\" == wanted && \"{{workflow.parameters.previous_provision_state}}\" == deploying"
106113
templateRef:
107114
name: ansible-workflow-template
108115
template: ansible-run
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# Ironic to Nautobot Device and Interface Synchronization
2+
3+
This document explains how baremetal server devices and their Ethernet interfaces are automatically created and updated in Nautobot using hardware inspection data from OpenStack Ironic.
4+
5+
## Overview
6+
7+
The integration automatically synchronizes hardware inventory information from Ironic to Nautobot when a baremetal node completes the inspection phase. This ensures that Nautobot maintains an accurate, up-to-date inventory of physical servers and their network connectivity.
8+
9+
## Architecture
10+
11+
The synchronization flow is event-driven and uses the following components:
12+
13+
1. **Server Enrollment Workflow** - Enrolls servers and triggers inspection
14+
2. **OpenStack Ironic** - Performs hardware inspection and publishes Oslo events
15+
3. **Argo Events Sensor** - Listens for specific Ironic events
16+
4. **Argo Workflow** - Orchestrates the synchronization process
17+
5. **Python Workflow Scripts** - Process inspection data and update Nautobot
18+
19+
### Enrollment Workflow Context
20+
21+
The Nautobot synchronization is triggered as part of the broader server enrollment process:
22+
23+
**Workflow:** `enroll-server` (`workflows/argo-events/workflowtemplates/enroll-server.yaml`)
24+
25+
**Steps:**
26+
27+
1. `enroll-server` - Enrolls the server in Ironic using BMC credentials
28+
2. `manage-server` - Transitions node to `manageable` state
29+
3. `redfish-inspect` - **Triggers hardware inspection** (this is where inventory data is collected)
30+
4. `openstack-set-baremetal-node-raid-config` - Configures RAID
31+
5. `inspect-server` - Additional inspection if needed
32+
6. `avail-server` - Makes server available for provisioning
33+
34+
The `redfish-inspect` step executes:
35+
36+
```bash
37+
openstack baremetal node inspect --wait 0 <node-uuid>
38+
```
39+
40+
This inspection triggers the event that causes Nautobot to be updated with the discovered hardware information.
41+
42+
## Event Flow
43+
44+
```text
45+
Server Enrollment → Redfish Inspection → Oslo Event Bus → Argo Events Sensor → Argo Workflow → Update Nautobot
46+
```
47+
48+
### Step-by-Step Process
49+
50+
1. **Server Enrollment**
51+
- The `enroll-server` workflow is triggered with a BMC IP address
52+
- Workflow defined in: `workflows/argo-events/workflowtemplates/enroll-server.yaml`
53+
- Server is enrolled in Ironic and transitioned to `manageable` state
54+
55+
2. **Hardware Inspection**
56+
- The `redfish-inspect` step executes: `openstack baremetal node inspect --wait 0 <node-uuid>`
57+
- Ironic performs Redfish-based hardware inspection on the baremetal node
58+
- Inspection collects: CPU, memory, network interfaces, LLDP neighbor data, BMC information
59+
- Node transitions from `inspecting` state to `manageable` state
60+
61+
3. **Event Publication**
62+
- Ironic publishes `baremetal.node.provision_set.end` event to Oslo message bus
63+
- Event contains node UUID and provision state information
64+
- Event includes `previous_provision_state: inspecting` in the payload
65+
66+
4. **Event Detection**
67+
- Argo Events sensor `ironic-oslo-inspecting-event` listens for events
68+
- Filters for events where `previous_provision_state` was `inspecting`
69+
- Parses the Oslo message JSON payload
70+
71+
5. **Workflow Trigger**
72+
- Sensor creates an Argo Workflow named `update-nautobot-*`
73+
- Workflow uses template `openstack-oslo-event`
74+
- Event data is passed as workflow parameter
75+
76+
6. **Data Processing**
77+
- Workflow executes `openstack-oslo-event` script
78+
- Script fetches full inventory data from Ironic API using node UUID
79+
- Inventory data is parsed and transformed into Nautobot format
80+
81+
7. **Nautobot Update**
82+
- Device is created or updated in Nautobot
83+
- Network interfaces are created with MAC addresses
84+
- Cables are created based on LLDP neighbor information
85+
- IP addresses are assigned (for BMC interfaces)
86+
87+
## Configuration Files
88+
89+
### Sensor Configuration
90+
91+
**File:** `components/site-workflows/sensors/sensor-ironic-oslo-event.yaml`
92+
93+
The sensor configuration defines:
94+
95+
- Event source: `openstack-ironic`
96+
- Event type filter: `baremetal.node.provision_set.end`
97+
- State filter: `previous_provision_state == "inspecting"`
98+
- Workflow template to trigger
99+
100+
### Workflow Template
101+
102+
**File:** `workflows/argo-events/workflowtemplates/openstack-oslo-event.yaml`
103+
104+
The workflow template:
105+
106+
- Runs the `openstack-oslo-event` command
107+
- Mounts Nautobot token and OpenStack credentials
108+
- Passes event JSON as input file
109+
- Uses service account with appropriate permissions
110+
111+
## Data Processing
112+
113+
### Inventory Data Extraction
114+
115+
**Module:** `understack_workflows.ironic.inventory`
116+
117+
The inventory module performs the following transformations:
118+
119+
#### Interface Name Mapping
120+
121+
Linux interface names from Ironic are converted to Redfish-style names:
122+
123+
| Linux Name | Redfish Name | Description |
124+
|------------|--------------|-------------|
125+
| `eno8303` | `NIC.Embedded.1-1-1` | Embedded NIC port 1 |
126+
| `eno8403` | `NIC.Embedded.2-1-1` | Embedded NIC port 2 |
127+
| `eno3np0` | `NIC.Integrated.1-1` | Integrated NIC port 1 |
128+
| `ens2f0np0` | `NIC.Slot.1-1` | Slot NIC port 1 |
129+
130+
#### LLDP Data Parsing
131+
132+
LLDP (Link Layer Discovery Protocol) data is extracted from inspection results:
133+
134+
- **Chassis ID (Type 1)**: Remote switch MAC address
135+
- **Port ID (Type 2)**: Remote switch port name
136+
- **Port Description (Type 4)**: Alternative port identifier
137+
138+
#### Device Information
139+
140+
The following device attributes are extracted:
141+
142+
- **Manufacturer**: System vendor from `system_vendor.manufacturer` (e.g., Dell)
143+
- **Model Number**: Product name from `system_vendor.product_name` (stripped of parenthetical suffixes)
144+
- **Serial Number**: System serial number from `system_vendor.serial_number`
145+
- **BMC IP Address**: Out-of-band management IP from `bmc_address`
146+
- **BMC MAC Address**: BMC interface MAC address from `bmc_mac`
147+
- **BIOS Version**: Firmware version from `system_vendor.firmware.version`
148+
- **Memory**: Total RAM in GiB (converted from `memory.physical_mb`)
149+
- **CPU**: Processor model from `cpu.model_name`
150+
- **Power State**: Assumed to be powered on during inspection
151+
- **Hostname**: System hostname from inventory
152+
153+
#### Interface Information
154+
155+
For each network interface discovered during inspection, the following attributes are extracted:
156+
157+
**BMC Interface (iDRAC):**
158+
159+
- **Name**: "iDRAC"
160+
- **Description**: "Dedicated iDRAC interface"
161+
- **MAC Address**: From `bmc_mac` (normalized to uppercase)
162+
- **Hostname**: System hostname
163+
- **IPv4 Address**: From `bmc_address` (assumed /26 subnet)
164+
- **IPv4 Gateway**: Not set for Ironic-sourced data
165+
- **DHCP**: False (assumed static)
166+
- **LLDP Data**: Not collected for BMC interface
167+
168+
**Server Interfaces:**
169+
170+
- **Name**: Linux interface name converted to Redfish format (e.g., `eno8303``NIC.Embedded.1-1-1`)
171+
- **Description**: Network driver name + " interface" (e.g., "bnxt_en interface")
172+
- **MAC Address**: From interface `mac_address` (normalized to uppercase)
173+
- **Hostname**: System hostname
174+
- **IPv4 Address**: Not collected for server interfaces (only BMC has IP)
175+
- **LLDP Neighbor Data** (parsed from LLDP TLVs):
176+
- **Remote Switch MAC Address**: From LLDP TLV Type 1 (Chassis ID, subtype 4 - MAC address)
177+
- **Remote Switch Port Name**: From LLDP TLV Type 2 (Port ID) or Type 4 (Port Description)
178+
- **Data Staleness**: Marked as fresh (not stale) for Ironic inspection data
179+
180+
## Monitoring and Troubleshooting
181+
182+
### Viewing Workflow Executions
183+
184+
```bash
185+
# List recent workflows
186+
kubectl get workflows -n argo-events | grep update-nautobot
187+
188+
# View workflow details
189+
kubectl describe workflow update-nautobot-<id> -n argo-events
190+
191+
# View workflow logs
192+
kubectl logs -n argo-events <pod-name>
193+
```
194+
195+
## Testing
196+
197+
### Triggering Server Enrollment
198+
199+
To enroll a new server and trigger the complete flow:
200+
201+
```bash
202+
# Submit the enroll-server workflow with BMC IP address
203+
argo -n argo-events submit \
204+
--from workflowtemplate/enroll-server \
205+
-p ip_address="10.0.0.100"
206+
```
207+
208+
This will:
209+
210+
1. Enroll the server in Ironic
211+
2. Run hardware inspection (redfish-inspect step)
212+
3. Automatically trigger the Nautobot update via Oslo events
213+
214+
### Manual Inspection Re-trigger
215+
216+
To re-inspect an already enrolled server:
217+
218+
```bash
219+
# Trigger inspection manually
220+
openstack baremetal node inspect --wait <node-uuid>
221+
```
222+
223+
This will publish the Oslo event and trigger Nautobot synchronization.
224+
225+
### Manual Workflow Execution
226+
227+
You can manually trigger the Nautobot update workflow for testing:
228+
229+
```bash
230+
# To view inspect inventory data
231+
openstack baremetal node inventory save [--file <filename>] <node>
232+
233+
# Submit workflow manually
234+
argo -n argo-events submit \
235+
--from workflowtemplate/openstack-oslo-event \
236+
-p event-json '{"event_type":"baremetal.node.provision_set.end","payload":{"ironic_object.data":{"uuid":"<node-uuid>", "previous_provision_state":"inspecting"}}}'
237+
```
238+
239+
### Verifying Results
240+
241+
After workflow execution, verify in Nautobot:
242+
243+
1. Device exists with correct serial number
244+
2. Device is in correct location/rack
245+
3. All network interfaces are created
246+
4. MAC addresses are correct
247+
5. Cables connect to correct switch ports
248+
6. BMC interface has IP address assigned
249+
250+
## Related Components
251+
252+
- **Ironic Client** (`understack_workflows.ironic.client`): Wrapper for Ironic API
253+
- **Chassis Info** (`understack_workflows.bmc_chassis_info`): Data models for hardware info
254+
- **Nautobot Device** (`understack_workflows.nautobot_device`): Nautobot API operations
255+
256+
## References
257+
258+
- [PR #1361](https://github.com/rackerlabs/understack/pull/1361) - Implementation details

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ nav:
156156
- 'OpenStack':
157157
- operator-guide/openstack-ironic.md
158158
- operator-guide/openstack-ironic-inspection-guide.md
159+
- operator-guide/openstack-ironic-nautobot-device-interfaces-sync.md
159160
- operator-guide/openstack-ironic-change-boot-interface.md
160161
- operator-guide/openstack-neutron.md
161162
- operator-guide/openstack-placement.md

0 commit comments

Comments
 (0)