Files
core/bible-local/docs/hardware-ingest-contract.md
2026-03-15 16:29:24 +03:00

24 KiB
Raw Blame History

title, version, updated, maintainer, audience, language
title version updated maintainer audience language
Hardware Ingest JSON Contract 2.1 2026-03-15 Reanimator Core external-integrators, ai-agents ru

Интеграция с Reanimator: контракт JSON-импорта аппаратного обеспечения

Версия: 2.1 · Дата: 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.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 и др.).

Endpoint

POST /ingest/hardware
Content-Type: application/json

Ответ при приёме (202 Accepted):

{
  "status": "accepted",
  "job_id": "job_01J..."
}

Импорт выполняется асинхронно. Результат доступен по:

GET /ingest/hardware/jobs/{job_id}

Ответ при успехе задачи:

{
  "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
  }
}

Ответ при дубликате:

{
  "status": "success",
  "duplicate": true,
  "message": "LogBundle with this content hash already exists"
}

Ответ при ошибке (400 Bad Request):

{
  "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-поля на любом уровне.
  • Тело запроса превышает допустимый размер.

Структура верхнего уровня

{
  "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":        { ... }
  }
}

Поля верхнего уровня

Поле Тип Обязательно Описание
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 Текст ошибки/диагностики

Объект 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).

Секции hardware

board

Основная информация о сервере. Обязательная секция.

Поле Тип Обязательно Описание
serial_number string да Серийный номер (ключ идентификации Asset)
manufacturer string нет Производитель
product_name string нет Модель
part_number string нет Партномер
uuid string нет UUID системы

Значения "NULL" в строковых полях трактуются как отсутствие данных.

"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.

"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 нет Максимальная частота
serial_number string нет Серийный номер (если доступен)
firmware string нет Версия микрокода
present bool нет Наличие (по умолчанию true)
+ общие поля статуса см. раздел выше

Генерация serial_number при отсутствии: {board_serial}-CPU-{socket}

"cpus": [
  {
    "socket": 0,
    "model": "INTEL(R) XEON(R) GOLD 6530",
    "cores": 32,
    "threads": 64,
    "frequency_mhz": 2100,
    "max_frequency_mhz": 4000,
    "manufacturer": "Intel",
    "status": "OK",
    "status_checked_at": "2026-02-10T15:28:00Z"
  }
]

memory

Поле Тип Обязательно Описание
slot string нет Идентификатор слота
location 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 нет Текущая частота
+ общие поля статуса см. раздел выше

Модуль без serial_number игнорируется. Модуль с present=false или status=Empty игнорируется.

"memory": [
  {
    "slot": "CPU0_C0D0",
    "present": true,
    "size_mb": 32768,
    "type": "DDR5",
    "max_speed_mhz": 4800,
    "current_speed_mhz": 4800,
    "manufacturer": "Hynix",
    "serial_number": "80AD032419E17CEEC1",
    "part_number": "HMCG88AGBRA191N",
    "status": "OK"
  }
]

storage

Поле Тип Обязательно Описание
slot string нет Идентификатор слота
serial_number string нет Серийный номер
model string нет Модель
manufacturer string нет Производитель
type string нет Тип: NVMe, SSD, HDD
interface string нет Интерфейс: NVMe, SATA, SAS
size_gb int нет Размер в ГБ
firmware string нет Версия прошивки
present bool нет Наличие (по умолчанию true)
+ общие поля статуса см. раздел выше

Диск без serial_number игнорируется. Изменение firmware создаёт событие FIRMWARE_CHANGED.

"storage": [
  {
    "slot": "OB01",
    "type": "NVMe",
    "model": "INTEL SSDPF2KX076T1",
    "size_gb": 7680,
    "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)
bdf string нет Bus:Device.Function, например 0000:18:00.0
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)
+ общие поля статуса см. раздел выше

Генерация serial_number при отсутствии или "N/A": {board_serial}-PCIE-{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)

Список открытый: допускаются произвольные строки для нестандартных классов.

"pcie_devices": [
  {
    "slot": "PCIeCard2",
    "vendor_id": 5555,
    "device_id": 4401,
    "bdf": "0000:3b:00.0",
    "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)
+ общие поля статуса см. раздел выше

Поля telemetry (input_voltage, input_power_w, output_power_w) сохраняются в атрибутах компонента и не влияют на его идентификацию.

PSU без serial_number игнорируется.

"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
  }
]

sensors

Показания сенсоров сервера. Секция опциональная, не привязана к компонентам. Данные хранятся как последнее известное значение (last-known-value) на уровне Asset.

"sensors": {
  "fans":         [ ... ],
  "power":        [ ... ],
  "temperatures": [ ... ],
  "other":        [ ... ]
}

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 по ключу).
"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

Тип Поведение
CPU Генерируется: {board_serial}-CPU-{socket}
PCIe Генерируется: {board_serial}-PCIE-{slot} (если serial = "N/A" или пустой)
Memory Компонент игнорируется
Storage Компонент игнорируется
PSU Компонент игнорируется

Если serial_number не уникален внутри одного payload для того же model:

  • Первое вхождение сохраняет оригинальный серийный номер.
  • Каждое следующее дублирующее получает placeholder: NO_SN-XXXXXXXX.

Минимальный валидный пример

{
  "collected_at": "2026-02-10T15:30:00Z",
  "target_host": "192.168.1.100",
  "hardware": {
    "board": {
      "serial_number": "SRV-001"
    }
  }
}

Полный пример с историей статусов

{
  "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": "PCIeCard1",
        "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": "%" }
      ]
    }
  }
}