--- 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": "%" } ] } } } ```