Lab 01 — Redfish Client Against a Live Mock
Phase: 03 — Management Protocols | Difficulty: ⭐⭐⭐☆☆ | Time: 4–6 hours Language: Python 3 (stdlib only) | Hardware: none (in-process Redfish mock)
Concept primer:
../WARMUP.mdCh. 2–4,../HITCHHIKERS-GUIDE.md§1–§2, §5.
Run
python3 solution.py # starts a Redfish mock, walks it, performs Reset, subscribes
Run it for REAL against the DMTF Redfish-Mockup-Server (the extension — verified)
redfish_real.py reuses the exact same RedfishClient against an independent, real Redfish
service — proving the link-following design (the client doesn't change):
git clone https://github.com/DMTF/Redfish-Mockup-Server
pip install -r Redfish-Mockup-Server/requirements.txt
python3 Redfish-Mockup-Server/redfishMockupServer.py \
-D Redfish-Mockup-Server/public-rackmount1 -S -p 8000 & # -S = short-form mockup
python3 redfish_real.py http://localhost:8000
Verified output against DMTF's public-rackmount1 mockup:
System: id=437XR1138R2 model=3500 power=On (id is a vendor string, not hardcoded)
temp CPU1 Temp 41C
temp CPU2 Temp NoneC # a real sensor with no reading -> code defensively
power System Input Power 344 W
reset allowable: ['On','ForceOff','GracefulShutdown','GracefulRestart','ForceRestart','Nmi',...]
The System id is 437XR1138R2 — not node-00 or 1. That's exactly the vendor variance the
"follow @odata.id links, never hardcode" rule (WARMUP Ch. 3, 9) exists for; the client handles it
unchanged, and .get() tolerates the None-reading sensor. (You can also point it at OpenBMC's
sushy-emulator or a real BMC — same code.)
0. The mission
Write the Redfish client a rack manager is built on — and write it the right way: by
following @odata.id links from the ServiceRoot, not by hardcoding paths. To make it
runnable with zero setup, the lab spins up a small in-process Redfish HTTP mock; the client
code is the real thing and works unchanged against the DMTF mockup server, OpenBMC's
sushy-emulator, or a real BMC.
Two questions you must answer at the end:
- Why follow links instead of constructing
/redfish/v1/Systems/1/...? - Which resource holds power state, which holds temperature, and which holds BMC firmware?
1. What the client does (read RedfishClient)
| Operation | Method | Path discipline |
|---|---|---|
first_system() | GET ×3 | root → Systems collection → first member (all by link) |
power_for() / thermal_for() | GET | System → Links.Chassis → Power/Thermal (by link) |
reset() | POST | the action's advertised target; server validates AllowableValues |
subscribe() | POST | EventService/Subscriptions; returns 201 + Location |
Notice the System owns PowerState and the Reset action; the Chassis owns Power
(PSUs, draw, cap) and Thermal (temps, fans); the Manager owns BMC firmware. Putting
the right capability on the right resource is the core Redfish skill (WARMUP Ch. 2).
2. What the run shows
System node-00 (AI Compute Node 00) power=On health=OK
power: 1480 W consumed, cap 2000 W, PSUs ['OK', 'OK']
temp: Inlet 27C (crit 45)
temp: Accelerator0 71C (crit 90)
reset(GracefulShutdown) -> HTTP 204 ← action accepted (No Content)
power now: Off ← state actually changed
subscription created -> HTTP 201 at .../Subscriptions/sub-1
The self-tests additionally prove that an illegal ResetType is rejected with 400 (the
server checks AllowableValues), and that the subscription appears in the collection.
3. Extension exercises (do them — this is the lab)
- Run it against a real Redfish service. Install the DMTF mockup server
(
pip install redfish-mockup-serveror cloneDMTF/Redfish-Mockup-Server) or OpenBMC'ssushy-emulator, start it, and pointRedfishClient(base)at it. Your client should work unchanged — that's the payoff of following links. - Tasks: add an
UpdateServiceSimpleUpdate that returns 202 + a Task, and make the client poll the Task (TaskState,PercentComplete) to completion. This is the exact pattern Phase 08 firmware updates use. - Session auth: add a
SessionServiceto the mock; have the client POST credentials, capture theX-Auth-Token, send it on every request, andDELETEthe session at the end. Then add HTTPS with certificate validation (and a test that rejects a bad cert). $expand: implement$expand=.on the Systems collection so one GET returns all members inline, and discuss the round-trips-vs-payload tradeoff at fleet scale.- Fold into the driver abstraction: make
RedfishClientimplement theDeviceDriverinterface from WARMUP Ch. 8 so it's swappable with the IPMI/SNMP drivers from Lab 02.
4. Common pitfalls
- Hardcoding paths —
/redfish/v1/Systems/1works on one vendor and 404s on the next (IDs differ:1,System.Embedded.1, a UUID). Follow@odata.id. - Assuming fields exist — real BMCs omit optional fields and add
Oemblocks. Use.get()with defaults; validate presence. - Blocking on async operations — a firmware update returns a Task, not a result. Poll it; don't wait for a synchronous body.
- Disabling TLS verification — the single most common Redfish security bug. Validate the certificate; pin or trust the management CA.
- Re-authenticating per call — use a session token, not Basic auth on every request, at fleet scale.
5. What this lab proves about you
You can write the Redfish client at the heart of any rack-management product — correctly
(link-following, action validation, events) and portably (works against any conformant
service). In an interview, "discover a server's power and temperature over Redfish" becomes
a confident walk of ServiceRoot → System → Chassis → Power/Thermal, with the right notes on
Sessions, HTTPS, Tasks, and events. This client becomes a DeviceDriver backend in the
Phase 13 capstone and the data source for the Phase 07 exporter.