Files
logpile/docs/INTEGRATION_GUIDE.md

37 KiB
Raw Blame History

Руководство по интеграции Reanimator

Импорт серверов через JSON (Redfish/API)

Данное руководство описывает формат JSON для импорта аппаратной информации о серверах, собранной через Redfish API или другие источники мониторинга.


Принципы импорта

  1. Snapshot данных - JSON содержит состояние сервера на момент сбора и может включать историю изменений статуса компонентов
  2. Автоматическое определение LOT - классификация компонентов определяется приложением на основе vendor/model/type
  3. Статус компонентов - каждый компонент имеет статус работоспособности (OK, Warning, Critical, Unknown) и может передавать время проверки статуса
  4. Идемпотентность - повторный импорт с тем же snapshot не создает дубликаты
  5. Event-driven обновления - импорт создает события в timeline (LOG_COLLECTED, INSTALLED, REMOVED, FIRMWARE_CHANGED)

Формат JSON для импорта

Важно: endpoint использует строгий JSON-декодер (DisallowUnknownFields). Любое неизвестное поле (включая вложенные объекты) приведет к 400 Bad Request. Используйте только snake_case ключи из этого руководства.

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

{
  "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": {...},
    "cpus": [...],
    "memory": [...],
    "storage": [...],
    "pcie_devices": [...],
    "power_supplies": [...],
    "firmware": [...]
  }
}

Обязательные поля верхнего уровня

  • collected_at (string RFC3339, обязательно) - время сбора информации
  • target_host (string, опционально) - IP или hostname сервера
  • hardware.board.serial_number (string, обязательно) - серийный номер сервера/платы
  • source_type (string, опционально) - тип источника: api, logfile, manual
  • protocol (string, опционально) - протокол сбора: redfish, ipmi, snmp, ssh
  • filename (string, опционально) - идентификатор источника данных
  • hardware (object, обязательно) - структура с аппаратными компонентами

Общее поле статуса для компонентных секций

Для секций cpus, memory, storage, pcie_devices, power_supplies поддерживается дополнительное поле:

  • status_checked_at (string RFC3339, опционально) - дата/время, когда был проверен статус работоспособности компонента
  • status_changed_at (string RFC3339, опционально) - дата/время последнего изменения статуса компонента
  • status_at_collection (object, опционально) - зафиксированный статус на момент сбора логов:
    • status (string) - статус в момент сбора (OK, Warning, Critical, Unknown, Empty)
    • at (string RFC3339) - дата/время, к которому относится этот статус
  • status_history (array, опционально) - история статусов компонента:
    • status (string) - статус (OK, Warning, Critical, Unknown, Empty)
    • changed_at (string RFC3339) - дата/время смены статуса
    • details (string, опционально) - пояснение к переходу статуса
  • error_description (string, опционально) - текст ошибки/диагностики для статуса компонента (например при Warning/Critical)

Правила экспорта JSON для внешнего проекта

Используйте эти правила, если JSON формируется внешним сервисом/экспортером:

  1. Всегда передавайте status как текущее состояние компонента в snapshot.
  2. Если есть точное время последней смены, передавайте status_changed_at (RFC3339, UTC).
  3. Если источник умеет фиксировать состояние именно на момент сбора, передавайте status_at_collection c полями status и at.
  4. Если источник хранит историю (например Windows Event Log), передавайте status_history отсортированным по changed_at по возрастанию.
  5. В status_history не отправляйте записи без changed_at; такие записи игнорируются.
  6. Для совместимости допускается передавать только старые поля (status, status_checked_at) без истории.
  7. Все даты/время в исторических полях должны быть RFC3339; рекомендуется использовать UTC (Z).

Секция hardware

1. Board (Материнская плата / Server)

Назначение: Основная информация о сервере/материнской плате. Эта информация используется для создания/обновления Asset.

{
  "board": {
    "manufacturer": "Supermicro",
    "product_name": "X12DPG-QT6",
    "serial_number": "21D634101",
    "part_number": "X12DPG-QT6-REV1.01",
    "uuid": "d7ef2fe5-2fd0-11f0-910a-346f11040868"
  }
}

