Skip to content

AIL-262: feat(edge): collect launchpad-ai + GPU + storage state for AI-appliance triage#37

Open
rishi-anand wants to merge 5 commits into
mainfrom
feat/launchpad-ai-and-gpu-collection
Open

AIL-262: feat(edge): collect launchpad-ai + GPU + storage state for AI-appliance triage#37
rishi-anand wants to merge 5 commits into
mainfrom
feat/launchpad-ai-and-gpu-collection

Conversation

@rishi-anand

@rishi-anand rishi-anand commented Jul 24, 2026

Copy link
Copy Markdown

Jira: AIL-262

Summary

Extends support-bundle-edge.sh to capture the host + cluster state needed to root-cause failures on Palette AI-inference appliances (launchpad-ai on MI325X / H200 / B200), and to close storage/LVM/NVMe gaps that affect any edge host. Every command added is read-only and fails gracefully if its dependency isn't installed or its target isn't present.

What's added

1. AI namespaces to SYSTEM_NAMESPACES

launchpad-ai, amd-gpu-operator, gpu-operator. Their pods, previous-instance logs, and CRs get pulled by the existing generic namespace + CRD walks. All launchpad.spectrocloud.com CRDs (models, launchpadconfigs, modelgroupquotas, modelgroupapikeys, quotasettings) are covered automatically.

2. Previous boot's kernel log

journald-log() now also collects dmesg-previous-boot and journalctl-previous-boot when persistent journald is enabled. Critical for post-crash forensics — GPU wedges typically freeze host networking and force a reboot, so the current-boot dmesg after such a reboot is post-recovery and useless.

3. New storage-info() — always safe to run

Read-only host storage collection, every tool gated on command -v, timeout-wrapped where a wedged controller could hang:

  • lsblk -f, lsblk -o … (fs/UUID/model/serial/rotational)
  • df -h, df -i, /proc/mounts, /etc/fstab
  • fdisk -l
  • LVM: pvdisplay, vgdisplay, lvdisplay, pvs, vgs, lvs
  • NVMe: nvme list, nvme id-ctrl, nvme smart-log per drive (10-15s each)
  • SMART: smartctl -a per block device (20s each; no -t — never triggers tests)
  • Sysfs block attributes (size, hidden, rotational, dm/uuid, dm/name, device/{model,vendor,serial}) — mirrors what stylus/pkg/disk reads for enumeration
  • /dev/disk/by-* full symlink tree (covers by-uuid, by-partuuid, by-label, by-partlabel, by-path, by-id)
  • dmsetup ls --tree, dmsetup info — device-mapper topology for LVM / multipath / dm-crypt
  • /sys/class/nvme-subsystem/ — native-NVMe-multipath subsystem tree

4. New gpu-info() — hardware-vendor gated

Emits gpu/ directory. AMD block gated on [ -d /sys/module/amdgpu ]; NVIDIA block gated on [ -e /proc/driver/nvidia ] || command -v nvidia-smi. Emits an empty gpu/ dir on non-GPU hosts.

