The curl -w argument in the command echo contains the literal text
'HTTP_CODE:%{http_code}', so raw.find("HTTP_CODE:") hits that first
and cuts search_area off before the actual JSON response body — leaving
data as {}. Switching to rfind targets the real HTTP_CODE:200 output
that curl appends at the end of the response.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_parse_network_data now returns mac, hostname, and link_status extracted
from the Redfish EthernetInterfaces/1 response (MACAddress, HostName,
LinkStatus fields confirmed present in live IOM output).
_print_results gains a second table — Interface Details (IOM | MAC | Hostname)
— between the Network Settings and Firmware Versions tables. Network Settings
table drops the redundant Origin column and adds Link Status instead.
Both _check_via_serial and _check_via_network updated to unpack and pass
the additional fields. fetch_current_config in workflow_serial.py also
updated to use the same address-parsing logic and trimmed table layout.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The serial cable connects to IOM1's console port. IOM2 cannot be queried
or configured via the serial connection. Updated all serial-path code to
reflect this:
workflow_serial.py:
- fetch_current_config: query IOM1 only, single-row table
- collect_network_config: prompt for IOM1 settings only, drop IOM2 section
- apply_configuration: apply to IOM1 only, single-row result table
- print_summary: IOM1-only table, updated warning text
workflow_check.py (_check_via_serial):
- Query IOM1 only for network settings, IOM firmware, and Fabric Card firmware
CLAUDE.md updated to document the IOM1-only serial limitation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The serial terminal echoes the curl command back before executing it.
The -w format string contains '%{http_code}' which includes a literal '{'.
When the terminal wraps long command lines (IOM2's path is ~70 chars),
that '{' can land at a line boundary, causing find("{") to pick up the
wrong position and produce garbled JSON/error output.
Fix: narrow the JSON search to the text before the HTTP_CODE: marker,
then use rfind("\n{") to find the last newline-prefixed '{'. The actual
curl response always starts on its own line, while the echoed '{http_code}'
is embedded mid-line in the command echo — so rfind("\n{") reliably skips it.
Also tighten the error snippet to use the same search_area bounds so the
displayed error shows actual response content rather than command echo text.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The BMC serial number (e.g. MXE3000048LHA03C) is embedded in the IOM
hostname shown in the serial login prompt. It also doubles as the root
password, so no manual entry is needed.
- If at login prompt: extract serial from 'hostname login:' line
- If already logged in: run 'hostname' on the shell and extract serial
- Falls back to prompt_password() if extraction fails either way
_login_serial_console() now returns (success, password) instead of bool.
Callers in workflow_serial.py and workflow_check.py updated accordingly.
CLAUDE.md updated to document the behaviour and remove it from planned features.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds _at_shell_prompt() helper that detects a shell prompt by checking
whether any line ends with '#' or '# ', rather than using a bare '#' in
response check guarded by 'login' not in output. The old guard caused a
false negative when the IOM echoed 'Last login: ...' text alongside the
prompt, sending an unnecessary login attempt to an active session.
Also broadens _ANSI_RE to catch all CSI escape sequences and two-character
ESC sequences, not just the original five terminal codes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Either IOM can reach the other via Redfish, so there's no need to collect
separate IOM1/IOM2 addresses. Firmware update and system check now prompt
for one IP per shelf with a note that either IOM's address works.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add firmware/ directory to hold firmware files for techs cloning the repo
- Scan firmware/ (relative to script location) instead of CWD
- Add .fwc to supported firmware extensions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each ES24N shelf has a unique Admin password (its BMC serial number), so a
single shared password is incorrect for multi-shelf runs. The password prompt
now appears once per shelf inside _collect_shelves(), stored as the first
element of each (password, [(iom, ip), ...]) shelf tuple. _make_targets()
threads the password into each (label, iom, ip, password) target entry, and
_show_fw_versions() uses the per-target password instead of a global one.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The firmware update workflow now supports updating any number of shelves in a
single run. After entering IPs for the first shelf, the user is prompted to
add another; this repeats until done. Firmware file and update-type choices
are made once and applied to all shelves sequentially.
_show_fw_versions() updated to accept (label, iom, ip) tuples so the display
label and Redfish path name can differ for multi-shelf tables (e.g. "S1 / IOM1"
vs "IOM1"). Pre- and post-update version tables include the shelf number when
more than one shelf is being updated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds workflow_check.py: a read-only diagnostic that queries current network
settings and firmware versions (IOM + Fabric Card) from both IOMs. Accessible
via a new main menu option (3 — System Check); Exit moves to option 4.
Supports both serial console (curl over the serial session) and direct network
(HTTPS to management IP) connection methods.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Redfish API at 127.0.0.1 is only accessible from within the IOM's
own shell, not directly from the host over the serial cable. The previous
approach of making urllib HTTPS requests from the host to 127.0.0.1 was
fundamentally incorrect.
Changes:
- serial_port.py: add optional per-call timeout override to
read_until_quiet() so curl responses have enough time to arrive
- workflow_serial.py:
- add _login_serial_console() — sends username/password over serial
and waits for a shell prompt before proceeding
- add _serial_redfish_request() — builds and sends a curl command
over the serial session, parses HTTP status and JSON from the output
- fetch_current_config(), apply_configuration(), _apply_iom() now
accept and use a SerialPort instance via _serial_redfish_request()
- configure_shelf() calls _login_serial_console() after collecting
the password, before making any Redfish calls
- remove unused _redfish_request import (HTTP transport no longer
used in the serial workflow)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update sys.path reference in es24n_conf.py and all documentation
to reflect the new folder name.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Document the new file structure, both connection methods (serial/network),
both workflows (serial config and firmware update), key design notes
(auth credentials, firmware bug workaround, API paths), and the planned
network-based config workflow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update module path reference in es24n_conf.py docstring to reflect
that modules now live in es24n/ rather than the root directory.
Add .gitignore to exclude __pycache__ and .pyc files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keeps the repo root clean with es24n_conf.py as the sole entry point.
All supporting modules (ui, serial_port, models, redfish, workflow_*)
now live in es24n/. The entry point adds es24n/ to sys.path at startup
so inter-module imports within the package remain unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Refactored the single 1200-line es24n_conf.py into six modules plus a
slim entry point, in preparation for the upcoming network-based config
workflow. Each file has a clear, single responsibility:
ui.py — ANSI colours, display primitives, input prompts
serial_port.py — SerialPort class (termios/fcntl/select)
models.py — IOMConfig and ShelfConfig dataclasses
redfish.py — Redfish API client (shared by all workflows)
workflow_serial.py — Serial-based IOM network configuration workflow
workflow_firmware.py — IOM and Fabric Card firmware update workflow
es24n_conf.py — Entry point and main menu only
No functional changes. All imports verified.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of requiring a manual path entry, scan the current working
directory for files with common firmware extensions and present them
as a numbered list (most recently modified first). The last option
always allows entering a custom path, and the manual prompt is used
as a fallback if no matching files are found.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously fetch_current_config silently dropped the error string when
an IOM failed to respond, showing only "No response". Now the specific
error (HTTP status, connection refused, timeout, etc.) is printed below
the table to aid diagnosis.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prompt user to choose IOM1 only, IOM2 only, or both before collecting
IPs or running updates. Only prompts for IPs of selected IOMs, and
suppresses the IOM1-first HA warning when updating a single IOM.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add option 2 to main menu: "Update IOM / Fabric Card Firmware"
- Add firmware_update_workflow() connecting to IOMs via network IP
- Add _redfish_upload_firmware() for multipart/form-data firmware upload
- Add _redfish_trigger_update() for Redfish SimpleUpdate action
- Add _redfish_poll_tasks() to monitor TaskService until completion
- Add _redfish_restart_iom() and _redfish_reset_fabric() for graceful restarts
- Add _get_iom_fw_version() and _get_fabric_fw_version() for validation
- Add host param to _redfish_request() (default 127.0.0.1, backward-compatible)
- Implements §12 of ES24N Product Service Guide v.26011
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>