Поля:

  • serial_number (string, обязательно) - серийный номер материнской платы/сервера (используется как vendor_serial для Asset)
  • manufacturer (string, опционально) - производитель (используется как vendor для Asset)
  • product_name (string, опционально) - модель (используется как model для Asset)
  • part_number (string, опционально) - партномер
  • uuid (string, опционально) - UUID системы

Примечание: Если manufacturer или product_name = "NULL", они интерпретируются как отсутствующие.


2. CPUs (Процессоры)

Назначение: Информация о установленных процессорах.

{
  "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"
    },
    {
      "socket": 1,
      "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"
    }
  ]
}

Поля:

  • socket (int, обязательно) - номер сокета (используется для формирования уникального идентификатора)
  • model (string, обязательно) - модель процессора
  • cores (int, опционально) - количество ядер
  • threads (int, опционально) - количество потоков
  • frequency_mhz (int, опционально) - текущая частота в МГц
  • max_frequency_mhz (int, опционально) - максимальная частота в МГц
  • manufacturer (string, опционально) - производитель (Intel, AMD, etc.)
  • status (string, опционально) - статус: OK, Warning, Critical, Unknown
  • status_checked_at (string RFC3339, опционально) - дата/время проверки статуса

Генерация serial_number:

  • Формат: {board_serial}-CPU-{socket}
  • Пример: 21D634101-CPU-0, 21D634101-CPU-1

LOT автоопределение:

  • Формат: CPU_{NORMALIZED_MODEL}
  • Пример: CPU_XEON_GOLD_6530, CPU_EPYC_7763

3. Memory (Модули памяти)

Назначение: Информация о модулях памяти (DIMM).

{
  "memory": [
    {
      "slot": "CPU0_C0D0",
      "location": "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",
      "status_checked_at": "2026-02-10T15:28:00Z"
    },
    {
      "slot": "CPU0_C1D0",
      "location": "CPU0_C1D0",
      "present": false,
      "size_mb": 0,
      "type": null,
      "manufacturer": null,
      "serial_number": null,
      "part_number": null,
      "status": "Empty"
    }
  ]
}

Поля:

  • slot (string, обязательно) - идентификатор слота
  • location (string, опционально) - физическое расположение
  • present (bool, обязательно) - наличие модуля в слоте
  • size_mb (int, опционально) - размер в МБ
  • type (string, опционально) - тип памяти: DDR4, DDR5, DDR3, etc.
  • max_speed_mhz (int, опционально) - максимальная частота
  • current_speed_mhz (int, опционально) - текущая частота
  • manufacturer (string, опционально) - производитель
  • serial_number (string, условно обязательно если present=true) - серийный номер
  • part_number (string, опционально) - партномер
  • status (string, опционально) - статус: OK, Warning, Critical, Unknown, Empty
  • status_checked_at (string RFC3339, опционально) - дата/время проверки статуса

Обработка:

  • Если present = false или status = "Empty", компонент не создается/не обновляется
  • Если модуль был в предыдущем snapshot, но отсутствует в текущем - создается событие REMOVED

LOT автоопределение:

  • Формат: DIMM_{TYPE}_{SIZE_GB}GB
  • Пример: DIMM_DDR5_32GB, DIMM_DDR4_64GB

4. Storage (Диски)

Назначение: Информация о дисках (SSD, HDD, NVMe).

{
  "storage": [
    {
      "slot": "OB01",
      "type": "NVMe",
      "model": "INTEL SSDPF2KX076T1",
      "size_gb": 7680,
      "serial_number": "BTAX41900GF87P6DGN",
      "manufacturer": "Intel",
      "firmware": "9CV10510",
      "interface": "NVMe",
      "present": true,
      "status": "OK"
    },
    {
      "slot": "FP00HDD00",
      "type": "HDD",
      "model": "ST12000NM0008",
      "size_gb": 12000,
      "serial_number": "ZJV01234",
      "manufacturer": "Seagate",
      "firmware": "SN03",
      "interface": "SATA",
      "present": true,
      "status": "OK"
    }
  ]
}

