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
+24
View File
@@ -135,6 +135,30 @@ func TestParseGPUPairAdjacencyDoesNotChainUnrelatedGPUs(t *testing.T) {
}
}
func TestParseGPUPairAdjacencyANSIUnderlinedHeader(t *testing.T) {
// Real techdump capture: nvidia-smi underlines the header row with ANSI
// escapes even when writing to a file, so the header line starts with
// ESC[4m, not "GPU0".
input := "\x1b[4m\tGPU0\tGPU1\tGPU2\tGPU3\tNIC0\tNIC1\tCPU Affinity\x1b[0m\n" +
"GPU0\t X \tNV18\tPIX\tPIX\tNODE\tNODE\t0-31,64-95\t0\n" +
"GPU1\tNV18\t X \tPIX\tPIX\tNODE\tNODE\t0-31,64-95\t0\n" +
"GPU2\tPIX\tPIX\t X \tNV18\tNODE\tNODE\t0-31,64-95\t0\n" +
"GPU3\tPIX\tPIX\tNV18\t X \tNODE\tNODE\t0-31,64-95\t0\n" +
"NIC0\tNODE\tNODE\tNODE\tNODE\t X \tPIX\n" +
"NIC1\tNODE\tNODE\tNODE\tNODE\tPIX\t X \n"
pairs := parseGPUPairAdjacency(input)
if len(pairs) != 2 {
t.Fatalf("pairs=%d want 2 (%#v)", len(pairs), pairs)
}
want := map[[2]int]bool{{0, 1}: true, {2, 3}: true}
for _, p := range pairs {
if !want[[2]int{p.GPUA, p.GPUB}] || p.NVLinks != 18 {
t.Fatalf("unexpected pair %#v", p)
}
}
}
func TestParseGPUPairAdjacencyEmptyOnNoMatrix(t *testing.T) {
if pairs := parseGPUPairAdjacency("no gpus here"); pairs != nil {
t.Fatalf("pairs=%v want nil", pairs)