webui/collector: strip ANSI escapes in nvidia-smi topo parsing, auto-prepare drives for RAID mirror creation

- nvidia-smi underlines the topo -m header with ANSI CSI codes even when
  writing to a file; both NVLink matrix parsers failed to find the header
  and /topo showed "No NVLink-bonded GPU pairs found" on bonded systems.
- raid-lsi-create-mirror failed with "resources already in use" (exit 11)
  on JBOD drives; the task now reads drive states and auto-converts
  JBOD/UBad (set good force), releases hotspares, refuses Frgn/Onln with
  actionable messages, and dumps preservedcache info when add vd fails.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-08 23:16:04 +03:00
co-authored by Claude Fable 5
parent 1175e6ccd8
commit 10557ec0f6
6 changed files with 184 additions and 3 deletions
@@ -12,6 +12,11 @@ import (
var nv5re = regexp.MustCompile(`(?i)^NV(\d+)$`)
// nvidia-smi underlines the topo -m header row with ANSI CSI sequences
// (ESC[4m...ESC[0m) even when stdout is not a TTY, so "GPU0" is not at the
// start of the trimmed header line unless they are stripped first.
var nvANSIRe = regexp.MustCompile("\x1b\\[[0-9;]*[A-Za-z]")
// isNVLinkBridgeCandidate returns true for Mellanox PCIe devices that look like
// NVLink bridge mezzanine cards: narrow link (x2), no host net interfaces.
// These are the CPU-side PCIe control plane of the NVSwitch fabric on HGX/DGX systems.
@@ -163,7 +168,7 @@ func locateGPUTopologyColumns(lines []string) (headerIdx int, gpuColIndices []in
// (NIC, CPU) which are ignored. Only GPU×GPU cells containing NV# values are
// counted. X is self; non-NV tokens (NODE, SYS, PHB, PIX) are skipped.
func parseNVIDIATopologyMatrix(raw string) nvlinkTopoResult {
lines := strings.Split(raw, "\n")
lines := strings.Split(nvANSIRe.ReplaceAllString(raw, ""), "\n")
headerIdx, gpuColIndices, gpuCount := locateGPUTopologyColumns(lines)
if headerIdx < 0 {
return nvlinkTopoResult{}