export: align reanimator and enrich redfish metrics

This commit is contained in:
Mikhail Chusavitin
2026-03-15 21:38:28 +03:00
parent 0acdc2b202
commit 9007f1b360
17 changed files with 3756 additions and 650 deletions

View File

@@ -0,0 +1,330 @@
# Hardware Ingest Contract
Version: 2.4
Updated: 2026-03-15
Source: Reanimator Core `hardware-ingest-contract.md`
This file mirrors the external Reanimator hardware-ingest contract that LOGPile targets.
The Reanimator endpoint uses strict JSON decoding. Any field not listed here must not be emitted.
## Endpoint
```http
POST /ingest/hardware
Content-Type: application/json
```
The ingest request is asynchronous.
Accepted response:
```json
{
"status": "accepted",
"job_id": "job_01J..."
}
```
Final result is available from:
```http
GET /ingest/hardware/jobs/{job_id}
```
## Top-level payload
```json
{
"filename": "redfish://10.10.10.103",
"source_type": "api",
"protocol": "redfish",
"target_host": "10.10.10.103",
"collected_at": "2026-02-10T15:30:00Z",
"hardware": {
"board": {},
"firmware": [],
"cpus": [],
"memory": [],
"storage": [],
"pcie_devices": [],
"power_supplies": [],
"sensors": {}
}
}
```
## Top-level rules
- `collected_at` is required and must be RFC3339
- `hardware.board.serial_number` is required
- `source_type` allowed values: `api`, `logfile`, `manual`
- `protocol` allowed values: `redfish`, `ipmi`, `snmp`, `ssh`
- Unknown JSON keys are rejected by Reanimator
## Shared component status fields
Allowed on `cpus`, `memory`, `storage`, `pcie_devices`, `power_supplies`:
- `status`
- `status_checked_at`
- `status_changed_at`
- `status_history`
- `error_description`
`status_history[]` items:
- `status`
- `changed_at`
- `details`
Do not emit `status_at_collection`; it is not part of the current strict ingest schema.
## `hardware.board`
Allowed fields:
- `serial_number` required
- `manufacturer`
- `product_name`
- `part_number`
- `uuid`
String values equal to `"NULL"` should be omitted.
## `hardware.firmware`
Allowed fields:
- `device_name`
- `version`
Only system-level firmware belongs here.
Device-bound firmware must stay on the relevant device record and must not be duplicated at the top level.
## `hardware.cpus`
Allowed fields:
- `socket`
- `model`
- `manufacturer`
- `cores`
- `threads`
- `frequency_mhz`
- `max_frequency_mhz`
- `temperature_c`
- `power_w`
- `throttled`
- `correctable_error_count`
- `uncorrectable_error_count`
- `life_remaining_pct`
- `life_used_pct`
- `serial_number`
- `firmware`
- `present`
- shared status fields
Exporter rule:
- if CPU serial is missing, generate `{board_serial}-CPU-{socket}`
## `hardware.memory`
Allowed fields:
- `slot`
- `location`
- `present`
- `serial_number`
- `part_number`
- `manufacturer`
- `size_mb`
- `type`
- `max_speed_mhz`
- `current_speed_mhz`
- `temperature_c`
- `correctable_ecc_error_count`
- `uncorrectable_ecc_error_count`
- `life_remaining_pct`
- `life_used_pct`
- `spare_blocks_remaining_pct`
- `performance_degraded`
- `data_loss_detected`
- shared status fields
Exporter rules:
- skip memory items with missing `serial_number`
- skip memory items with `present=false`
- skip memory items with `status=Empty`
## `hardware.storage`
Allowed fields:
- `slot`
- `serial_number`
- `model`
- `manufacturer`
- `type`
- `interface`
- `size_gb`
- `temperature_c`
- `power_on_hours`
- `power_cycles`
- `unsafe_shutdowns`
- `media_errors`
- `error_log_entries`
- `written_bytes`
- `read_bytes`
- `life_used_pct`
- `firmware`
- `present`
- `remaining_endurance_pct`
- `life_remaining_pct`
- `available_spare_pct`
- `reallocated_sectors`
- `current_pending_sectors`
- `offline_uncorrectable`
- shared status fields
Exporter rule:
- skip storage items with missing `serial_number`
## `hardware.pcie_devices`
Allowed fields:
- `slot`
- `vendor_id`
- `device_id`
- `numa_node`
- `temperature_c`
- `power_w`
- `life_remaining_pct`
- `life_used_pct`
- `ecc_corrected_total`
- `ecc_uncorrected_total`
- `hw_slowdown`
- `battery_charge_pct`
- `battery_health_pct`
- `battery_temperature_c`
- `battery_voltage_v`
- `battery_replace_required`
- `sfp_temperature_c`
- `sfp_tx_power_dbm`
- `sfp_rx_power_dbm`
- `sfp_voltage_v`
- `sfp_bias_ma`
- `bdf`
- `device_class`
- `manufacturer`
- `model`
- `serial_number`
- `firmware`
- `link_width`
- `link_speed`
- `max_link_width`
- `max_link_speed`
- `mac_addresses`
- `present`
- shared status fields
Known `device_class` values:
- `MassStorageController`
- `StorageController`
- `NetworkController`
- `EthernetController`
- `FibreChannelController`
- `VideoController`
- `ProcessingAccelerator`
- `DisplayController`
Exporter rules:
- if PCIe serial is missing or placeholder-like, generate `{board_serial}-PCIE-{slot}`
- `numa_node` is allowed again in the upstream contract
- network adapters should emit `mac_addresses` when available
- do not emit fields outside the upstream contract
## `hardware.power_supplies`
Allowed fields:
- `slot`
- `present`
- `serial_number`
- `part_number`
- `model`
- `vendor`
- `wattage_w`
- `firmware`
- `input_type`
- `input_voltage`
- `input_power_w`
- `output_power_w`
- `temperature_c`
- `life_remaining_pct`
- `life_used_pct`
- shared status fields
Exporter rule:
- skip PSUs with missing `serial_number`
## `hardware.sensors`
Shape:
```json
{
"fans": [],
"power": [],
"temperatures": [],
"other": []
}
```
### `sensors.fans`
Allowed fields:
- `name` required
- `location`
- `rpm`
- `status`
### `sensors.power`
Allowed fields:
- `name` required
- `location`
- `voltage_v`
- `current_a`
- `power_w`
- `status`
### `sensors.temperatures`
Allowed fields:
- `name` required
- `location`
- `celsius`
- `threshold_warning_celsius`
- `threshold_critical_celsius`
- `status`
### `sensors.other`
Allowed fields:
- `name` required
- `location`
- `value`
- `unit`
- `status`
Sensor rules:
- dedupe within one payload by `(section, name)`, keeping the first item
- skip sensors without `name`
- the current LOGPile exporter maps generic `SensorReading` values into these four groups heuristically