AMD (when amdgpu present):

  • Module version + modinfo + /sys/module/amdgpu/parameters/* (lockup_timeout, reset_method, gpu_recovery)
  • Per-card VBIOS via /sys/bus/pci/devices/*/vbios_version
  • Per-card firmware components (sdma_fw_version, sos_fw_version, smc_fw_version, ta_xgmi_fw_version, mec_fw_version, rlc_fw_version, …)
  • Per-card RAS + ECC counters via /sys/bus/pci/devices/*/ras/*
  • Per-card temp/power/voltage/fan via hwmon
  • rocm-smi -a and rocm-smi --show{hw,driverversion,vbios,temp,use,power,fw,bios} — from host if installed, else via kubectl exec into an operator/vLLM pod (timeout-guarded)
  • AMD GPU devcoredumps from /var/log/amdgpu-devcoredump/*.bin (populated by AIL-263 / launchpad-ai#512)
  • Live /sys/class/devcoredump/ listing (no reads of data — reads would consume)

NVIDIA (when nvidia driver present):

  • /proc/driver/nvidia/version
  • nvidia-smi -q, nvidia-smi topo -m, compact query CSV (pstate/temp/util/memory/ECC-corrected/ECC-uncorrected)
  • nvidia-bug-report.sh if installed (comprehensive vendor dump; 180s hard cap)
  • NVIDIA GPU devcoredumps from /var/log/nvidia-devcoredump/*.bin (populated by AIL-264 / launchpad-ai#530)

launchpad-ai on-disk (both vendors):

  • Directory shape of /opt/data/spectrocloud/models/ — weights are hundreds of GB, never copied into the bundle
  • Every model's metadata.yaml (~20 KB each; declares the launch recipe)

Read-only + graceful-fail guarantee

Read-only. Verified by grepping for --set, --reset, smartctl -t, nvme format, dmsetup remove/create/load, pvcreate/pvremove, vgcreate/vgremove, lvcreate/lvremove/lvresize, parted mkpart. Zero matches. Every GPU/storage tool uses only --show* / --query* / -l / list / display / info / id-ctrl / smart-log flags.

Graceful-fail.

  • Every optional binary gated on command -v — silent skip if not installed
  • Every vendor block gated on hardware presence (/sys/module/amdgpu, /proc/driver/nvidia) — no-op on non-GPU nodes
  • Every command that could hang wrapped in timeout N: nvme (10-15s), smartctl (20s), kubectl exec (10-30s), nvidia-bug-report.sh (180s hard cap)
  • Script does NOT use set -e (verified — existing pattern), so individual command failures don't abort the bundle
  • 13 timeout wrappers in the new code; 61 gated conditionals total

Motivation

Grounded in the July 2026 MI325X incident (see AIL-262) where two vLLM crashes each wedged the host. We had to log in mid-triage and hand-run every one of these commands. This PR turns the ad-hoc triage checklist into a first-class collector so support engineers don't repeat it.

Companion PRs that install the udev rules this collector reads:

Diff size

support-bundle/README-edge.md         |  49 ++
support-bundle/support-bundle-edge.sh | 258 ++++++++++++++
2 files changed, ~307 insertions

Test plan

  • Run on the MI325X host (137.220.60.220): confirm gpu/amd/ gets rocm-smi + per-card firmware/VBIOS + RAS state; storage/ gets pvdisplay + lsblk + nvme SMART.
  • Run on an H200 / B200 host: confirm gpu/nvidia/ gets nvidia-smi + optional nvidia-bug-report.
  • Run on a non-GPU edge host: confirm gpu/ is empty and everything else is unaffected. ← critical graceful-fail test
  • Run on a minimal Kairos host without nvme-cli or smartmontools: confirm storage/ still gets the sysfs + lsblk output and skips the missing tools without erroring. ← critical graceful-fail test
  • bash -n support-bundle-edge.sh — passes ✅
  • Introduce a synthetic hang in an exec target (e.g. unresponsive pod) and confirm the bundle completes within the timeout bounds.

🤖 Generated with Claude Code

Extend the edge support bundle to capture the state needed to
troubleshoot Palette AI-inference appliances (launchpad-ai on
MI325X / H200 / B200), where the standard k8s/system collection
alone is insufficient for root-cause on GPU-side failures.

Three changes:

1. SYSTEM_NAMESPACES: add launchpad-ai, amd-gpu-operator, gpu-operator
   so their pods, previous-instance logs, and CRs (models,
   launchpadconfigs, modelgroupquotas, modelgroupapikeys,
   quotasettings) are pulled by the existing generic namespace +
   CRD walks. No changes to API_RESOURCES needed — the launchpad.
   spectrocloud.com CRDs are already picked up automatically.

2. journald-log: also grab the PREVIOUS boot's kernel log
   (dmesg-previous-boot, journalctl-previous-boot) when journald
   has persistent storage. Post-crash forensics on GPU wedges that
   force a host reboot depend on this — the current-boot dmesg is
   post-recovery and useless.

3. gpu-info: new function that emits gpu/ with vendor-specific state
   * AMD (amdgpu present): module version + parameters, per-card
     VBIOS, per-card firmware components (sdma_fw, sos_fw, smc,
     xgmi_ta, mec, rlc, etc.), RAS/ECC counters, hwmon
     (temp/power/fan), rocm-smi -a and detailed views (from host or
     via kubectl exec into an operator/vLLM pod), and any AMD GPU
     devcoredumps preserved to /var/log/amdgpu-devcoredump/ by the
     OS profile udev rule.
   * NVIDIA (nvidia driver present): driver version, nvidia-smi -q +
     topo -m + summary CSV, nvidia-bug-report.sh if installed, and
     any NVIDIA devcoredumps from /var/log/nvidia-devcoredump/.
   * launchpad-ai: directory shape of /opt/data/spectrocloud/models/
     (never copies weights — hundreds of GB), plus every model's
     metadata.yaml (~20 KB each; declares the launch recipe).

Companion to the OS-profile PRs (launchpad-ai#512 for AMD, #530 for
NVIDIA) that install the udev rules producing the devcoredump files
this collector reads.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@rishi-anand
rishi-anand requested a review from a team as a code owner July 24, 2026 21:57
Add a storage-info() step that captures block devices, filesystems, LVM,
NVMe inventory + SMART health. Every tool is gated on its own binary
presence, so this is a no-op on hosts that don't have LVM / nvme-cli /
smartmontools installed.

Palette edge hosts run on LVM (spectro-data-vg / spectro-data-lv with
persistent partition at /opt). AI appliances additionally park model
weights under /opt/data/spectrocloud/models/. LVM or NVMe health issues
are a common load-bearing failure mode that the previous bundle
collected zero data for.

Collected commands (all optional-per-tool):
- lsblk -f, lsblk with FSTYPE/UUID/MODEL/SERIAL/TRAN/ROTA/STATE
- df -h, df -i, /proc/mounts, /etc/fstab
- fdisk -l
- pvdisplay, vgdisplay, lvdisplay, pvs, vgs, lvs
- nvme list, nvme id-ctrl, nvme smart-log per drive
- smartctl -a per block device

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@rishi-anand rishi-anand changed the title feat(edge): collect launchpad-ai + GPU state for AI-appliance triage AIL-262: feat(edge): collect launchpad-ai + GPU + storage state for AI-appliance triage Jul 24, 2026
rishi-anand and others added 3 commits July 24, 2026 15:02
…ystem

Mirrors the read-only sysfs paths that stylus/pkg/disk uses for disk
enumeration (dm UUIDs for LVM/dm-crypt/multipath detection, rotational
flag for SSD vs HDD, hidden/removable/ro flags). Also captures the
/dev/disk/by-* symlink tree (covers by-uuid, by-partuuid, by-label,
by-partlabel, by-path, by-id) and device-mapper topology via dmsetup.

Every command added here is READ-ONLY:
- cat of sysfs attributes (size, rotational, dm/uuid, dm/name, etc.)
- ls -laR /dev/disk (symlink listing only)
- dmsetup ls --tree, dmsetup info (query-only subcommands)
- ls -laR /sys/class/nvme-subsystem

No state-modifying subcommands anywhere in this file (verified: no
smartctl -t, no rocm-smi --set*, no nvme format, no dmsetup remove,
no fdisk without -l).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Every added command is now either (a) gated on tool presence via
'command -v <tool>' / '[ -d /sys/... ]' / '[ -b /dev/... ]', or (b)
wrapped in 'timeout N' so a wedged controller / unresponsive pod
can't block the entire bundle run.

Specific hardening:
- nvme list / id-ctrl / smart-log: 10-15s timeouts per drive
- smartctl -a: 20s timeout per drive (failing drives can spin)
- kubectl exec (rocm-smi / nvidia-smi fallback path): 30s timeout
  per exec, 10s on pod listing / 'which' probe
- nvidia-smi (direct): 10-20s per query
- nvidia-bug-report.sh: hard 180s cap (60s typical; hangs on
  wedged nodes)
- Merged the two AMD kubectl fallback loops (amd-gpu-operator +
  launchpad-ai) into one with 'break 2' for clarity

Read-only guarantee: no state-modifying subcommands present in
this file. Verified via grep for --set/--reset/-t (smartctl test)/
format/create/remove/mkpart. All GPU/storage tools are called
with query/show/list/display/id-ctrl/smart-log flags only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
On Palette NVIDIA appliances the driver + userspace tools live inside
the GPU Operator's driver DaemonSet container, not on the host (Kairos
is minimal by design). So 'command -v nvidia-bug-report.sh' on the
host misses the majority case. Mirror the rocm-smi fallback pattern:

  1. Try host binary first (works for BYO-driver / driver-in-image
     deployments)
  2. If not found or failed, exec inside any Running pod in
     gpu-operator or launchpad-ai that has the tool
  3. Stream the .gz output back over stdout (no kubectl cp, no in-pod
     cleanup needed)
  4. Sanity-check the received file is non-empty before declaring
     capture success
  5. If nothing worked, write a status file explaining why

Read-only from the system's perspective; the tool only writes to its
declared output path. 180s hard cap kept — nvidia-bug-report.sh can
hang on wedged GPUs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant