diff --git a/CLAUDE.md b/CLAUDE.md index ae592c1..5dc8f5a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,12 +39,12 @@ modules/ ## Workflows ### 1 — Serial Network Configuration (`workflow_serial.py`) -5-step workflow using the USB serial cable. **Serial access is limited to IOM1 only** — the cable connects to IOM1's console port; IOM2 cannot be queried or configured this way. +5-step workflow using the USB serial cable. The serial cable connects to one IOM's console port at a time — the user is prompted to select IOM1 or IOM2 after login, and all Redfish paths use that selection. 1. Detect USB serial device (`/dev/ttyUSB*`, `/dev/ttyACM*`, `/dev/ttyU*`) 2. Open 115200-baud 8N1 connection and wake the IOM console -3. Query IOM1 current network settings via Redfish (`GET` over `127.0.0.1`) -4. Collect new settings from user (Static IP or DHCP) for IOM1 -5. Apply via Redfish `PATCH` over `127.0.0.1` to IOM1 +3. Prompt for IOM1 or IOM2, then query current network settings via Redfish (`GET` over `127.0.0.1`) +4. Collect new settings from user (Static IP or DHCP) +5. Apply via Redfish `PATCH` over `127.0.0.1` ### 2 — Firmware Update (`workflow_firmware.py`) Updates IOM firmware and/or Fabric Card firmware over the network: diff --git a/modules/workflow_serial.py b/modules/workflow_serial.py index 090140e..8a160e2 100644 --- a/modules/workflow_serial.py +++ b/modules/workflow_serial.py @@ -340,20 +340,19 @@ def open_serial_connection(device: str) -> Optional[SerialPort]: # ── Step 3: Fetch & display current IOM network settings ───────────────────── -def fetch_current_config(cfg: ShelfConfig, ser: SerialPort) -> bool: +def fetch_current_config(cfg: ShelfConfig, ser: SerialPort, iom: str) -> bool: """ - Query Redfish for the current network config of IOM1 via curl over the - serial console session. Only IOM1 is reachable — the serial cable - connects to IOM1's console port; IOM2 cannot be queried this way. - Populates cfg.iom1 with live data. - Returns True if IOM1 responded successfully. + Query Redfish for the current network config of the connected IOM via curl + over the serial console session. Only the IOM whose console port the serial + cable is plugged into is reachable. + Populates cfg.iom1 with live data (regardless of whether IOM1 or IOM2). + Returns True if the IOM responded successfully. """ - rule("Step 3 of 5 -- Current IOM1 Network Settings") - info("Querying IOM1 Redfish API via serial console...") - info("Note: only IOM1 is reachable over the serial connection.") + rule(f"Step 3 of 5 -- Current {iom} Network Settings") + info(f"Querying {iom} Redfish API via serial console...") print() - path = "/redfish/v1/Managers/IOM1/EthernetInterfaces/1" + path = f"/redfish/v1/Managers/{iom}/EthernetInterfaces/1" ok_flag, data = _serial_redfish_request(ser, cfg.password, "GET", path) if ok_flag and isinstance(data, dict): @@ -373,7 +372,7 @@ def fetch_current_config(cfg: ShelfConfig, ser: SerialPort) -> bool: ip = gateway = netmask = "--" cfg.iom1 = IOMConfig( - iom = "IOM1", + iom = iom, dhcp = dhcp_enabled, ip = ip if ip != "--" else "", gateway = gateway if gateway != "--" else "", @@ -383,26 +382,26 @@ def fetch_current_config(cfg: ShelfConfig, ser: SerialPort) -> bool: mode_str = _c(C.CYN, "DHCP") if dhcp_enabled else _c(C.GRN, "Static") draw_table( ["IOM", "Mode", "IP Address", "Gateway", "Subnet Mask"], - [["IOM1", mode_str, ip, gateway, netmask]], + [[iom, mode_str, ip, gateway, netmask]], [5, 8, 15, 15, 15], ) print() return True else: draw_table( - ["IOM", "Mode", "Origin", "IP Address", "Gateway", "Subnet Mask"], - [["IOM1", _c(C.RED, "No response"), "--", "--", "--", "--"]], - [5, 10, 8, 16, 16, 16], + ["IOM", "Mode", "IP Address", "Gateway", "Subnet Mask"], + [[iom, _c(C.RED, "No response"), "--", "--", "--"]], + [5, 8, 15, 15, 15], ) print() - error(f"IOM1 query failed: {data}") - error("Check that the serial cable is connected and IOM1 is booted.") + error(f"{iom} query failed: {data}") + error(f"Check that the serial cable is connected and {iom} is booted.") print() return False # ── Step 4: Prompt user — change config or exit ─────────────────────────────── -def collect_network_config(cfg: ShelfConfig) -> bool: +def collect_network_config(cfg: ShelfConfig, iom: str) -> bool: """ Show current settings, ask user what to do. Returns True to proceed with applying changes, False to skip. @@ -425,7 +424,7 @@ def collect_network_config(cfg: ShelfConfig) -> bool: # ── User wants to change settings ───────────────────────────────────────── print() - print(" How should IOM1 be configured?") + print(f" How should {iom} be configured?") print(f" {_c(C.BOLD, '1')} Static IP address") print(f" {_c(C.BOLD, '2')} DHCP") print() @@ -440,16 +439,16 @@ def collect_network_config(cfg: ShelfConfig) -> bool: print() if use_dhcp: - cfg.iom1 = IOMConfig("IOM1", dhcp=True) - ok("IOM1 will be set to DHCP.") + cfg.iom1 = IOMConfig(iom, dhcp=True) + ok(f"{iom} will be set to DHCP.") return True - # Static — IOM1 - info(f"Static network details for {_c(C.BOLD, 'IOM1')}:") - iom1_ip = prompt_ip(" IOM1 IP address ") - iom1_gw = prompt_ip(" IOM1 Gateway ") - iom1_nm = prompt_ip(" IOM1 Subnet Mask") - cfg.iom1 = IOMConfig("IOM1", dhcp=False, ip=iom1_ip, gateway=iom1_gw, netmask=iom1_nm) + # Static + info(f"Static network details for {_c(C.BOLD, iom)}:") + ip = prompt_ip(f" {iom} IP address ") + gw = prompt_ip(f" {iom} Gateway ") + nm = prompt_ip(f" {iom} Subnet Mask") + cfg.iom1 = IOMConfig(iom, dhcp=False, ip=ip, gateway=gw, netmask=nm) return True @@ -598,11 +597,24 @@ def configure_shelf() -> bool: time.sleep(2) return True + # Prompt for which IOM the serial cable is connected to + print() + print(" Which IOM is the serial cable connected to?") + print(f" {_c(C.BOLD, '1')} IOM1") + print(f" {_c(C.BOLD, '2')} IOM2") + print() + while True: + iom_choice = prompt("Select [1/2]") + if iom_choice in ("1", "2"): + break + warn("Please enter 1 or 2.") + iom = "IOM1" if iom_choice == "1" else "IOM2" + # 3 — Fetch & display current settings - fetch_current_config(cfg, ser) + fetch_current_config(cfg, ser, iom) # 4 — Ask user: change or leave alone? - apply_changes = collect_network_config(cfg) + apply_changes = collect_network_config(cfg, iom) # 5 — Apply if requested changed = False