Поля:

  • slot (string, обязательно) - идентификатор слота
  • type (string, опционально) - тип: NVMe, SSD, HDD
  • model (string, обязательно) - модель диска
  • size_gb (int, опционально) - размер в ГБ
  • serial_number (string, обязательно) - серийный номер
  • manufacturer (string, опционально) - производитель (может быть VID в hex формате типа "8086")
  • firmware (string, опционально) - версия прошивки
  • interface (string, опционально) - интерфейс: NVMe, SATA, SAS
  • present (bool, обязательно) - наличие диска в слоте
  • status (string, опционально) - статус: OK, Warning, Critical, Unknown
  • status_checked_at (string RFC3339, опционально) - дата/время проверки статуса

Обработка firmware:

  • Если версия firmware изменилась относительно предыдущего observation - создается событие FIRMWARE_CHANGED

LOT автоопределение:

  • Формат: {TYPE}_{INTERFACE}_{SIZE_TB}TB или {TYPE}_{INTERFACE}_{SIZE_GB}GB
  • Пример: SSD_NVME_07.68TB, HDD_SATA_12TB

5. Power Supplies (Блоки питания)

Назначение: Информация о блоках питания.

{
  "power_supplies": [
    {
      "slot": "0",
      "present": true,
      "model": "GW-CRPS3000LW",
      "vendor": "Great Wall",
      "wattage_w": 3000,
      "serial_number": "2P06C102610",
      "part_number": "V0310C9000000000",
      "firmware": "00.03.05",
      "status": "OK",
      "status_checked_at": "2026-02-10T15:28:00Z",
      "input_type": "ACWideRange",
      "input_power_w": 137,
      "output_power_w": 104,
      "input_voltage": 215.25
    }
  ]
}

Поля:

  • slot (string, обязательно) - идентификатор слота
  • present (bool, обязательно) - наличие PSU
  • model (string, опционально) - модель
  • vendor (string, опционально) - производитель
  • wattage_w (int, опционально) - мощность в ваттах
  • serial_number (string, условно обязательно если present=true) - серийный номер
  • part_number (string, опционально) - партномер
  • firmware (string, опционально) - версия прошивки
  • status (string, опционально) - статус: OK, Warning, Critical, Unknown
  • status_checked_at (string RFC3339, опционально) - дата/время проверки статуса
  • input_type (string, опционально) - тип входа
  • input_power_w (int, опционально) - входная мощность (telemetry)
  • output_power_w (int, опционально) - выходная мощность (telemetry)
  • input_voltage (float, опционально) - входное напряжение (telemetry)

Примечание: Telemetry поля (input_power_w, output_power_w, input_voltage) сохраняются в observation, но не влияют на Component.

LOT автоопределение:

  • Формат: PSU_{WATTAGE}W
  • Пример: PSU_3000W, PSU_1600W

6. PCIe Devices (PCIe устройства)

Назначение: Информация о PCIe устройствах (NIC, RAID контроллеры, GPU, etc.).

{
  "pcie_devices": [
    {
      "slot": "PCIeCard1",
      "vendor_id": 32902,
      "device_id": 2912,
      "bdf": "0000:18:00.0",
      "device_class": "MassStorageController",
      "manufacturer": "Intel",
      "model": "RAID Controller RSP3DD080F",
      "link_width": 8,
      "link_speed": "Gen3",
      "max_link_width": 8,
      "max_link_speed": "Gen3",
      "serial_number": "RAID-001-12345",
      "firmware": "50.9.1-4296",
      "status": "OK",
      "status_checked_at": "2026-02-10T15:28:00Z"
    },
    {
      "slot": "PCIeCard2",
      "vendor_id": 5555,
      "device_id": 4401,
      "bdf": "",
      "device_class": "NetworkController",
      "manufacturer": "Mellanox",
      "model": "ConnectX-5",
      "link_width": 16,
      "link_speed": "Gen3",
      "max_link_width": 16,
      "max_link_speed": "Gen3",
      "serial_number": "MT2892012345",
      "status": "OK"
    }
  ]
}

