1047 lines
37 KiB
Markdown
1047 lines
37 KiB
Markdown
# Руководство по интеграции 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` ключи из этого руководства.
|
||
|
||
### Структура верхнего уровня
|
||
|
||
```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": {...},
|
||
"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.
|
||
|
||
```json
|
||
{
|
||
"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 (Процессоры)
|
||
|
||
**Назначение:** Информация о установленных процессорах.
|
||
|
||
```json
|
||
{
|
||
"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).
|
||
|
||
```json
|
||
{
|
||
"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).
|
||
|
||
```json
|
||
{
|
||
"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 (Блоки питания)
|
||
|
||
**Назначение:** Информация о блоках питания.
|
||
|
||
```json
|
||
{
|
||
"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.).
|
||
|
||
```json
|
||
{
|
||
"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.).
|
||
|
||
```json
|
||
{
|
||
"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
|
||
|
||
```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 для импорта
|
||
|
||
```http
|
||
POST /ingest/hardware
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"collected_at": "2026-02-10T15:30:00Z",
|
||
"target_host": "10.10.10.103",
|
||
"hardware": {...}
|
||
}
|
||
```
|
||
|
||
### Ответ при успехе (201 Created)
|
||
|
||
```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
|
||
}
|
||
}
|
||
```
|
||
|
||
### Ответ при дубликате (200 OK)
|
||
|
||
```json
|
||
{
|
||
"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)
|
||
|
||
```json
|
||
{
|
||
"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
|
||
|
||
```json
|
||
{
|
||
"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 с историей "сломан -> починен"
|
||
|
||
```json
|
||
{
|
||
"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 (до замены):**
|
||
```json
|
||
{
|
||
"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 (после замены):**
|
||
```json
|
||
{
|
||
"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 спецификация
|