Add integration guide, example generator, and built binary
This commit is contained in:
992
docs/INTEGRATION_GUIDE.md
Normal file
992
docs/INTEGRATION_GUIDE.md
Normal file
@@ -0,0 +1,992 @@
|
||||
# Руководство по интеграции 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, обязательно) - структура с аппаратными компонентами
|
||||
|
||||
---
|
||||
|
||||
## Секция 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"
|
||||
},
|
||||
{
|
||||
"socket": 1,
|
||||
"model": "INTEL(R) XEON(R) GOLD 6530",
|
||||
"cores": 32,
|
||||
"threads": 64,
|
||||
"frequency_mhz": 2100,
|
||||
"max_frequency_mhz": 4000,
|
||||
"manufacturer": "Intel",
|
||||
"status": "OK"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Поля:**
|
||||
- `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`
|
||||
|
||||
**Генерация 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"
|
||||
},
|
||||
{
|
||||
"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`
|
||||
|
||||
**Обработка:**
|
||||
- Если `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`
|
||||
|
||||
**Обработка 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",
|
||||
"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`
|
||||
- `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"
|
||||
},
|
||||
{
|
||||
"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`
|
||||
|
||||
**Генерация 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": "Critical"
|
||||
},
|
||||
{
|
||||
"slot": "Disk.Bay.1",
|
||||
"type": "SSD",
|
||||
"model": "Samsung PM1733",
|
||||
"serial_number": "S5GUNG0N123457",
|
||||
"firmware": "9CV10510",
|
||||
"interface": "NVMe",
|
||||
"present": true,
|
||||
"status": "OK"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Обработка:**
|
||||
- Disk.Bay.0 получит статус Critical
|
||||
- Автоматически создастся failure_event для компонента S5GUNG0N123456
|
||||
- Timeline event COMPONENT_FAILED
|
||||
|
||||
### Пример 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 спецификация
|
||||
Reference in New Issue
Block a user