Поля:

  • slot (string, обязательно) - идентификатор слота
  • vendor_id (int, опционально) - PCI Vendor ID (hex в decimal)
  • device_id (int, опционально) - PCI Device ID (hex в decimal)
  • bdf (string, опционально) - Bus:Device.Function (например "0000:18:00.0")
  • device_class (string, опционально) - класс устройства: NetworkController, MassStorageController, DisplayController, etc.
  • manufacturer (string, опционально) - производитель
  • model (string, опционально) - модель устройства
  • link_width (int, опционально) - текущая ширина линка (x1, x4, x8, x16)
  • link_speed (string, опционально) - текущая скорость линка (Gen3, Gen4, Gen5)
  • max_link_width (int, опционально) - максимальная ширина линка
  • max_link_speed (string, опционально) - максимальная скорость линка
  • serial_number (string, опционально) - серийный номер (если доступен, иначе генерируется)
  • firmware (string, опционально) - версия прошивки
  • status (string, опционально) - статус: OK, Warning, Critical, Unknown
  • status_checked_at (string RFC3339, опционально) - дата/время проверки статуса

Генерация serial_number (если отсутствует):

  • Формат: {board_serial}-PCIE-{slot}
  • Пример: 21D634101-PCIE-PCIeCard1

LOT автоопределение:

  • Формат: PCIE_{DEVICE_CLASS}_{NORMALIZED_MODEL} или PCIE_{DEVICE_CLASS}_{VENDOR_ID}_{DEVICE_ID}
  • Пример: PCIE_NETWORK_CONNECTX5, PCIE_STORAGE_32902_2912

7. Firmware (Прошивки системных компонентов)

Назначение: Информация о версиях прошивок системных компонентов (BIOS, BMC, etc.).

{
  "firmware": [
    {
      "device_name": "BIOS",
      "version": "06.08.05 (2025-05-15 18:39:00)"
    },
    {
      "device_name": "BMC",
      "version": "5.17.00 (2025-04-22 12:06:31)"
    }
  ]
}

Поля:

  • device_name (string, обязательно) - название устройства: BIOS, BMC, CPLD, etc.
  • version (string, обязательно) - версия прошивки

Обработка:

  • Firmware данные сохраняются в observation
  • Изменения версий firmware системных компонентов создают события FIRMWARE_CHANGED для Asset

Полный пример 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",
      "part_number": "X12DPG-QT6-REV1.01",
      "uuid": "d7ef2fe5-2fd0-11f0-910a-346f11040868"
    },
    "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",
        "cores": 32,
        "threads": 64,
        "frequency_mhz": 2100,
        "max_frequency_mhz": 4000,
        "manufacturer": "Intel",
        "status": "OK"
      },
      {
        "socket": 1,
        "model": "INTEL(R) XEON(R) GOLD 6530",
        "cores": 32,
        "threads": 64,
        "frequency_mhz": 2100,
        "max_frequency_mhz": 4000,
        "manufacturer": "Intel",
        "status": "OK"
      }
    ],
    "memory": [
      {
        "slot": "CPU0_C0D0",
        "location": "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"
      },
      {
        "slot": "CPU1_C0D0",
        "location": "CPU1_C0D0",
        "present": true,
        "size_mb": 32768,
        "type": "DDR5",
        "max_speed_mhz": 4800,
        "current_speed_mhz": 4800,
        "manufacturer": "Hynix",
        "serial_number": "80AD032419E17D6FBA",
        "part_number": "HMCG88AGBRA191N",
        "status": "OK"
      }
    ],
    "storage": [
      {
        "slot": "OB01",
        "type": "NVMe",
        "model": "INTEL SSDPF2KX076T1",
        "size_gb": 7680,
        "serial_number": "BTAX41900GF87P6DGN",
        "manufacturer": "Intel",
        "firmware": "9CV10510",
        "interface": "NVMe",
        "present": true,
        "status": "OK"
      },
      {
        "slot": "OB02",
        "type": "NVMe",
        "model": "INTEL SSDPF2KX076T1",
        "size_gb": 7680,
        "serial_number": "BTAX41900BEG7P6DGN",
        "manufacturer": "Intel",
        "firmware": "9CV10510",
        "interface": "NVMe",
        "present": true,
        "status": "OK"
      }
    ],
    "pcie_devices": [
      {
        "slot": "PCIeCard1",
        "vendor_id": 32902,
        "device_id": 2912,
        "bdf": "0000:18:00.0",
        "device_class": "MassStorageController",
        "manufacturer": "Intel",
        "model": "RAID Controller",
        "serial_number": "RAID-001-12345",
        "status": "OK"
      }
    ],
    "power_supplies": [
      {
        "slot": "0",
        "present": true,
        "model": "GW-CRPS3000LW",
        "vendor": "Great Wall",
        "wattage_w": 3000,
        "serial_number": "2P06C102610",
        "part_number": "V0310C9000000000",
        "firmware": "00.03.05",
        "status": "OK",
        "input_power_w": 137,
        "output_power_w": 104,
        "input_voltage": 215.25
      }
    ]
  }
}

