fix(xfusion): emit OCP NIC ports with no serial so reanimator keys them by MAC

Verified against reanimator/core: it keys a NIC component on serial → MAC →
synthetic(slot). A BMC dump carrying the card serial collapses both ports into
one serial-keyed component, while a live-CD bundle (no serial) keeps two
MAC-keyed components, so alternating the two sources produced a spurious
COMPONENT_REMOVED + 2x COMPONENT_INSTALLED every time. Emitting the per-port
NetworkAdapter entries with an empty serial makes both sources key on the port
MAC and yield the same two components. The card serial still reaches the export
via the FRU record and the legacy NIC entry.

Also records ADL-062 findings from reading the ingesting audit tool: it persists
only vendor/model/serial per component (no size/speed/link/clock/wattage), so the
remaining one-sided field diffs between the two bundles cannot generate change
events.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFy4m7cVv4cqp25jJh2gSB
This commit is contained in:
Mikhail Chusavitin
2026-08-31 22:55:45 +03:00
co-authored by Claude Sonnet 5
parent 9b2c654182
commit 8e7f22077d
3 changed files with 67 additions and 13 deletions
+39 -7
View File
@@ -1726,12 +1726,44 @@ the work between the two vendor parsers and the shared exporter:
taken from the bundle's `ipmitool-fru.txt` chassis "Product Part Number" to match
the BMC value.
**Consequences:** For the reference server every physical component now appears in
both exports keyed identically (serial, or BDF for PCIe). Residual diffs are
one-sided *enrichment* only — PCIe link speed/width, NVMe block sizes, drive
`size_gb`, CPU clocks, PSU firmware/wattage, `board.uuid`, and the extra firmware
components (CPLD/U-Boot/SDK/…) — where one collector's source simply has data the
other's does not; none is a value that *conflicts*. Whether the audit treats a
null→value transition on an unchanged component as a change is a config question
on the audit side. Tests: `TestCanonicalMemorySlot`, `TestCanonicalGPUModel`,
both exports keyed identically (serial, or BDF for PCIe). Tests:
`TestCanonicalMemorySlot`, `TestCanonicalGPUModel`,
`TestCanonicalStorageMediaAndInterface`, `TestIsOnboardControllerPCIeDevice`,
`TestNormalizePSUSlots`, updated `TestParse_ServerFileExport_NetworkAdaptersAndFirmware`.
**Verified against `reanimator/core` (the ingesting audit tool), 2026-08-31.**
Reanimator persists only a narrow slice of what the export carries, so most
residual field diffs cannot generate a change event:
- Component identity = `vendor_serial` only (`parts` table). Fallback chain per
`flattenPCIe`: real serial → MAC → `{board}-PCIE-{slot}`. Memory/storage/PSU:
serial → synthetic-by-slot. `parts` stores only vendor, model, serial — **no
size, speed, link width, block size, clocks, wattage, location, numa/iommu**, so
a null→value transition on any of those is a no-op.
- `vendor`/`model` are re-canonicalized on ingest via the alias resolver **using
`vendor_id`/`device_id`** ("prefer the authoritative pci.ids name"). Both bundles
carry the same PCI IDs, so GPU model and NIC vendor already converge server-side
regardless of the raw strings — the logpile-side `canonicalGPUModel` / OEM-vendor
blanking are belt-and-suspenders for non-reanimator consumers.
- `slot_name` is written once at install and only re-patched when the install
itself changes (`res.Changed`); a component that stays continuously present
never gets a slot-change event, so differing slot labels are harmless once
presence is stable.
- Asset firmware = `machine_firmware_states` keyed by `(machine_id, device_name)`;
an event fires only on a version change for the *same* name. A name absent from
an import is left untouched (no downgrade), so the 6 BMC-only firmware entries
are inert. `iBMC` (BMC dump) vs `BMC` (live CD) stay two independent, non-churning
rows — deliberately **not** normalized, because unifying the name would then
churn on the version (`3.08.05.85` vs `3.08`).
- Reanimator has its own `IsDeviceIgnored(vendor, model)` alias-driven ignore list
for "onboard controllers, service USB flash drives" — the logpile-side
`isRemovableUSBStorageDevice`/`isOnboardControllerPCIeDevice` filters overlap it
but remove the dependency on the alias dict being configured.
The one real cross-collector reinstall risk was the **OCP NIC**: with the card
serial on it, reanimator collapses both ports to one serial-keyed component, while
a live-CD bundle (no serial) stays two MAC-keyed components → remove + 2×install
on every source switch. Fixed by emitting the xFusion NIC as per-port entries
**with no serial**, so both sources key on the port MAC and produce the same two
components. Net: after this work the only fields that still differ between the two
bundles are ones reanimator does not track, so alternating collection methods for
one server produces no spurious install/remove/firmware events.