fix(parser,exporter): reconcile BMC-dump and live-CD exports of the same server
The audit tool that ingests Reanimator exports treats any per-component field
change between imports as a component replacement. Importing an xFusion BMC dump
and an easy_bee BEE-SP bundle for one server produced large spurious diffs.
xfusion:
- parseMemInfo tolerates a stray 0x0A inside the binary SPD "bom number" column
(it was splitting a DIMM record in two and emitting a phantom "slot s" module)
- DIMM slot from the "dimm name" column ("DIMM071"), mainboard "location" dropped
- GPU slot = BDF (Reanimator contract)
- NIC emitted per PCI function from netcard_info.txt (BDF + per-port MAC, shared
card serial) instead of one card-level adapter with the wrong BDF, which had
been colliding with a GPU and vanishing in dedup
- NIC manufacturer left blank when it is the system OEM so the exporter resolves
the silicon vendor from pci.ids
- "(U6216)" chip designator stripped from firmware versions
easy_bee:
- PSU bay numbers rebased 0-indexed -> 1-indexed; bare single-letter PSU
"firmware" (a leaked FRU version) cleared
- board.part_number taken from the bundle's ipmitool-fru.txt chassis
"Product Part Number" to match the BMC value
exporter (cross-vendor):
- canonicalMemorySlot: drop dmidecode "(J)" channel tag, Memory111 -> DIMM111
- canonicalGPUModel: NVIDIA DC GPUs reduce to the bare chip token
- canonicalStorageMediaAndInterface: NVMe is a bus not a medium
- manufacturerFromStorageModel: fill blank drive vendor from the model prefix
- isRemovableUSBStorageDevice: drop live-CD boot sticks
- isOnboardControllerPCIeDevice: drop SATA/NVMe/MegaRAID/PCIe-switch controller
functions that only an lspci scan reports (keep add-in cards with an identity)
For the reference server every physical component now appears in both exports
keyed identically; residual diffs are one-sided enrichment only.
Refs ADL-061, ADL-062.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFy4m7cVv4cqp25jJh2gSB
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5b65c99b0e
commit
9b2c654182
@@ -2270,3 +2270,75 @@ func TestConvertToReanimator_ExportsLicenses(t *testing.T) {
|
||||
t.Errorf("Status = %q, want %q", scoped.Status, "Warning")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalMemorySlot(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"DIMM111(J)": "DIMM111",
|
||||
"DIMM111 (J)": "DIMM111",
|
||||
"Memory111": "DIMM111",
|
||||
"DIMM111": "DIMM111",
|
||||
"P1-DIMMA1": "P1-DIMMA1",
|
||||
"CPU0_C0D0": "CPU0_C0D0",
|
||||
}
|
||||
for in, want := range cases {
|
||||
if got := canonicalMemorySlot(in); got != want {
|
||||
t.Errorf("canonicalMemorySlot(%q) = %q, want %q", in, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalGPUModel(t *testing.T) {
|
||||
cases := []struct{ model, mfr, want string }{
|
||||
{"NVIDIA H200 NVL", "NVIDIA Corporation", "H200"},
|
||||
{"H200", "NVIDIA Corporation", "H200"},
|
||||
{"NVIDIA H200 141G", "", "H200"},
|
||||
{"GH100 [H200 NVL]", "NVIDIA Corporation", "H200"},
|
||||
{"Radeon Instinct MI300X", "AMD", "Radeon Instinct MI300X"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := canonicalGPUModel(c.model, c.mfr); got != c.want {
|
||||
t.Errorf("canonicalGPUModel(%q,%q) = %q, want %q", c.model, c.mfr, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalStorageMediaAndInterface(t *testing.T) {
|
||||
cases := []struct{ inT, inI, wantT, wantI string }{
|
||||
{"NVMe", "PCIe", "SSD", "NVMe"},
|
||||
{"NVMe", "", "SSD", "NVMe"},
|
||||
{"SSD", "PCIe", "SSD", "NVMe"},
|
||||
{"SSD", "SATA", "SSD", "SATA"},
|
||||
{"HDD", "SAS", "HDD", "SAS"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
gotT, gotI := canonicalStorageMediaAndInterface(c.inT, c.inI)
|
||||
if gotT != c.wantT || gotI != c.wantI {
|
||||
t.Errorf("canonicalStorageMediaAndInterface(%q,%q) = %q,%q want %q,%q", c.inT, c.inI, gotT, gotI, c.wantT, c.wantI)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsOnboardControllerPCIeDevice(t *testing.T) {
|
||||
drop := []models.HardwareDevice{
|
||||
{Kind: models.DeviceKindPCIe, DeviceClass: "SATA controller", Model: "Sapphire Rapids SATA AHCI Controller"},
|
||||
{Kind: models.DeviceKindPCIe, DeviceClass: "Non-Volatile memory controller", Model: "NVMe SSD Controller CD8P"},
|
||||
{Kind: models.DeviceKindPCIe, DeviceClass: "MassStorageController", Model: "MegaRAID 12GSAS/PCIe Secure SAS38xx"},
|
||||
{Kind: models.DeviceKindPCIe, DeviceClass: "StorageController", Model: "PCIe Switch management endpoint"},
|
||||
}
|
||||
for _, d := range drop {
|
||||
if !isOnboardControllerPCIeDevice(d) {
|
||||
t.Errorf("expected %q/%q to be dropped", d.DeviceClass, d.Model)
|
||||
}
|
||||
}
|
||||
keep := []models.HardwareDevice{
|
||||
{Kind: models.DeviceKindGPU, DeviceClass: "VideoController", Model: "H200"},
|
||||
{Kind: models.DeviceKindNetwork, DeviceClass: "EthernetController", Model: "ConnectX-6 Lx"},
|
||||
{Kind: models.DeviceKindPCIe, DeviceClass: "raid_controller", Model: "RAID Controller", PartNumber: "XC170-M-8i"},
|
||||
{Kind: models.DeviceKindPCIe, DeviceClass: "MassStorageController", Model: "HBA", SerialNumber: "ABC123"},
|
||||
}
|
||||
for _, d := range keep {
|
||||
if isOnboardControllerPCIeDevice(d) {
|
||||
t.Errorf("expected %q/%q to be kept", d.DeviceClass, d.Model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user