Процесс обработки импорта

1. Валидация входных данных

  • Проверка наличия обязательных полей: collected_at, hardware.board.serial_number
  • Проверка формата collected_at (RFC3339)
  • Проверка наличия hardware.board.serial_number

2. Поиск или создание Asset

Поиск: по hardware.board.serial_number (= vendor_serial в таблице assets)

Создание/Обновление:

vendor_serial = board.serial_number
vendor = board.manufacturer (если != "NULL")
model = board.product_name (если != "NULL")
name = target_host (если передан), иначе `hardware.board.serial_number`

Примечание: Asset должен быть связан с Project. Если project_id не задан, используется default project для данного импорта.

3. Обработка компонентов

Для каждого типа компонентов (cpus, memory, storage, pcie_devices, power_supplies):

3.1. Фильтрация

  • Игнорировать компоненты с present = false (кроме создания REMOVED events)
  • Игнорировать компоненты без serial_number (после генерации, если применимо)

3.2. Определение LOT

  • Автоматически определить LOT на основе vendor/model/type/size
  • Создать LOT если не существует
  • Связать component с lot_id

3.3. Поиск или создание Component

Поиск: по vendor_serial

Создание/Обновление:

vendor_serial = {serial_number или generated}
vendor = {manufacturer}
model = {model}
lot_id = {auto-determined lot}

3.4. Создание Observation

Для каждого компонента создается observation запись:

log_bundle_id = {created bundle}
asset_id = {asset.id}
component_id = {component.id}
observed_at = collected_at

Дополнительные данные сохраняются в JSON поле observation (slot, status, firmware, telemetry, etc.)

3.5. Обновление Installations

Логика:

  • Если компонент уже установлен в этот asset (installations.removed_at IS NULL) - ничего не делать
  • Если компонент был в другом asset - закрыть старую installation (установить removed_at)
  • Создать новую installation:
    asset_id = {asset.id}
    component_id = {component.id}
    installed_at = collected_at (или first_seen_at если компонент новый)
    removed_at = NULL
    

3.6. Определение removed компонентов

Сравнить текущий snapshot с предыдущим observation для этого asset:

  • Если компонент был в предыдущем observation, но отсутствует в текущем - закрыть installation (removed_at = collected_at)

4. Создание Timeline Events

События создаются автоматически на основе изменений:

LOG_COLLECTED:

subject_type = "asset"
subject_id = asset.id
event_type = "LOG_COLLECTED"
event_time = collected_at

INSTALLED: (при создании новой installation)

subject_type = "component"
subject_id = component.id
event_type = "INSTALLED"
event_time = installed_at
asset_id = asset.id
component_id = component.id

REMOVED: (при закрытии installation)

subject_type = "component"
subject_id = component.id
event_type = "REMOVED"
event_time = removed_at
asset_id = asset.id
component_id = component.id

FIRMWARE_CHANGED: (при изменении firmware версии)

subject_type = "component" (или "asset" для BIOS/BMC)
subject_id = {id}
event_type = "FIRMWARE_CHANGED"
event_time = collected_at
firmware_version = {new version}

5. Обработка статусов компонентов

Статусы (OK, Warning, Critical, Unknown) сохраняются в observation и могут быть использованы для:

  • Анализа трендов деградации
  • Автоматического создания failure events (если status = "Critical")
  • Dashboard отображения текущего состояния

