fix(parser): support Inspur HGX dump_<serial>_<timestamp>/ onekeylog layout

Fixes #20. This onekeylog variant has no devicefrusdr.log at all: FRU/sensors
come from raw ipmitool text output, PCIe/GPU presence has a dedicated
structural snapshot, SEL lives at a different path, and BMC component
failures are logged separately from SEL/IDL.

- Fall back to component/fru.txt (same FRU block format as devicefrusdr.log)
  and component/sensor.txt / sdr.txt (ipmitool sensor list / sdr elist)
  when devicefrusdr.log is absent.
- Parse log/bmc/diagnose/OtrdDiagnoseComponent.json's PCIe Device Info array
  for GPU/PCIe presence and link state, independent of SEL/IDL alarm
  history; flag devices running below their negotiated max link
  speed/width as degraded with a Warning event.
- Fall back to log/sel.csv (same format as selelist.csv) when selelist.csv
  is absent.
- Parse log/bmc/commer-comp/{commerslot,commerhmc,commerswvr,commerswcpld}
  logs (including rotated *.tar.gz.N parts) into failure events, filtering
  known-noisy lines.
- Collapse SEL events duplicated across sources by
  (timestamp, event_type, description).
- Surface a CollectionError when FRU/sensors are still empty after all
  fallbacks, instead of silently returning an empty inventory.
- Fix ParseFRU: a later placeholder "Product Serial : 0" / "Product Part
  Number : NULL" line in the same FRU block (e.g. SCM_FRU) was overwriting
  an already-parsed real Board Serial/Part Number.

Verified against dump_23DB01633_20260727-1359.tar.gz (HGX B200, KR9288-X3):
fru 0→21, sensors 0→303, 8 GPUs present at Gen5 x16 in slots 100-107.

Deferred (not covered by this change): BIOS-change-settings context and
BIOS POST codes from the same layout — see bible-local/10-decisions.md
ADL-048.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 10:05:58 +03:00
co-authored by Claude Sonnet 5
parent 6e1a8232ec
commit 74e6bf0578
12 changed files with 708 additions and 4 deletions
+55
View File
@@ -1229,3 +1229,58 @@ later content-free duplicate cannot blank out an earlier real reading.
Revisit only if a real archive needs that specific data and asset.json does not cover it.
- Any future component/*.txt GETALL consumer should reuse `parseDBusGetAllObjects` rather than
re-implementing block splitting or field extraction.
---
## ADL-048 — Inspur HGX `dump_<serial>_<timestamp>/` layout: ipmitool-output FRU/sensors, diagnose-json PCIe, commer-comp events
**Date:** 2026-07-29
**Context:** A field dump from an HGX B200 / KR9288-X3 (`dump_23DB01633_20260727-1359.tar.gz`)
uses yet another onekeylog variant that has no `devicefrusdr.log` at all (unlike ADL-047's
per-file D-Bus layout, which is missing only `component.log`). FRU and sensors come from raw
`ipmitool fru print` / `ipmitool sensor list` / `ipmitool sdr elist` output under
`component/{fru,sensor,sdr}.txt`. Without a fallback the parser returned `fru: 0, sensors: 0` on
an otherwise well-detected archive (`Detect()` still scored via `onekeylog_dreport.log`), silently
dropping inventory a diagnostic case (intermittent GPU PCIe dropout) depended on.
**Decision:**
- `component/fru.txt` uses the exact same `FRU Device Description :` block format as the FRU
section of `devicefrusdr.log`, so it's parsed with the existing `ParseFRU` unchanged.
- `component/sensor.txt` (`ipmitool sensor list`, has value+unit+status per line) is the primary
sensor fallback; `component/sdr.txt` (`ipmitool sdr elist`, no value on disabled sensors) is used
only if `sensor.txt` is absent. New parsers in `component_fallback.go`
(`ParseSensorList`, `ParseSDRElist`).
- `log/bmc/diagnose/OtrdDiagnoseComponent.json`'s `"Pcie Device Info"` array is a structural,
point-in-time PCIe snapshot (independent of SEL/IDL alarm history) — parsed by
`ParseOtrdDiagnosePCIe` in `diagnose.go` into `models.PCIeDevice` (using the existing
`Present *bool` field) and merged via the existing `MergePCIeDevices`. A device present but
running below its negotiated max link speed/width gets `Status = "Link Degraded"` and a
matching Warning event (`BuildPCIeLinkDegradationEvents`), independent of GPU-fault SEL/IDL
parsing in `gpu_status.go`.
- `log/sel.csv` is textually identical to `selelist.csv` (`ipmitool sel elist -c -Z` output with
the same 6-column CSV body) and is now a fallback source when `selelist.csv` is absent, reusing
`ParseSELListWithLocation` unchanged.
- `log/bmc/commer-comp/<commerslot|commerhmc|commerswvr|commerswcpld>/` component logs (plus
rotated `*.tar.gz.N` parts, decoded in-memory) share one line format
(`[timestamp][file, line][level] message`); `ParseCommerCompEvents` in `commercomp.go` emits an
event per line that looks like a real failure, after dropping a fixed noise list (`Invalid Comp
Data`, `Error in update redis`, `MutexTimeout = 0`).
- Fixed two long-standing `ParseFRU` bugs surfaced by this archive: `Board Serial`/`Board Part
Number` values were overwritten by a later, placeholder `Product Serial : 0` / `Product Part
Number : NULL` line within the same FRU block (e.g. `SCM_FRU`, which has no product-level FRU
fields). Placeholder values (`"0"`, `"NULL"`) no longer overwrite an already-set real value.
- Since duplicate SEL entries can now surface through more than one source file (`sel.csv` +
IDL/BMC logs) for the same moment, `Parse()` runs a final `dedupSELEvents` pass collapsing
`Source == "SEL"` events with identical `(timestamp, event_type, description)`. This is
deliberately narrower than IDL's own timestamp-inclusive dedup in `idl.go`, which must keep
distinct occurrences of a recurring alarm.
- When `Parse()` still ends up with `len(FRU) == 0 || len(Sensors) == 0` after all fallbacks, it
appends a `CollectionError{Section: "inventory"}` so the gap is visible in the API response
instead of silently returning an empty inventory.
**Consequences:**
- `stats.fru`/`stats.sensors` are non-zero on this dump class; GPU presence/link state is
available from a source independent of SEL/IDL alarm parsing.
- BIOS-change-settings context (`biosChangedSettings/Bios_change_settings*.json`) and BIOS POST
codes (`log/server/progress_log/host0/*`) from the same issue are not yet parsed — deferred,
no acceptance case depended on them yet.
- Any future ipmitool-text-output fallback (FRU/sensor/sdr) should extend
`component_fallback.go` rather than adding another one-off parser.