794 lines
36 KiB
Markdown
794 lines
36 KiB
Markdown
---
|
||
title: Hardware Ingest JSON Contract
|
||
version: "2.7"
|
||
updated: "2026-03-15"
|
||
maintainer: Reanimator Core
|
||
audience: external-integrators, ai-agents
|
||
language: ru
|
||
---
|
||
|
||
# Интеграция с Reanimator: контракт JSON-импорта аппаратного обеспечения
|
||
|
||
Версия: **2.7** · Дата: **2026-03-15**
|
||
|
||
Документ описывает формат JSON для передачи данных об аппаратном обеспечении серверов в систему **Reanimator** (управление жизненным циклом аппаратного обеспечения).
|
||
Предназначен для разработчиков смежных систем (Redfish-коллекторов, агентов мониторинга, CMDB-экспортёров) и может быть включён в документацию интегрируемых проектов.
|
||
|
||
> Актуальная версия документа: https://git.mchus.pro/reanimator/core/src/branch/main/bible-local/docs/hardware-ingest-contract.md
|
||
|
||
---
|
||
|
||
## Changelog
|
||
|
||
| Версия | Дата | Изменения |
|
||
|--------|------|-----------|
|
||
| 2.7 | 2026-03-15 | Явно запрещён синтез данных в `event_logs`; интеграторы не должны придумывать серийные номера компонентов, если источник их не отдал |
|
||
| 2.6 | 2026-03-15 | Добавлена необязательная секция `event_logs` для dedup/upsert логов `host` / `bmc` / `redfish` вне history timeline |
|
||
| 2.5 | 2026-03-15 | Добавлено общее необязательное поле `manufactured_year_week` для компонентных секций (`YYYY-Www`) |
|
||
| 2.4 | 2026-03-15 | Добавлена первая волна component telemetry: health/life поля для `cpus`, `memory`, `storage`, `pcie_devices`, `power_supplies` |
|
||
| 2.3 | 2026-03-15 | Добавлены component telemetry поля: `pcie_devices.temperature_c`, `pcie_devices.power_w`, `power_supplies.temperature_c` |
|
||
| 2.2 | 2026-03-15 | Добавлено поле `numa_node` у `pcie_devices` для topology/affinity |
|
||
| 2.1 | 2026-03-15 | Добавлена секция `sensors` (fans, power, temperatures, other); поле `mac_addresses` у `pcie_devices`; расширен список значений `device_class` |
|
||
| 2.0 | 2026-02-01 | История статусов (`status_history`, `status_changed_at`); поля telemetry у PSU; async job response |
|
||
| 1.0 | 2026-01-01 | Начальная версия контракта |
|
||
|
||
---
|
||
|
||
## Принципы
|
||
|
||
1. **Snapshot** — JSON описывает состояние сервера на момент сбора. Может включать историю изменений статуса компонентов.
|
||
2. **Идемпотентность** — повторная отправка идентичного payload не создаёт дублей (дедупликация по хешу).
|
||
3. **Частичность** — можно передавать только те секции, данные по которым доступны. Пустой массив и отсутствие секции эквивалентны.
|
||
4. **Строгая схема** — endpoint использует строгий JSON-декодер; неизвестные поля приводят к `400 Bad Request`.
|
||
5. **Event-driven** — импорт создаёт события в timeline (LOG_COLLECTED, INSTALLED, REMOVED, FIRMWARE_CHANGED и др.).
|
||
6. **Без синтеза со стороны интегратора** — сборщик передаёт только фактически собранные значения. Нельзя придумывать `serial_number`, `component_ref`, `message`, `message_id` или другие идентификаторы/атрибуты, если источник их не предоставил или парсер не смог их надёжно извлечь.
|
||
|
||
---
|
||
|
||
## Endpoint
|
||
|
||
```
|
||
POST /ingest/hardware
|
||
Content-Type: application/json
|
||
```
|
||
|
||
**Ответ при приёме (202 Accepted):**
|
||
```json
|
||
{
|
||
"status": "accepted",
|
||
"job_id": "job_01J..."
|
||
}
|
||
```
|
||
|
||
Импорт выполняется асинхронно. Результат доступен по:
|
||
```
|
||
GET /ingest/hardware/jobs/{job_id}
|
||
```
|
||
|
||
**Ответ при успехе задачи:**
|
||
```json
|
||
{
|
||
"status": "success",
|
||
"bundle_id": "lb_01J...",
|
||
"asset_id": "mach_01J...",
|
||
"collected_at": "2026-02-10T15:30:00Z",
|
||
"duplicate": false,
|
||
"summary": {
|
||
"parts_observed": 15,
|
||
"parts_created": 2,
|
||
"parts_updated": 13,
|
||
"installations_created": 2,
|
||
"installations_closed": 1,
|
||
"timeline_events_created": 9,
|
||
"failure_events_created": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
**Ответ при дубликате:**
|
||
```json
|
||
{
|
||
"status": "success",
|
||
"duplicate": true,
|
||
"message": "LogBundle with this content hash already exists"
|
||
}
|
||
```
|
||
|
||
**Ответ при ошибке (400 Bad Request):**
|
||
```json
|
||
{
|
||
"status": "error",
|
||
"error": "validation_failed",
|
||
"details": {
|
||
"field": "hardware.board.serial_number",
|
||
"message": "serial_number is required"
|
||
}
|
||
}
|
||
```
|
||
|
||
Частые причины `400`:
|
||
- Неверный формат `collected_at` (требуется RFC3339).
|
||
- Пустой `hardware.board.serial_number`.
|
||
- Наличие неизвестного JSON-поля на любом уровне.
|
||
- Тело запроса превышает допустимый размер.
|
||
|
||
---
|
||
|
||
## Структура верхнего уровня
|
||
|
||
```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": { ... },
|
||
"event_logs": [ ... ]
|
||
}
|
||
}
|
||
```
|
||
|
||
### Поля верхнего уровня
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `collected_at` | string RFC3339 | **да** | Время сбора данных |
|
||
| `hardware` | object | **да** | Аппаратный снапшот |
|
||
| `hardware.board.serial_number` | string | **да** | Серийный номер платы/сервера |
|
||
| `target_host` | string | нет | IP или hostname |
|
||
| `source_type` | string | нет | Тип источника: `api`, `logfile`, `manual` |
|
||
| `protocol` | string | нет | Протокол: `redfish`, `ipmi`, `snmp`, `ssh` |
|
||
| `filename` | string | нет | Идентификатор источника |
|
||
|
||
---
|
||
|
||
## Общие поля статуса компонентов
|
||
|
||
Применяются ко всем компонентным секциям (`cpus`, `memory`, `storage`, `pcie_devices`, `power_supplies`).
|
||
|
||
| Поле | Тип | Описание |
|
||
|------|-----|----------|
|
||
| `status` | string | Текущий статус: `OK`, `Warning`, `Critical`, `Unknown`, `Empty` |
|
||
| `status_checked_at` | string RFC3339 | Время последней проверки статуса |
|
||
| `status_changed_at` | string RFC3339 | Время последнего изменения статуса |
|
||
| `status_history` | array | История переходов статусов (см. ниже) |
|
||
| `error_description` | string | Текст ошибки/диагностики |
|
||
| `manufactured_year_week` | string | Дата производства в формате `YYYY-Www`, например `2024-W07` |
|
||
|
||
**Объект `status_history[]`:**
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `status` | string | **да** | Статус в этот момент |
|
||
| `changed_at` | string RFC3339 | **да** | Время перехода (без этого поля запись игнорируется) |
|
||
| `details` | string | нет | Пояснение к переходу |
|
||
|
||
**Правила приоритета времени события:**
|
||
|
||
1. `status_changed_at`
|
||
2. Последняя запись `status_history` с совпадающим статусом
|
||
3. Последняя парсируемая запись `status_history`
|
||
4. `status_checked_at`
|
||
|
||
**Правила передачи статусов:**
|
||
- Передавайте `status` как текущее состояние компонента в snapshot.
|
||
- Если источник хранит историю — передавайте `status_history` отсортированным по `changed_at` по возрастанию.
|
||
- Не включайте записи `status_history` без `changed_at`.
|
||
- Все даты — RFC3339, рекомендуется UTC (`Z`).
|
||
- `manufactured_year_week` используйте, когда источник знает только год и неделю производства, без точной календарной даты.
|
||
|
||
---
|
||
|
||
## Секции hardware
|
||
|
||
### board
|
||
|
||
Основная информация о сервере. Обязательная секция.
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `serial_number` | string | **да** | Серийный номер (ключ идентификации Asset) |
|
||
| `manufacturer` | string | нет | Производитель |
|
||
| `product_name` | string | нет | Модель |
|
||
| `part_number` | string | нет | Партномер |
|
||
| `uuid` | string | нет | UUID системы |
|
||
|
||
Значения `"NULL"` в строковых полях трактуются как отсутствие данных.
|
||
|
||
```json
|
||
"board": {
|
||
"manufacturer": "Supermicro",
|
||
"product_name": "X12DPG-QT6",
|
||
"serial_number": "21D634101",
|
||
"part_number": "X12DPG-QT6-REV1.01",
|
||
"uuid": "d7ef2fe5-2fd0-11f0-910a-346f11040868"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### firmware
|
||
|
||
Версии прошивок системных компонентов (BIOS, BMC, CPLD и др.).
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `device_name` | string | **да** | Название устройства (`BIOS`, `BMC`, `CPLD`, …) |
|
||
| `version` | string | **да** | Версия прошивки |
|
||
|
||
Записи с пустым `device_name` или `version` игнорируются.
|
||
Изменение версии создаёт событие `FIRMWARE_CHANGED` для Asset.
|
||
|
||
```json
|
||
"firmware": [
|
||
{ "device_name": "BIOS", "version": "06.08.05" },
|
||
{ "device_name": "BMC", "version": "5.17.00" },
|
||
{ "device_name": "CPLD", "version": "01.02.03" }
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### cpus
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `socket` | int | **да** | Номер сокета (используется для генерации serial) |
|
||
| `model` | string | нет | Модель процессора |
|
||
| `manufacturer` | string | нет | Производитель |
|
||
| `cores` | int | нет | Количество ядер |
|
||
| `threads` | int | нет | Количество потоков |
|
||
| `frequency_mhz` | int | нет | Текущая частота |
|
||
| `max_frequency_mhz` | int | нет | Максимальная частота |
|
||
| `temperature_c` | float | нет | Температура CPU, °C (telemetry) |
|
||
| `power_w` | float | нет | Текущая мощность CPU, Вт (telemetry) |
|
||
| `throttled` | bool | нет | Зафиксирован thermal/power throttling |
|
||
| `correctable_error_count` | int | нет | Количество корректируемых ошибок CPU |
|
||
| `uncorrectable_error_count` | int | нет | Количество некорректируемых ошибок CPU |
|
||
| `life_remaining_pct` | float | нет | Остаточный ресурс / health, % |
|
||
| `life_used_pct` | float | нет | Использованный ресурс / wear, % |
|
||
| `serial_number` | string | нет | Серийный номер (если доступен) |
|
||
| `firmware` | string | нет | Версия микрокода; если логгер отдает `Microcode level`, передавайте его сюда как есть |
|
||
| `present` | bool | нет | Наличие (по умолчанию `true`) |
|
||
| + общие поля статуса | | | см. раздел выше |
|
||
|
||
**Генерация serial_number при отсутствии:** `{board_serial}-CPU-{socket}`
|
||
|
||
Если источник использует поле/лейбл `Microcode level`, его значение передавайте в `cpus[].firmware` без дополнительного преобразования.
|
||
|
||
```json
|
||
"cpus": [
|
||
{
|
||
"socket": 0,
|
||
"model": "INTEL(R) XEON(R) GOLD 6530",
|
||
"cores": 32,
|
||
"threads": 64,
|
||
"frequency_mhz": 2100,
|
||
"max_frequency_mhz": 4000,
|
||
"temperature_c": 61.5,
|
||
"power_w": 182.0,
|
||
"throttled": false,
|
||
"manufacturer": "Intel",
|
||
"status": "OK",
|
||
"status_checked_at": "2026-02-10T15:28:00Z"
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### memory
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `slot` | string | нет | Идентификатор слота |
|
||
| `present` | bool | нет | Наличие модуля (по умолчанию `true`) |
|
||
| `serial_number` | string | нет | Серийный номер |
|
||
| `part_number` | string | нет | Партномер (используется как модель) |
|
||
| `manufacturer` | string | нет | Производитель |
|
||
| `size_mb` | int | нет | Объём в МБ |
|
||
| `type` | string | нет | Тип: `DDR3`, `DDR4`, `DDR5`, … |
|
||
| `max_speed_mhz` | int | нет | Максимальная частота |
|
||
| `current_speed_mhz` | int | нет | Текущая частота |
|
||
| `temperature_c` | float | нет | Температура DIMM/модуля, °C (telemetry) |
|
||
| `correctable_ecc_error_count` | int | нет | Количество корректируемых ECC-ошибок |
|
||
| `uncorrectable_ecc_error_count` | int | нет | Количество некорректируемых ECC-ошибок |
|
||
| `life_remaining_pct` | float | нет | Остаточный ресурс / health, % |
|
||
| `life_used_pct` | float | нет | Использованный ресурс / wear, % |
|
||
| `spare_blocks_remaining_pct` | float | нет | Остаток spare blocks, % |
|
||
| `performance_degraded` | bool | нет | Зафиксирована деградация производительности |
|
||
| `data_loss_detected` | bool | нет | Источник сигнализирует риск/факт потери данных |
|
||
| + общие поля статуса | | | см. раздел выше |
|
||
|
||
Модуль без `serial_number` игнорируется. Модуль с `present=false` или `status=Empty` игнорируется.
|
||
|
||
```json
|
||
"memory": [
|
||
{
|
||
"slot": "CPU0_C0D0",
|
||
"present": true,
|
||
"size_mb": 32768,
|
||
"type": "DDR5",
|
||
"max_speed_mhz": 4800,
|
||
"current_speed_mhz": 4800,
|
||
"temperature_c": 43.0,
|
||
"correctable_ecc_error_count": 0,
|
||
"manufacturer": "Hynix",
|
||
"serial_number": "80AD032419E17CEEC1",
|
||
"part_number": "HMCG88AGBRA191N",
|
||
"status": "OK"
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### storage
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `slot` | string | нет | Канонический адрес установки PCIe-устройства; передавайте BDF (`0000:18:00.0`) |
|
||
| `serial_number` | string | нет | Серийный номер |
|
||
| `model` | string | нет | Модель |
|
||
| `manufacturer` | string | нет | Производитель |
|
||
| `type` | string | нет | Тип: `NVMe`, `SSD`, `HDD` |
|
||
| `interface` | string | нет | Интерфейс: `NVMe`, `SATA`, `SAS` |
|
||
| `size_gb` | int | нет | Размер в ГБ |
|
||
| `temperature_c` | float | нет | Температура накопителя, °C (telemetry) |
|
||
| `power_on_hours` | int64 | нет | Время работы, часы |
|
||
| `power_cycles` | int64 | нет | Количество циклов питания |
|
||
| `unsafe_shutdowns` | int64 | нет | Нештатные выключения |
|
||
| `media_errors` | int64 | нет | Ошибки носителя / media errors |
|
||
| `error_log_entries` | int64 | нет | Количество записей в error log |
|
||
| `written_bytes` | int64 | нет | Всего записано байт |
|
||
| `read_bytes` | int64 | нет | Всего прочитано байт |
|
||
| `life_used_pct` | float | нет | Использованный ресурс / wear, % |
|
||
| `life_remaining_pct` | float | нет | Остаточный ресурс / health, % |
|
||
| `available_spare_pct` | float | нет | Доступный spare, % |
|
||
| `reallocated_sectors` | int64 | нет | Переназначенные сектора |
|
||
| `current_pending_sectors` | int64 | нет | Сектора в ожидании ремапа |
|
||
| `offline_uncorrectable` | int64 | нет | Некорректируемые ошибки offline scan |
|
||
| `firmware` | string | нет | Версия прошивки |
|
||
| `present` | bool | нет | Наличие (по умолчанию `true`) |
|
||
| + общие поля статуса | | | см. раздел выше |
|
||
|
||
Диск без `serial_number` игнорируется. Изменение `firmware` создаёт событие `FIRMWARE_CHANGED`.
|
||
|
||
```json
|
||
"storage": [
|
||
{
|
||
"slot": "OB01",
|
||
"type": "NVMe",
|
||
"model": "INTEL SSDPF2KX076T1",
|
||
"size_gb": 7680,
|
||
"temperature_c": 38.5,
|
||
"power_on_hours": 12450,
|
||
"unsafe_shutdowns": 3,
|
||
"written_bytes": 9876543210,
|
||
"life_remaining_pct": 91.0,
|
||
"serial_number": "BTAX41900GF87P6DGN",
|
||
"manufacturer": "Intel",
|
||
"firmware": "9CV10510",
|
||
"interface": "NVMe",
|
||
"present": true,
|
||
"status": "OK"
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### pcie_devices
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `slot` | string | нет | Идентификатор слота |
|
||
| `vendor_id` | int | нет | PCI Vendor ID (decimal) |
|
||
| `device_id` | int | нет | PCI Device ID (decimal) |
|
||
| `numa_node` | int | нет | NUMA node / CPU affinity устройства |
|
||
| `temperature_c` | float | нет | Температура устройства, °C (telemetry) |
|
||
| `power_w` | float | нет | Текущее энергопотребление устройства, Вт (telemetry) |
|
||
| `life_remaining_pct` | float | нет | Остаточный ресурс / health, % |
|
||
| `life_used_pct` | float | нет | Использованный ресурс / wear, % |
|
||
| `ecc_corrected_total` | int64 | нет | Всего корректируемых ECC-ошибок |
|
||
| `ecc_uncorrected_total` | int64 | нет | Всего некорректируемых ECC-ошибок |
|
||
| `hw_slowdown` | bool | нет | Устройство вошло в hardware slowdown / protective mode |
|
||
| `battery_charge_pct` | float | нет | Заряд батареи / supercap, % |
|
||
| `battery_health_pct` | float | нет | Состояние батареи / supercap, % |
|
||
| `battery_temperature_c` | float | нет | Температура батареи / supercap, °C |
|
||
| `battery_voltage_v` | float | нет | Напряжение батареи / supercap, В |
|
||
| `battery_replace_required` | bool | нет | Требуется замена батареи / supercap |
|
||
| `sfp_temperature_c` | float | нет | Температура SFP/optic, °C |
|
||
| `sfp_tx_power_dbm` | float | нет | TX optical power, dBm |
|
||
| `sfp_rx_power_dbm` | float | нет | RX optical power, dBm |
|
||
| `sfp_voltage_v` | float | нет | Напряжение SFP, В |
|
||
| `sfp_bias_ma` | float | нет | Bias current SFP, мА |
|
||
| `bdf` | string | нет | Deprecated alias для `slot`; при наличии ingest нормализует его в `slot` |
|
||
| `device_class` | string | нет | Класс устройства (см. список ниже) |
|
||
| `manufacturer` | string | нет | Производитель |
|
||
| `model` | string | нет | Модель |
|
||
| `serial_number` | string | нет | Серийный номер |
|
||
| `firmware` | string | нет | Версия прошивки |
|
||
| `link_width` | int | нет | Текущая ширина линка |
|
||
| `link_speed` | string | нет | Текущая скорость: `Gen3`, `Gen4`, `Gen5` |
|
||
| `max_link_width` | int | нет | Максимальная ширина линка |
|
||
| `max_link_speed` | string | нет | Максимальная скорость |
|
||
| `mac_addresses` | string[] | нет | MAC-адреса портов (для сетевых устройств) |
|
||
| `present` | bool | нет | Наличие (по умолчанию `true`) |
|
||
| + общие поля статуса | | | см. раздел выше |
|
||
|
||
`numa_node` передавайте для NIC / InfiniBand / RAID / GPU, когда источник знает CPU/NUMA affinity. Поле сохраняется в snapshot-атрибутах PCIe-компонента и дублируется в telemetry для topology use cases.
|
||
Поля `temperature_c` и `power_w` используйте для device-level telemetry GPU / accelerator / smart PCIe devices. Они не влияют на идентификацию компонента.
|
||
|
||
**Генерация serial_number при отсутствии или `"N/A"`:** `{board_serial}-PCIE-{slot}`, где `slot` для PCIe равен BDF.
|
||
|
||
`slot` — единственный канонический адрес компонента. Для PCIe в `slot` передавайте BDF. Поле `bdf` сохраняется только как переходный alias на входе и не должно использоваться как отдельная координата рядом со `slot`.
|
||
|
||
**Значения `device_class`:**
|
||
|
||
| Значение | Назначение |
|
||
|----------|------------|
|
||
| `MassStorageController` | RAID-контроллеры |
|
||
| `StorageController` | HBA, SAS-контроллеры |
|
||
| `NetworkController` | Сетевые адаптеры (InfiniBand, общий) |
|
||
| `EthernetController` | Ethernet NIC |
|
||
| `FibreChannelController` | Fibre Channel HBA |
|
||
| `VideoController` | GPU, видеокарты |
|
||
| `ProcessingAccelerator` | Вычислительные ускорители (AI/ML) |
|
||
| `DisplayController` | Контроллеры дисплея (BMC VGA) |
|
||
|
||
Список открытый: допускаются произвольные строки для нестандартных классов.
|
||
|
||
```json
|
||
"pcie_devices": [
|
||
{
|
||
"slot": "0000:3b:00.0",
|
||
"vendor_id": 5555,
|
||
"device_id": 4401,
|
||
"numa_node": 0,
|
||
"temperature_c": 48.5,
|
||
"power_w": 18.2,
|
||
"sfp_temperature_c": 36.2,
|
||
"sfp_tx_power_dbm": -1.8,
|
||
"sfp_rx_power_dbm": -2.1,
|
||
"device_class": "EthernetController",
|
||
"manufacturer": "Intel",
|
||
"model": "X710 10GbE",
|
||
"serial_number": "K65472-003",
|
||
"firmware": "9.20 0x8000d4ae",
|
||
"mac_addresses": ["3c:fd:fe:aa:bb:cc", "3c:fd:fe:aa:bb:cd"],
|
||
"status": "OK"
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### power_supplies
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `slot` | string | нет | Идентификатор слота |
|
||
| `present` | bool | нет | Наличие (по умолчанию `true`) |
|
||
| `serial_number` | string | нет | Серийный номер |
|
||
| `part_number` | string | нет | Партномер |
|
||
| `model` | string | нет | Модель |
|
||
| `vendor` | string | нет | Производитель |
|
||
| `wattage_w` | int | нет | Мощность в ваттах |
|
||
| `firmware` | string | нет | Версия прошивки |
|
||
| `input_type` | string | нет | Тип входа (например `ACWideRange`) |
|
||
| `input_voltage` | float | нет | Входное напряжение, В (telemetry) |
|
||
| `input_power_w` | float | нет | Входная мощность, Вт (telemetry) |
|
||
| `output_power_w` | float | нет | Выходная мощность, Вт (telemetry) |
|
||
| `temperature_c` | float | нет | Температура PSU, °C (telemetry) |
|
||
| `life_remaining_pct` | float | нет | Остаточный ресурс / health, % |
|
||
| `life_used_pct` | float | нет | Использованный ресурс / wear, % |
|
||
| + общие поля статуса | | | см. раздел выше |
|
||
|
||
Поля telemetry (`input_voltage`, `input_power_w`, `output_power_w`, `temperature_c`, `life_remaining_pct`, `life_used_pct`) сохраняются в атрибутах компонента и не влияют на его идентификацию.
|
||
|
||
PSU без `serial_number` игнорируется.
|
||
|
||
```json
|
||
"power_supplies": [
|
||
{
|
||
"slot": "0",
|
||
"present": true,
|
||
"model": "GW-CRPS3000LW",
|
||
"vendor": "Great Wall",
|
||
"wattage_w": 3000,
|
||
"serial_number": "2P06C102610",
|
||
"firmware": "00.03.05",
|
||
"status": "OK",
|
||
"input_type": "ACWideRange",
|
||
"input_power_w": 137,
|
||
"output_power_w": 104,
|
||
"input_voltage": 215.25,
|
||
"temperature_c": 39.5,
|
||
"life_remaining_pct": 97.0
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### sensors
|
||
|
||
Показания сенсоров сервера. Секция опциональная, не привязана к компонентам.
|
||
Данные хранятся как последнее известное значение (last-known-value) на уровне Asset.
|
||
|
||
```json
|
||
"sensors": {
|
||
"fans": [ ... ],
|
||
"power": [ ... ],
|
||
"temperatures": [ ... ],
|
||
"other": [ ... ]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### event_logs
|
||
|
||
Нормализованные операционные логи сервера из `host`, `bmc` или `redfish`.
|
||
|
||
Эти записи не попадают в history timeline и не создают history events. Они сохраняются в отдельной deduplicated log store и отображаются в отдельном UI-блоке asset logs / host logs.
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `source` | string | **да** | Источник лога: `host`, `bmc`, `redfish` |
|
||
| `event_time` | string RFC3339 | нет | Время события из источника; если отсутствует, используется время ingest/collection |
|
||
| `severity` | string | нет | Уровень: `OK`, `Info`, `Warning`, `Critical`, `Unknown` |
|
||
| `message_id` | string | нет | Идентификатор/код события источника |
|
||
| `message` | string | **да** | Нормализованный текст события |
|
||
| `component_ref` | string | нет | Ссылка на компонент/устройство/слот, если извлекается |
|
||
| `fingerprint` | string | нет | Внешний готовый dedup-key; если не передан, система вычисляет свой |
|
||
| `is_active` | bool | нет | Признак, что событие всё ещё активно/не погашено, если источник умеет lifecycle |
|
||
| `raw_payload` | object | нет | Сырой vendor-specific payload для диагностики |
|
||
|
||
**Правила event_logs:**
|
||
- Логи дедуплицируются в рамках asset + source + fingerprint.
|
||
- Если `fingerprint` не передан, система строит его из нормализованных полей (`source`, `message_id`, `message`, `component_ref`, временная нормализация).
|
||
- Интегратор/сборщик логов не должен синтезировать содержимое событий: не придумывайте `message`, `message_id`, `component_ref`, serial/device identifiers или иные поля, если они отсутствуют в исходном логе или не были надёжно извлечены.
|
||
- Повторное получение того же события обновляет `last_seen_at`/счётчик повторов и не должно создавать новый timeline/history event.
|
||
- `event_logs` используются для отдельного UI-представления логов и не изменяют canonical state компонентов/asset по умолчанию.
|
||
|
||
```json
|
||
"event_logs": [
|
||
{
|
||
"source": "bmc",
|
||
"event_time": "2026-03-15T14:03:11Z",
|
||
"severity": "Warning",
|
||
"message_id": "0x000F",
|
||
"message": "Correctable ECC error threshold exceeded",
|
||
"component_ref": "CPU0_C0D0",
|
||
"raw_payload": {
|
||
"sensor": "DIMM_A1",
|
||
"sel_record_id": "0042"
|
||
}
|
||
},
|
||
{
|
||
"source": "redfish",
|
||
"event_time": "2026-03-15T14:03:20Z",
|
||
"severity": "Info",
|
||
"message_id": "OpenBMC.0.1.SystemReboot",
|
||
"message": "System reboot requested by administrator",
|
||
"component_ref": "Mainboard"
|
||
}
|
||
]
|
||
```
|
||
|
||
#### sensors.fans
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `name` | string | **да** | Уникальное имя сенсора в рамках секции |
|
||
| `location` | string | нет | Физическое расположение |
|
||
| `rpm` | int | нет | Обороты, RPM |
|
||
| `status` | string | нет | Статус: `OK`, `Warning`, `Critical`, `Unknown` |
|
||
|
||
#### sensors.power
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `name` | string | **да** | Уникальное имя сенсора |
|
||
| `location` | string | нет | Физическое расположение |
|
||
| `voltage_v` | float | нет | Напряжение, В |
|
||
| `current_a` | float | нет | Ток, А |
|
||
| `power_w` | float | нет | Мощность, Вт |
|
||
| `status` | string | нет | Статус |
|
||
|
||
#### sensors.temperatures
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `name` | string | **да** | Уникальное имя сенсора |
|
||
| `location` | string | нет | Физическое расположение |
|
||
| `celsius` | float | нет | Температура, °C |
|
||
| `threshold_warning_celsius` | float | нет | Порог Warning, °C |
|
||
| `threshold_critical_celsius` | float | нет | Порог Critical, °C |
|
||
| `status` | string | нет | Статус |
|
||
|
||
#### sensors.other
|
||
|
||
| Поле | Тип | Обязательно | Описание |
|
||
|------|-----|-------------|----------|
|
||
| `name` | string | **да** | Уникальное имя сенсора |
|
||
| `location` | string | нет | Физическое расположение |
|
||
| `value` | float | нет | Значение |
|
||
| `unit` | string | нет | Единица измерения |
|
||
| `status` | string | нет | Статус |
|
||
|
||
**Правила sensors:**
|
||
- Идентификатор сенсора: пара `(sensor_type, name)`. Дубли в одном payload — берётся первое вхождение.
|
||
- Сенсоры без `name` игнорируются.
|
||
- При каждом импорте значения перезаписываются (upsert по ключу).
|
||
|
||
```json
|
||
"sensors": {
|
||
"fans": [
|
||
{ "name": "FAN1", "location": "Front", "rpm": 4200, "status": "OK" },
|
||
{ "name": "FAN_CPU0", "location": "CPU0", "rpm": 5600, "status": "OK" }
|
||
],
|
||
"power": [
|
||
{ "name": "12V Rail", "location": "Mainboard", "voltage_v": 12.06, "status": "OK" },
|
||
{ "name": "PSU0 Input", "location": "PSU0", "voltage_v": 215.25, "current_a": 0.64, "power_w": 137.0, "status": "OK" }
|
||
],
|
||
"temperatures": [
|
||
{ "name": "CPU0 Temp", "location": "CPU0", "celsius": 46.0, "threshold_warning_celsius": 80.0, "threshold_critical_celsius": 95.0, "status": "OK" },
|
||
{ "name": "Inlet Temp", "location": "Front", "celsius": 22.0, "threshold_warning_celsius": 40.0, "threshold_critical_celsius": 50.0, "status": "OK" }
|
||
],
|
||
"other": [
|
||
{ "name": "System Humidity", "value": 38.5, "unit": "%", "status": "OK" }
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Обработка статусов компонентов
|
||
|
||
| Статус | Поведение |
|
||
|--------|-----------|
|
||
| `OK` | Нормальная обработка |
|
||
| `Warning` | Создаётся событие `COMPONENT_WARNING` |
|
||
| `Critical` | Создаётся событие `COMPONENT_FAILED` + запись в `failure_events` |
|
||
| `Unknown` | Компонент считается рабочим, создаётся событие `COMPONENT_UNKNOWN` |
|
||
| `Empty` | Компонент не создаётся/не обновляется |
|
||
|
||
---
|
||
|
||
## Обработка отсутствующих serial_number
|
||
|
||
Общее правило для всех секций: если источник не вернул серийный номер и сборщик не смог его надёжно извлечь, интегратор не должен подставлять вымышленные значения, хеши, локальные placeholder-идентификаторы или серийные номера "по догадке". Разрешены только явно оговорённые ниже server-side fallback-правила ingest.
|
||
|
||
| Тип | Поведение |
|
||
|-----|-----------|
|
||
| CPU | Генерируется: `{board_serial}-CPU-{socket}` |
|
||
| PCIe | Генерируется: `{board_serial}-PCIE-{slot}` (если serial = `"N/A"` или пустой; `slot` для PCIe = BDF) |
|
||
| Memory | Компонент игнорируется |
|
||
| Storage | Компонент игнорируется |
|
||
| PSU | Компонент игнорируется |
|
||
|
||
Если `serial_number` не уникален внутри одного payload для того же `model`:
|
||
- Первое вхождение сохраняет оригинальный серийный номер.
|
||
- Каждое следующее дублирующее получает placeholder: `NO_SN-XXXXXXXX`.
|
||
|
||
---
|
||
|
||
## Минимальный валидный пример
|
||
|
||
```json
|
||
{
|
||
"collected_at": "2026-02-10T15:30:00Z",
|
||
"target_host": "192.168.1.100",
|
||
"hardware": {
|
||
"board": {
|
||
"serial_number": "SRV-001"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Полный пример с историей статусов
|
||
|
||
```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": {
|
||
"manufacturer": "Supermicro",
|
||
"product_name": "X12DPG-QT6",
|
||
"serial_number": "21D634101"
|
||
},
|
||
"firmware": [
|
||
{ "device_name": "BIOS", "version": "06.08.05" },
|
||
{ "device_name": "BMC", "version": "5.17.00" }
|
||
],
|
||
"cpus": [
|
||
{
|
||
"socket": 0,
|
||
"model": "INTEL(R) XEON(R) GOLD 6530",
|
||
"manufacturer": "Intel",
|
||
"cores": 32,
|
||
"threads": 64,
|
||
"status": "OK"
|
||
}
|
||
],
|
||
"storage": [
|
||
{
|
||
"slot": "OB01",
|
||
"type": "NVMe",
|
||
"model": "INTEL SSDPF2KX076T1",
|
||
"size_gb": 7680,
|
||
"serial_number": "BTAX41900GF87P6DGN",
|
||
"manufacturer": "Intel",
|
||
"firmware": "9CV10510",
|
||
"present": true,
|
||
"status": "OK",
|
||
"status_changed_at": "2026-02-10T15:22:00Z",
|
||
"status_history": [
|
||
{ "status": "Critical", "changed_at": "2026-02-10T15:10:00Z", "details": "I/O timeout on NVMe queue 3" },
|
||
{ "status": "OK", "changed_at": "2026-02-10T15:22:00Z", "details": "Recovered after controller reset" }
|
||
]
|
||
}
|
||
],
|
||
"pcie_devices": [
|
||
{
|
||
"slot": "0000:18:00.0",
|
||
"device_class": "EthernetController",
|
||
"manufacturer": "Intel",
|
||
"model": "X710 10GbE",
|
||
"serial_number": "K65472-003",
|
||
"mac_addresses": ["3c:fd:fe:aa:bb:cc", "3c:fd:fe:aa:bb:cd"],
|
||
"status": "OK"
|
||
}
|
||
],
|
||
"power_supplies": [
|
||
{
|
||
"slot": "0",
|
||
"present": true,
|
||
"model": "GW-CRPS3000LW",
|
||
"vendor": "Great Wall",
|
||
"wattage_w": 3000,
|
||
"serial_number": "2P06C102610",
|
||
"firmware": "00.03.05",
|
||
"status": "OK",
|
||
"input_power_w": 137,
|
||
"output_power_w": 104,
|
||
"input_voltage": 215.25
|
||
}
|
||
],
|
||
"sensors": {
|
||
"fans": [
|
||
{ "name": "FAN1", "location": "Front", "rpm": 4200, "status": "OK" }
|
||
],
|
||
"power": [
|
||
{ "name": "12V Rail", "voltage_v": 12.06, "status": "OK" }
|
||
],
|
||
"temperatures": [
|
||
{ "name": "CPU0 Temp", "celsius": 46.0, "threshold_warning_celsius": 80.0, "threshold_critical_celsius": 95.0, "status": "OK" }
|
||
],
|
||
"other": [
|
||
{ "name": "System Humidity", "value": 38.5, "unit": "%" }
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|