API Endpoint для импорта

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

{
  "collected_at": "2026-02-10T15:30:00Z",
  "target_host": "10.10.10.103",
  "hardware": {...}
}

Ответ при успехе (201 Created)

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

Ответ при дубликате (200 OK)

{
  "status": "success",
  "bundle_id": "lb_01J...",
  "asset_id": "mach_01J...",
  "collected_at": "2026-02-10T15:30:00Z",
  "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 Bad Request

  • Лишние поля в JSON (даже глубоко во вложенных объектах).
  • Неверное имя ключа (например, targetHost вместо target_host).
  • Неверный формат даты (collected_at должен быть RFC3339).
  • Пустой hardware.board.serial_number.

Правила автоопределения LOT

CPU

Формат: CPU_{VENDOR}_{MODEL_NORMALIZED}
Пример:
  "INTEL(R) XEON(R) GOLD 6530" -> "CPU_INTEL_XEON_GOLD_6530"
  "AMD EPYC 7763" -> "CPU_AMD_EPYC_7763"

Memory (DIMM)

Формат: DIMM_{TYPE}_{SIZE_GB}GB
Пример:
  DDR5 32GB -> "DIMM_DDR5_32GB"
  DDR4 64GB -> "DIMM_DDR4_64GB"

Storage

Формат: {TYPE}_{INTERFACE}_{SIZE_TB}TB (или GB для маленьких дисков)
Пример:
  NVMe 7.68TB -> "SSD_NVME_07.68TB"
  HDD 12TB -> "HDD_SATA_12TB"
  SSD 960GB -> "SSD_SATA_0.96TB" или "SSD_SATA_960GB"

Power Supply

Формат: PSU_{WATTAGE}W_{VENDOR_NORMALIZED}
Пример:
  3000W Great Wall -> "PSU_3000W_GREAT_WALL"
  1600W Delta -> "PSU_1600W_DELTA"

PCIe Device

Формат: PCIE_{DEVICE_CLASS}_{MODEL_NORMALIZED} или PCIE_{DEVICE_CLASS}_{VENDOR_ID}_{DEVICE_ID}
Пример:
  Network Mellanox ConnectX-5 -> "PCIE_NETWORK_CONNECTX5"
  Storage Intel RAID -> "PCIE_STORAGE_INTEL_RAID"
  Unknown 32902:2912 -> "PCIE_STORAGE_32902_2912"

Правила нормализации

  1. Удаление специальных символов: (, ), -, ®, , пробелы заменяются на _
  2. Uppercase: все символы в верхнем регистре
  3. Множественные подчеркивания: заменяются на одно
  4. Префиксы: убираются общие префиксы типа MODEL:, PN:, etc.

Статусы компонентов

Возможные значения

  • OK - компонент работает нормально
  • Warning - есть предупреждения (degraded, warning threshold)
  • Critical - критическое состояние (failed, error)
  • Unknown - статус неизвестен или не поддерживается
  • Empty - слот пустой (только для memory, pcie_devices)

Обработка статусов

OK:

  • Нормальная обработка, никаких дополнительных действий

Warning:

  • Создать observation с флагом warning
  • Опционально: создать timeline event COMPONENT_WARNING

Critical:

  • Создать observation с флагом critical
  • Автоматически создать failure_event для этого компонента
  • Создать timeline event COMPONENT_FAILED

Unknown:

  • Сохранить как есть, считать компонент рабочим

Empty:

  • Не создавать component/observation для этого слота

Обработка отсутствующих полей

serial_number

CPU: генерируется как {board_serial}-CPU-{socket}

PCIe Device: генерируется как {board_serial}-PCIE-{slot} (если serial_number = "N/A" или пустой)

Другие компоненты: если serial_number отсутствует и не может быть сгенерирован - компонент игнорируется

manufacturer

Если vendor_id присутствует (PCIe): используется lookup таблица PCI vendors

  • 8086 -> Intel
  • 10de -> NVIDIA
  • 15b3 -> Mellanox
  • etc.

Если "NULL" или пустой: сохраняется как NULL в БД

status

Если отсутствует: считается Unknown

firmware

Если отсутствует: не создается FIRMWARE_CHANGED event


Примеры использования

Пример 1: Минимальный snapshot

{
  "collected_at": "2026-02-10T15:30:00Z",
  "target_host": "192.168.1.100",
  "hardware": {
    "board": {
      "serial_number": "TEST-SERVER-001"
    },
    "cpus": [
      {
        "socket": 0,
        "model": "Intel Xeon Gold 6530"
      }
    ],
    "memory": [],
    "storage": [],
    "pcie_devices": [],
    "power_supplies": []
  }
}

Пример 2: Server с историей "сломан -> починен"

{
  "collected_at": "2026-02-10T15:30:00Z",
  "target_host": "prod-db-01",
  "hardware": {
    "board": {
      "manufacturer": "Dell",
      "product_name": "PowerEdge R740",
      "serial_number": "CN7475162Q0123"
    },
    "storage": [
      {
        "slot": "Disk.Bay.0",
        "type": "SSD",
        "model": "Samsung PM1733",
        "serial_number": "S5GUNG0N123456",
        "firmware": "9CV10510",
        "interface": "NVMe",
        "present": true,
        "status": "OK",
        "status_changed_at": "2026-02-10T15:22:00Z",
        "status_at_collection": {
          "status": "OK",
          "at": "2026-02-10T15:30: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"
          }
        ]
      },
      {
        "slot": "Disk.Bay.1",
        "type": "SSD",
        "model": "Samsung PM1733",
        "serial_number": "S5GUNG0N123457",
        "firmware": "9CV10510",
        "interface": "NVMe",
        "present": true,
        "status": "OK"
      }
    ]
  }
}

