# IBM HCI Manual Node Power Operations This guide explains how to perform node power operations on an IBM HCI (Hardware Converged Infrastructure) cluster **manually** — without running ocs-ci — using SSH, IPMI, and Redfish directly. Use this when: - ocs-ci is unavailable or you want to verify a node outside of a test run - The cluster API is unreachable and you need to recover nodes - You want to debug power management issues independently --- ## Architecture Overview ``` Test runner / you │ │ SSH (rack_ssh_username / rack_ssh_password) ▼ MGem / Rack host (rackIP from rack-details JSON) │ │ IPMI (Lenovo) or Redfish/curl (Dell) ▼ Node BMC (ipv4 / ipv6 from rack-details JSON) ``` All IPMI and Redfish commands are executed **on the MGem**, not from your local machine. The node BMC IPs are only routable from the MGem. --- ## Step 1 — Find Your Rack Details The rack-details JSON is saved at: ``` /rack_details/.json ``` `DATA_DIR` defaults to `/data` but can be overridden with the `OCSCI_DATA_DIR` environment variable. Backups are also kept at: - `/rack_details/_backup_.json` - `~/_rack_backup_.json` > **If the file does not exist**, see > [Step 1a — Generating the Rack Details File](#step-1a--generating-the-rack-details-file) > before continuing. --- ## Step 1a — Generating the Rack Details File The file is generated automatically when ocs-ci first initialises `IBMHCI`. If it is missing entirely (first run, or the file was deleted), build it manually using the steps below. ### Build manually (cluster API required) Use this when the cluster is accessible. **1. Collect BMC IPs from the kickstart ConfigMaps** If the cluster is still partially accessible, extract the data directly: ```bash # List all kickstart configmaps oc get configmap -n ibm-spectrum-fusion-ns | grep kickstart- # Dump one configmap (replace kickstart- with your rack serial) oc get configmap kickstart- -n ibm-spectrum-fusion-ns -o jsonpath='{.data}' | python3 -m json.tool ``` The JSON value inside the configmap contains a `computeNodeIntegratedManagementModules` array with each node's `OCPRole`, `ipv4`, `ipv6`, `manufacturer`, and `secretName`. **2. Fetch BMC credentials from node secrets** ```bash # Get the secret for a node (secretName comes from the configmap above) oc get secret -n ibm-spectrum-fusion-ns \ -o jsonpath='{.data.isfmgmtUserName}' | base64 -d && echo oc get secret -n ibm-spectrum-fusion-ns \ -o jsonpath='{.data.isfmgmtUserPasswrd}' | base64 -d && echo ``` **3. Find the rackIP (MGem IP)** The `rackIP` is not stored in the cluster — it lives in an external GitHub rack-config file. Ask your team/infrastructure owner for the MGem IP for each rack serial. It is the IP address you SSH into in Step 2. Alternatively, check any existing backup file: ```bash ls -lt ~/_rack_backup_*.json 2>/dev/null | head -3 cat ~/_rack_backup_.json | python3 -m json.tool \ | grep -A2 rackIP ``` **4. Write the JSON file** Create the directory and write the file manually: ```bash mkdir -p /rack_details cat > /rack_details/.json <<'EOF' { "": { "nodes": { "": { "ipv4": "", "ipv6": null, "manufacturer": "Lenovo", "role": "master", "username": "", "password": "" } }, "rackInfo": { "ibmSerialNumber": "", "ibmMTM": "9155-R42", "rackGen": 2, "storageType": "fdf", "isfModel": "9155", "ipStack": "v4", "rackIP": "" } } } EOF # Restrict permissions (file contains BMC passwords) chmod 600 /rack_details/.json ``` **5. Verify the file is valid JSON** ```bash python3 -m json.tool /rack_details/.json > /dev/null \ && echo "JSON OK" || echo "JSON INVALID" ``` **6. Verify BMC reachability from the MGem** SSH into the MGem and ping each BMC IP: ```bash ssh @ ping -c 1 -W 5 ``` Once the file exists and the pings succeed, proceed from Step 2. --- **Example config (multi-AZ cluster):** ```json { "": { "nodes": { "": { "ipv4": "", "ipv6": null, "manufacturer": "Lenovo", "role": "master", "username": "", "password": "" }, "": { "ipv4": "", "ipv6": null, "manufacturer": "Lenovo", "role": "worker", "username": "", "password": "" } }, "rackInfo": { "rackIP": "" } }, "": { "nodes": { "": { "ipv4": "", "ipv6": null, "manufacturer": "Lenovo", "role": "master", "username": "", "password": "" } }, "rackInfo": { "rackIP": "" } } } ``` Key fields used in every operation: | Field | Description | |---|---| | `rackIP` | IP of the MGem — the SSH hop host | | `ipv4` / `ipv6` | BMC IP of the node (reachable only from MGem) | | `username` / `password` | BMC credentials (IPMI or Redfish) | | `manufacturer` | `Lenovo` → use IPMI; `Dell` → use Redfish | --- ## Step 2 — SSH into the MGem ```bash ssh @ ``` All commands in Steps 3–6 are run **inside this SSH session**. --- ## Step 3 — Verify BMC Reachability (Ping) Before running any power command, confirm the node BMC is reachable from the MGem. **IPv4:** ```bash ping -c 1 -W 5 ``` **IPv6:** ```bash ping6 -c 1 -W 5 ``` A successful ping (`0% packet loss`) confirms the network path is healthy. If ping fails, try another rack's MGem (see [Multi-AZ fallback](#multi-az-mgem-fallback)). --- ## Step 4 — Lenovo Nodes (IPMI) All Lenovo operations use `ipmitool` via `lanplus`. ### Install ipmitool (if not present) ```bash which ipmitool || yum install -y ipmitool || dnf install -y ipmitool ``` ### Power status ```bash ipmitool -I lanplus -H -U -P '' power status # Expected output: "Chassis Power is on" or "Chassis Power is off" ``` **IPv6:** ```bash ipmitool -I lanplus -H "" -U -P '' power status ``` > Note: IPv6 addresses must be **quoted** for ipmitool. ### Power on ```bash ipmitool -I lanplus -H -U -P '' power on ``` ### Power off (graceful) ```bash ipmitool -I lanplus -H -U -P '' power soft ``` ### Power off (force) ```bash ipmitool -I lanplus -H -U -P '' power off ``` ### Power cycle ```bash ipmitool -I lanplus -H -U -P '' power cycle ``` ### Power reset ```bash ipmitool -I lanplus -H -U -P '' power reset ``` --- ## Step 5 — Dell Nodes (Redfish) All Dell operations use `curl` against the Redfish REST API. > IPv6 addresses must be wrapped in `[brackets]` in URLs. ### Discover the Systems URI ```bash curl -k -sS -f \ -u :'' \ https:///redfish/v1/Systems ``` From the JSON response, note the `@odata.id` of the first member, e.g. `/redfish/v1/Systems/System.Embedded.1`. Use this as `` below. ### Power status ```bash curl -k -sS -f \ -u :'' \ https:// | grep -i powerstate # Expected: "PowerState": "On" or "PowerState": "Off" ``` ### Power on ```bash curl -k -sS -f \ -u :'' -X POST \ https:///Actions/ComputerSystem.Reset \ -H 'Content-Type: application/json' \ -d '{"ResetType": "On"}' ``` ### Power off (graceful) ```bash curl -k -sS -f \ -u :'' -X POST \ https:///Actions/ComputerSystem.Reset \ -H 'Content-Type: application/json' \ -d '{"ResetType": "GracefulShutdown"}' ``` ### Power off (force) ```bash curl -k -sS -f \ -u :'' -X POST \ https:///Actions/ComputerSystem.Reset \ -H 'Content-Type: application/json' \ -d '{"ResetType": "ForceOff"}' ``` ### Power cycle ```bash curl -k -sS -f \ -u :'' -X POST \ https:///Actions/ComputerSystem.Reset \ -H 'Content-Type: application/json' \ -d '{"ResetType": "PowerCycle"}' ``` ### Power reset (graceful) ```bash curl -k -sS -f \ -u :'' -X POST \ https:///Actions/ComputerSystem.Reset \ -H 'Content-Type: application/json' \ -d '{"ResetType": "GracefulRestart"}' ``` ### Power reset (force) ```bash curl -k -sS -f \ -u :'' -X POST \ https:///Actions/ComputerSystem.Reset \ -H 'Content-Type: application/json' \ -d '{"ResetType": "ForceRestart"}' ``` --- ## Step 6 — Power on All Nodes (Recovery) When the cluster API is unreachable and all nodes are off, power them all on from the MGem without any ocs-ci involvement. Repeat the following for each rack in your cluster, substituting the rack's MGem IP and each node's BMC IP from the rack-details JSON: ```bash ssh @ # Power on each node in this rack (one BMC IP per node) for BMC_IP in ; do echo "Powering on $BMC_IP" ipmitool -I lanplus -H $BMC_IP -U -P '' power on done ``` Wait ~5 minutes then verify each node booted: ```bash ipmitool -I lanplus -H -U -P '' power status ``` --- ## Multi-AZ MGem Fallback In a multi-AZ cluster each rack has its own MGem (`rackIP`). If a node's BMC is not reachable from its own rack's MGem, try another rack's MGem. Look up the `rackIP` values for all racks from the rack-details JSON, then: ```bash # BMC not reachable from its own rack's MGem? # SSH into another rack's MGem and try from there: ssh @ ping -c 1 -W 5 ipmitool -I lanplus -H -U -P '' power status ``` --- ## Quick Reference | Operation | Lenovo (IPMI) | Dell (Redfish ResetType) | |---|---|---| | Status | `power status` | GET `` → `PowerState` | | Power on | `power on` | `On` | | Power off graceful | `power soft` | `GracefulShutdown` | | Power off force | `power off` | `ForceOff` | | Power cycle | `power cycle` | `PowerCycle` | | Reset graceful | `power reset` | `GracefulRestart` | | Reset force | `power reset` (with force) | `ForceRestart` | --- ## Troubleshooting **`ipmitool: command not found`** ```bash yum install -y ipmitool # RHEL/CentOS dnf install -y ipmitool # Fedora/newer RHEL ``` **`Error in open session response message : insufficient resources for session`** Too many open IPMI sessions on the BMC. Close them: ```bash ipmitool -I lanplus -H -U -P '' session info all ipmitool -I lanplus -H -U -P '' session deactivate ``` **`curl: (22) The requested URL returned error: 401`** Wrong Redfish credentials. Verify `username`/`password` from the rack-details JSON. **Ping succeeds but IPMI/Redfish fails** - Check credentials in the rack-details JSON (`username`, `password` fields). - Verify ipmitool is installed on the MGem. - For Dell nodes, ensure the Systems URI is correct by re-running the discovery curl command. **Node BMC not pingable from own MGem** - Try another rack's MGem (see [Multi-AZ MGem Fallback](#multi-az-mgem-fallback)). - If no MGem can reach the BMC, there is a network-level issue that must be resolved before power operations are possible.