feat(hardware): collect and export licenses via Dell iDRAC10 Redfish walk

Implements the hardware.licenses[] contract section (v2.12, refreshed from
reanimator/core's hardware-ingest-contract.md — was v2.11 locally).

- models.License / HardwareConfig.Licenses mirror the contract field set.
- collector.collectLicenses() reads the standard DMTF
  /redfish/v1/LicenseService/Licenses collection during Redfish-walk replay;
  it's a generic DMTF resource, not Dell-specific, so any future vendor's
  Redfish walk gets license collection for free through
  ReplayRedfishFromRawPayloads.
- vendors/dell merges replayed Licenses like every other category.
- exporter.convertLicenses/dedupeLicenses wire hw.Licenses into the
  reanimator export directly (no canonical-devices merge — licenses have no
  physical identity to merge on), setting Present on every record from the
  start (per the ADL-049 round-trip lesson).
- chart viewer renders a licenses section in /chart/current.

Verified end-to-end on the PowerEdge R7715 (1TVFYL4) TSR: 3 system-level
licenses extracted and correctly exported/rendered.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-08-11 11:48:21 +03:00
co-authored by Claude Sonnet 5
parent eb6cc207ce
commit eaaf5c09d3
13 changed files with 582 additions and 10 deletions
+43
View File
@@ -1310,3 +1310,46 @@ given the field it needs from a re-imported export.
`parseUploadedSnapshot` must actually be populated by its `convert*FromDevices` function — the struct
declaring the field is not enough. `Storage` was the only category doing this correctly before this fix;
worth auditing PCIe/NIC/GPU conversion the same way if a similar round-trip gap is reported for them.
---
## ADL-050 — Added `hardware.licenses[]` collection/export (contract v2.12), Dell iDRAC10 first
**Date:** 2026-08-11
**Context:** Reanimator's hardware ingest contract added an optional `hardware.licenses[]` section in
v2.12 (2026-08-11) for software/firmware licenses and feature-on-demand activations (BMC advanced
licenses, vGPU, CPU FoD, RAID feature unlocks, etc). LOGPile's local copy of
`bible-local/docs/hardware-ingest-contract.md` was still v2.11 and was refreshed from
`reanimator/core/bible-local/docs/hardware-ingest-contract.md`. Scoped the first implementation to the
Dell iDRAC10 Redfish-walk path (`vendors/dell` + `vendors/redfishwalk`, see ADL-048/049), since that's
the only resolver currently producing a full captured Redfish tree with a `LicenseService` collection
in it — other vendor parsers have no comparable source for this data yet.
**Decision:**
- `models.License` (`internal/models/models.go`) added, mirroring the contract's field set 1:1
(`name`, `license_key`, `vendor`, `type`, `feature`, `component_ref`, `activated_at`, `expires_at`,
`present`, status fields). `HardwareConfig.Licenses []License` added.
- `internal/collector/redfish_replay_licenses.go`: `collectLicenses()` reads the standard DMTF
`/redfish/v1/LicenseService/Licenses` collection (`License.v1_x` schema) via the existing
`redfishSnapshotReader.getCollectionMembers` helper — no Dell-specific parsing needed, this is a
generic DMTF resource, so any future vendor whose Redfish walk includes it gets license collection
for free through `ReplayRedfishFromRawPayloads`. `AuthorizationScope: "Device"` licenses get
`component_ref` from `Links.AuthorizedDevices[0]`; `Service`-scoped licenses stay system-level (no
`component_ref`). `LicenseOrigin != "Installed"` maps to `Present: false`.
- `internal/parser/vendors/dell/redfish_walk.go`'s `mergeRedfishReplay` appends replayed `Licenses`
into `result.Hardware.Licenses` like every other category.
- `internal/exporter/reanimator_converter.go`: `convertLicenses` + `dedupeLicenses` (dedup key:
`license_key`, falling back to `component_ref|name`) added, wired into `ConvertToReanimator`
directly from `hw.Licenses` — licenses don't go through the canonical-devices merge/dedup pipeline
used for PCIe/GPU/NIC, since they carry no physical identity to merge on. `ReanimatorLicense.Present`
is set on every emitted record (learned from ADL-049 — declaring the field isn't enough, it must
actually be populated for the reanimator round-trip to survive).
- `internal/chart/viewer/render.go`: added a `licenses` section (between `power_supplies` and
`sensors`) so licenses show up in the `/chart/current` web view like every other hardware category.
**Consequences:**
- Verified end-to-end on the PowerEdge R7715 (1TVFYL4) TSR archive: 3 licenses extracted from
`redfishidracwalk.tar.gz` ("Secure Enterprise Key Manager", "Secured Component Verification",
"iDRAC10 17G Enterprise License"), all system-level (`AuthorizationScope: "Service"`), correctly
exported with `present: true` and visible in the live `/chart/current` page.
- No other vendor parser populates `Hardware.Licenses` yet. If a future TSR/log source carries license
data outside a Redfish walk (e.g. embedded in a vendor-specific XML/JSON file), it needs its own
parsing — `collectLicenses()` only covers the generic Redfish `LicenseService` path.