Обработка:

  • Disk.Bay.0 получит текущий статус OK
  • История статусов сохранится в observations.details.status_history
  • Автоматический failure_event не создается, так как текущий статус snapshot не Critical

Пример 3: Замена памяти

Snapshot 1 (до замены):

{
  "collected_at": "2026-02-09T10:00:00Z",
  "target_host": "web-01",
  "hardware": {
    "board": {"serial_number": "SRV001"},
    "memory": [
      {
        "slot": "DIMM_A1",
        "serial_number": "OLD-DIMM-001",
        "present": true,
        "status": "OK"
      }
    ]
  }
}

Snapshot 2 (после замены):

{
  "collected_at": "2026-02-10T14:00:00Z",
  "target_host": "web-01",
  "hardware": {
    "board": {"serial_number": "SRV001"},
    "memory": [
      {
        "slot": "DIMM_A1",
        "serial_number": "NEW-DIMM-002",
        "present": true,
        "status": "OK"
      }
    ]
  }
}

Обработка:

  • Компонент OLD-DIMM-001: закрывается installation (removed_at = 2026-02-10T14:00:00Z), создается REMOVED event
  • Компонент NEW-DIMM-002: создается новый component, создается installation, создается INSTALLED event

Интеграция с существующим кодом

Текущий эндпоинт /ingest/logbundle уже реализует часть этой логики. Новый формат должен:

  1. Быть обратно совместимым - старый формат продолжает работать
  2. Использовать ту же инфраструктуру - LogBundle, Observations, Installations
  3. Расширить observation JSON - добавить поля status, slot, telemetry
  4. Добавить LOT автоопределение - новая функция в internal/ingest
  5. Добавить обработку статусов - автоматическое создание failure events

Предлагаемые изменения

Новый endpoint: POST /ingest/hardware (принимает новый формат)

Старый endpoint: POST /ingest/logbundle (остается без изменений)

Общая логика: оба endpoint используют общий ingest.Service с расширенной обработкой


Следующие шаги

  1. Реализовать парсер нового формата - internal/ingest/parser_hardware.go
  2. Добавить LOT автоопределение - internal/ingest/lot_classifier.go
  3. Расширить observation модель - добавить JSON поля для status, slot, etc.
  4. Реализовать обработку статусов - автосоздание failure events
  5. Добавить endpoint - POST /ingest/hardware
  6. Написать тесты - unit + integration тесты для нового формата
  7. Документировать API - OpenAPI спецификация