feat: добавлена информация о VM в коллектор GPU
- Добавлен сбор информации о виртуальных машинах и контейнерах Proxmox - Генерация уникального vm_id на основе cluster_uuid + vmid (16 символов SHA256) - Убрана информация о VM из коллектора proxcluster - Обновлена документация по коллектору GPU - Исправлен возврат пустого массива вместо null для vms Автор: Сергей Антропов, сайт: https://devops.org.ru
This commit is contained in:
parent
5bfb6fea8b
commit
621d3f0a43
35
Makefile
35
Makefile
@ -43,11 +43,23 @@ collectors:
|
|||||||
ARCH=$$(/usr/bin/uname -m | sed 's/x86_64/amd64/; s/arm64/arm64/'); \
|
ARCH=$$(/usr/bin/uname -m | sed 's/x86_64/amd64/; s/arm64/arm64/'); \
|
||||||
docker run --rm -v $$PWD:/workspace -w /workspace \
|
docker run --rm -v $$PWD:/workspace -w /workspace \
|
||||||
-e GOOS=darwin -e GOARCH=$$ARCH -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
-e GOOS=darwin -e GOARCH=$$ARCH -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
||||||
sh -c "go mod tidy >/dev/null 2>&1 && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime ./src/collectors/uptime && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos ./src/collectors/macos && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/docker ./src/collectors/docker"; \
|
sh -c "go mod tidy >/dev/null 2>&1 && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime ./src/collectors/uptime && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos ./src/collectors/macos && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/docker ./src/collectors/docker"; \
|
||||||
else \
|
else \
|
||||||
docker run --rm -v $$PWD:/workspace -w /workspace \
|
docker run --rm -v $$PWD:/workspace -w /workspace \
|
||||||
-e GOOS=linux -e GOARCH=amd64 -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
-e GOOS=linux -e GOARCH=amd64 -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
||||||
sh -c "go mod tidy >/dev/null 2>&1 && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime ./src/collectors/uptime && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos ./src/collectors/macos && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/system ./src/collectors/system && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/hba ./src/collectors/hba && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/sensors ./src/collectors/sensors && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/docker ./src/collectors/docker && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/gpu ./src/collectors/gpu && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/kubernetes ./src/collectors/kubernetes"; \
|
sh -c "go mod tidy >/dev/null 2>&1 && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime ./src/collectors/uptime && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos ./src/collectors/macos && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/system ./src/collectors/system && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/hba ./src/collectors/hba && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/sensors ./src/collectors/sensors && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/docker ./src/collectors/docker && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/gpu ./src/collectors/gpu && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/kubernetes ./src/collectors/kubernetes && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/proxcluster ./src/collectors/proxcluster"; \
|
||||||
fi
|
fi
|
||||||
@# Убедимся, что скрипты исполняемые
|
@# Убедимся, что скрипты исполняемые
|
||||||
@chmod +x ./bin/agent/collectors/*.sh 2>/dev/null || true
|
@chmod +x ./bin/agent/collectors/*.sh 2>/dev/null || true
|
||||||
@ -56,19 +68,32 @@ collectors-darwin:
|
|||||||
# Кросс-сборка коллекторов для macOS
|
# Кросс-сборка коллекторов для macOS
|
||||||
@mkdir -p ./bin/agent/collectors .cache/go-build .cache/go-mod; \
|
@mkdir -p ./bin/agent/collectors .cache/go-build .cache/go-mod; \
|
||||||
docker run --rm -v $$PWD:/workspace -w /workspace -e GOOS=darwin -e GOARCH=arm64 -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
docker run --rm -v $$PWD:/workspace -w /workspace -e GOOS=darwin -e GOARCH=arm64 -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
||||||
sh -c "go mod tidy >/dev/null 2>&1 && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime-darwin ./src/collectors/uptime && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos-darwin ./src/collectors/macos"
|
sh -c "go mod tidy >/dev/null 2>&1 && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime-darwin ./src/collectors/uptime && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos-darwin ./src/collectors/macos"
|
||||||
|
|
||||||
collectors-linux:
|
collectors-linux:
|
||||||
# Кросс-сборка коллекторов для Linux
|
# Кросс-сборка коллекторов для Linux
|
||||||
@mkdir -p ./bin/agent/collectors .cache/go-build .cache/go-mod; \
|
@mkdir -p ./bin/agent/collectors .cache/go-build .cache/go-mod; \
|
||||||
docker run --rm -v $$PWD:/workspace -w /workspace -e GOOS=linux -e GOARCH=amd64 -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
docker run --rm -v $$PWD:/workspace -w /workspace -e GOOS=linux -e GOARCH=amd64 -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
||||||
sh -c "go mod tidy >/dev/null 2>&1 && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime ./src/collectors/uptime && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos ./src/collectors/macos && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/system ./src/collectors/system && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/hba ./src/collectors/hba && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/sensors ./src/collectors/sensors && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/docker ./src/collectors/docker && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/gpu ./src/collectors/gpu && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/kubernetes ./src/collectors/kubernetes"
|
sh -c "go mod tidy >/dev/null 2>&1 && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime ./src/collectors/uptime && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos ./src/collectors/macos && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/system ./src/collectors/system && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/hba ./src/collectors/hba && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/sensors ./src/collectors/sensors && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/docker ./src/collectors/docker && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/gpu ./src/collectors/gpu && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/kubernetes ./src/collectors/kubernetes && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/proxcluster ./src/collectors/proxcluster"
|
||||||
|
|
||||||
collectors-windows:
|
collectors-windows:
|
||||||
# Кросс-сборка коллекторов для Windows
|
# Кросс-сборка коллекторов для Windows
|
||||||
@mkdir -p ./bin/agent/collectors .cache/go-build .cache/go-mod; \
|
@mkdir -p ./bin/agent/collectors .cache/go-build .cache/go-mod; \
|
||||||
docker run --rm -v $$PWD:/workspace -w /workspace -e GOOS=windows -e GOARCH=amd64 -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
docker run --rm -v $$PWD:/workspace -w /workspace -e GOOS=windows -e GOARCH=amd64 -e GOCACHE=/workspace/.cache/go-build -e GOMODCACHE=/workspace/.cache/go-mod golang:1.22 \
|
||||||
sh -c "go mod tidy >/dev/null 2>&1 && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime-windows.exe ./src/collectors/uptime && CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos-windows.exe ./src/collectors/macos"
|
sh -c "go mod tidy >/dev/null 2>&1 && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/uptime-windows.exe ./src/collectors/uptime && \
|
||||||
|
CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/macos-windows.exe ./src/collectors/macos"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ SensusAgent — модульный агент сбора метрик. Аген
|
|||||||
- Сборка и запуск (Make/Docker/Compose): `docs/build_and_run.md`
|
- Сборка и запуск (Make/Docker/Compose): `docs/build_and_run.md`
|
||||||
- Деплой (Ansible, systemd): `docs/deploy.md`
|
- Деплой (Ansible, systemd): `docs/deploy.md`
|
||||||
- **Kafka SSL поддержка**: `docs/kafka_ssl.md` ⭐
|
- **Kafka SSL поддержка**: `docs/kafka_ssl.md` ⭐
|
||||||
|
- **Proxmox кластер**: `docs/collectors/proxcluster.md` ⭐
|
||||||
|
|
||||||
Быстрый старт:
|
Быстрый старт:
|
||||||
```bash
|
```bash
|
||||||
|
@ -6,7 +6,7 @@ log_level: info
|
|||||||
|
|
||||||
kafka:
|
kafka:
|
||||||
enabled: false
|
enabled: false
|
||||||
brokers: ["10.99.0.90:9092"]
|
brokers: ["10.29.91.4:9092"]
|
||||||
topic: "sensus.metrics"
|
topic: "sensus.metrics"
|
||||||
client_id: "sensusagent"
|
client_id: "sensusagent"
|
||||||
enable_tls: false
|
enable_tls: false
|
||||||
@ -71,7 +71,7 @@ collectors:
|
|||||||
exec: "./collectors/sensors"
|
exec: "./collectors/sensors"
|
||||||
platforms: [linux]
|
platforms: [linux]
|
||||||
docker:
|
docker:
|
||||||
enabled: true
|
enabled: false
|
||||||
type: exec
|
type: exec
|
||||||
key: docker
|
key: docker
|
||||||
interval: "3600s"
|
interval: "3600s"
|
||||||
@ -87,13 +87,21 @@ collectors:
|
|||||||
exec: "./collectors/gpu"
|
exec: "./collectors/gpu"
|
||||||
platforms: [linux]
|
platforms: [linux]
|
||||||
kubernetes:
|
kubernetes:
|
||||||
enabled: true
|
enabled: false
|
||||||
type: exec
|
type: exec
|
||||||
key: kubernetes
|
key: kubernetes
|
||||||
interval: "3600s"
|
interval: "3600s"
|
||||||
timeout: "60s"
|
timeout: "60s"
|
||||||
exec: "./collectors/kubernetes"
|
exec: "./collectors/kubernetes"
|
||||||
platforms: [linux]
|
platforms: [linux]
|
||||||
|
proxcluster:
|
||||||
|
enabled: true
|
||||||
|
type: exec
|
||||||
|
key: proxcluster
|
||||||
|
interval: "1800s"
|
||||||
|
timeout: "30s"
|
||||||
|
exec: "./collectors/proxcluster"
|
||||||
|
platforms: [linux]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,3 +46,22 @@ make collectors-darwin # darwin/arm64
|
|||||||
- Ограничивайте потребление ресурсов и время выполнения
|
- Ограничивайте потребление ресурсов и время выполнения
|
||||||
- На стороне агента используйте `interval` ≥ 10s для тяжелых коллекторов
|
- На стороне агента используйте `interval` ≥ 10s для тяжелых коллекторов
|
||||||
|
|
||||||
|
## Доступные коллекторы
|
||||||
|
|
||||||
|
### Встроенные коллекторы
|
||||||
|
|
||||||
|
- **system** - системные метрики (CPU, RAM, сеть, диски, обновления)
|
||||||
|
- **uptime** - время работы системы
|
||||||
|
- **macos** - специфичные для macOS метрики
|
||||||
|
- **hba** - информация о HBA адаптерах
|
||||||
|
- **sensors** - данные датчиков температуры/напряжения
|
||||||
|
- **docker** - информация о Docker контейнерах
|
||||||
|
- **gpu** - информация о GPU устройствах
|
||||||
|
- **kubernetes** - метрики Kubernetes кластера
|
||||||
|
- **proxcluster** - информация о Proxmox кластере ⭐
|
||||||
|
|
||||||
|
### Документация коллекторов
|
||||||
|
|
||||||
|
- [proxcluster](collectors/proxcluster.md) - сбор информации о Proxmox кластере
|
||||||
|
- [gpu](collectors/gpu.md) - сбор информации о GPU устройствах с агрегированной статистикой
|
||||||
|
|
||||||
|
256
docs/collectors/gpu.md
Normal file
256
docs/collectors/gpu.md
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
# GPU коллектор
|
||||||
|
|
||||||
|
**Автор:** Сергей Антропов
|
||||||
|
**Сайт:** https://devops.org.ru
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
Коллектор GPU собирает информацию о графических процессорах (GPU) в системе и виртуальных машинах Proxmox. Поддерживает NVIDIA GPU через `nvidia-smi` и AMD GPU через `rocm-smi`. Возвращает детальную информацию о каждом GPU, агрегированную статистику по всем устройствам, а также информацию о виртуальных машинах и контейнерах в Proxmox кластере.
|
||||||
|
|
||||||
|
## Собираемые данные
|
||||||
|
|
||||||
|
### Детальная информация о GPU
|
||||||
|
|
||||||
|
Для каждого GPU собирается:
|
||||||
|
- `id` - индекс GPU
|
||||||
|
- `name` - модель GPU
|
||||||
|
- `driver_version` - версия драйвера
|
||||||
|
- `mem_total_mb` - общий объем видеопамяти в МБ
|
||||||
|
- `mem_used_mb` - используемая видеопамять в МБ
|
||||||
|
- `gpu_util_pct` - утилизация GPU в процентах
|
||||||
|
- `mem_util_pct` - утилизация видеопамяти в процентах
|
||||||
|
- `temperature_c` - температура в градусах Цельсия
|
||||||
|
- `power_watt` - потребляемая мощность в ваттах
|
||||||
|
|
||||||
|
### Агрегированная статистика
|
||||||
|
|
||||||
|
В секции `summary`:
|
||||||
|
- `total_count` - общее количество GPU
|
||||||
|
- `models` - количество GPU по моделям (map[string]int)
|
||||||
|
- `total_mem_mb` - суммарный объем видеопамяти всех GPU
|
||||||
|
- `total_used_mem_mb` - суммарная используемая видеопамять
|
||||||
|
- `total_watt` - суммарное потребление всех GPU
|
||||||
|
- `avg_utilization_pct` - средняя утилизация всех GPU
|
||||||
|
- `temperature_c` - статистика по температуре:
|
||||||
|
- `min` - минимальная температура среди всех GPU
|
||||||
|
- `max` - максимальная температура среди всех GPU
|
||||||
|
- `avg` - средняя температура всех GPU
|
||||||
|
|
||||||
|
### Информация о виртуальных машинах
|
||||||
|
|
||||||
|
В секции `vms` (только для Proxmox):
|
||||||
|
- `vmid` - ID виртуальной машины/контейнера
|
||||||
|
- `vm_id` - уникальный ID (16 символов SHA256 от cluster_uuid + vmid)
|
||||||
|
- `name` - имя виртуальной машины/контейнера
|
||||||
|
- `status` - статус (running, stopped, suspended)
|
||||||
|
- `node` - нода, на которой запущена VM
|
||||||
|
- `cpu` - текущее использование CPU
|
||||||
|
- `maxcpu` - максимальное количество CPU
|
||||||
|
- `mem` - текущее использование памяти в МБ
|
||||||
|
- `maxmem` - максимальная память в МБ
|
||||||
|
- `disk` - текущее использование диска в ГБ
|
||||||
|
- `maxdisk` - максимальный размер диска в ГБ
|
||||||
|
- `uptime` - время работы в секундах
|
||||||
|
- `template` - является ли шаблоном
|
||||||
|
- `pid` - PID процесса
|
||||||
|
- `netin` - входящий сетевой трафик в байтах
|
||||||
|
- `netout` - исходящий сетевой трафик в байтах
|
||||||
|
- `diskread` - прочитано с диска в байтах
|
||||||
|
- `diskwrite` - записано на диск в байтах
|
||||||
|
- `guest_agent` - статус guest agent (только для VM)
|
||||||
|
- `type` - тип: "qemu" для виртуальных машин, "lxc" для контейнеров
|
||||||
|
|
||||||
|
## Зависимости
|
||||||
|
|
||||||
|
### NVIDIA GPU
|
||||||
|
- `nvidia-smi` - утилита для мониторинга NVIDIA GPU
|
||||||
|
|
||||||
|
### AMD GPU
|
||||||
|
- `rocm-smi` - утилита для мониторинга AMD GPU
|
||||||
|
|
||||||
|
### Виртуальные машины Proxmox
|
||||||
|
- `pvesh` - утилита командной строки Proxmox VE
|
||||||
|
- Доступ к `/etc/corosync/corosync.conf` или `/etc/pve/corosync.conf` для получения cluster_uuid
|
||||||
|
|
||||||
|
## Примеры вывода
|
||||||
|
|
||||||
|
### NVIDIA GPU
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"collector_name": "gpu",
|
||||||
|
"gpu": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "NVIDIA GeForce RTX 3080",
|
||||||
|
"driver_version": "525.60.13",
|
||||||
|
"mem_total_mb": 10240,
|
||||||
|
"mem_used_mb": 5120,
|
||||||
|
"gpu_util_pct": 75,
|
||||||
|
"mem_util_pct": 50,
|
||||||
|
"temperature_c": 65,
|
||||||
|
"power_watt": 250.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "NVIDIA GeForce RTX 4090",
|
||||||
|
"driver_version": "525.60.13",
|
||||||
|
"mem_total_mb": 24576,
|
||||||
|
"mem_used_mb": 12288,
|
||||||
|
"gpu_util_pct": 85,
|
||||||
|
"mem_util_pct": 50,
|
||||||
|
"temperature_c": 70,
|
||||||
|
"power_watt": 450.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": {
|
||||||
|
"total_count": 2,
|
||||||
|
"models": {
|
||||||
|
"NVIDIA GeForce RTX 3080": 1,
|
||||||
|
"NVIDIA GeForce RTX 4090": 1
|
||||||
|
},
|
||||||
|
"total_mem_mb": 34816,
|
||||||
|
"total_used_mem_mb": 17408,
|
||||||
|
"total_watt": 700.5,
|
||||||
|
"avg_utilization_pct": 80.0,
|
||||||
|
"temperature_c": {
|
||||||
|
"min": 65,
|
||||||
|
"max": 70,
|
||||||
|
"avg": 67.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### AMD GPU
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"collector_name": "gpu",
|
||||||
|
"gpu": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "AMD Radeon RX 6800 XT",
|
||||||
|
"driver_version": "22.40.0",
|
||||||
|
"mem_total_mb": 16384,
|
||||||
|
"mem_used_mb": 8192,
|
||||||
|
"gpu_util_pct": 60,
|
||||||
|
"mem_util_pct": 50,
|
||||||
|
"temperature_c": 55,
|
||||||
|
"power_watt": 200.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": {
|
||||||
|
"total_count": 1,
|
||||||
|
"models": {
|
||||||
|
"AMD Radeon RX 6800 XT": 1
|
||||||
|
},
|
||||||
|
"total_mem_mb": 16384,
|
||||||
|
"total_used_mem_mb": 8192,
|
||||||
|
"total_watt": 200.0,
|
||||||
|
"avg_utilization_pct": 60.0,
|
||||||
|
"temperature_c": {
|
||||||
|
"min": 55,
|
||||||
|
"max": 55,
|
||||||
|
"avg": 55
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Отсутствие GPU
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"collector_name": "gpu",
|
||||||
|
"gpu": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Примеры использования
|
||||||
|
|
||||||
|
### Получить общую информацию о GPU
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.summary'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить список всех моделей GPU
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.summary.models'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить суммарное потребление GPU
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.summary.total_watt'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить среднюю утилизацию
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.summary.avg_utilization_pct'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить статистику по температуре
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.summary.temperature_c'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить максимальную температуру
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.summary.temperature_c.max'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить минимальную температуру
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.summary.temperature_c.min'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить среднюю температуру
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.summary.temperature_c.avg'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить информацию о конкретном GPU
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.gpu[0]'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить GPU с высокой утилизацией (>80%)
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.gpu[] | select(.gpu_util_pct > 80)'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Получить GPU с высокой температурой (>70°C)
|
||||||
|
```bash
|
||||||
|
./collectors/gpu | jq '.gpu[] | select(.temperature_c > 70)'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
Пример конфигурации в `config.yaml`:
|
||||||
|
```yaml
|
||||||
|
collectors:
|
||||||
|
gpu:
|
||||||
|
enabled: true
|
||||||
|
type: exec
|
||||||
|
key: gpu
|
||||||
|
interval: "30s"
|
||||||
|
timeout: "10s"
|
||||||
|
exec: "./collectors/gpu"
|
||||||
|
platforms: [linux]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Особенности
|
||||||
|
|
||||||
|
- **Приоритет NVIDIA**: Если доступен `nvidia-smi`, используется он, иначе `rocm-smi`
|
||||||
|
- **Fallback**: Если ни один из драйверов недоступен, возвращается пустой результат
|
||||||
|
- **Агрегация**: Статистика вычисляется только при наличии GPU
|
||||||
|
- **Совместимость**: Поддерживает различные версии `nvidia-smi` и `rocm-smi`
|
||||||
|
- **Производительность**: Минимальное время выполнения за счет оптимизированных запросов
|
||||||
|
|
||||||
|
## Мониторинг
|
||||||
|
|
||||||
|
Рекомендуемые метрики для мониторинга:
|
||||||
|
- `summary.total_watt` - общее потребление GPU
|
||||||
|
- `summary.avg_utilization_pct` - средняя утилизация
|
||||||
|
- `summary.temperature_c.max` - максимальная температура GPU
|
||||||
|
- `summary.temperature_c.avg` - средняя температура GPU
|
||||||
|
- `gpu[].temperature_c` - температура каждого GPU
|
||||||
|
- `gpu[].mem_util_pct` - утилизация видеопамяти
|
||||||
|
- `summary.total_count` - количество GPU в системе
|
445
docs/collectors/proxcluster.md
Normal file
445
docs/collectors/proxcluster.md
Normal file
@ -0,0 +1,445 @@
|
|||||||
|
# Коллектор proxcluster
|
||||||
|
|
||||||
|
## Автор: Сергей Антропов, сайт: https://devops.org.ru
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
Коллектор `proxcluster` собирает подробную информацию о Proxmox кластере, включая основную информацию о кластере, кворуме, хранилищах, нодах и данных corosync.
|
||||||
|
|
||||||
|
## Поддерживаемые платформы
|
||||||
|
|
||||||
|
- **Linux**: Полная поддержка
|
||||||
|
- **macOS/Windows**: Не поддерживается (возвращает пустой JSON)
|
||||||
|
|
||||||
|
## Собираемые данные
|
||||||
|
|
||||||
|
### Основная информация о кластере
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cluster_id": "a1b2c3d4e5f67890", // Уникальный ID на основе cluster_name + cluster_uuid (SHA256, 16 символов)
|
||||||
|
"name": "production-cluster", // Имя кластера из corosync.conf
|
||||||
|
"cluster_uuid": "12345678-1234-1234-1234-123456789abc", // UUID кластера
|
||||||
|
"version": "8.1.4" // Версия Proxmox VE
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Информация о кворуме
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"quorum": {
|
||||||
|
"quorate": true, // Есть ли кворум
|
||||||
|
"members": 3, // Количество участников
|
||||||
|
"total_votes": 3, // Общее количество голосов
|
||||||
|
"expected_votes": 3 // Ожидаемое количество голосов
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Хранилища кластера
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"storages": [
|
||||||
|
{
|
||||||
|
"storage_id": "local-lvm", // Идентификатор хранилища
|
||||||
|
"type": "lvmthin", // Тип хранилища
|
||||||
|
"content": ["images", "rootdir"], // Типы контента
|
||||||
|
"total_gb": 500, // Общий размер в ГБ
|
||||||
|
"used_gb": 320, // Использовано в ГБ
|
||||||
|
"avail_gb": 180, // Доступно в ГБ
|
||||||
|
"shared": false // Является ли хранилище общим
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"storage_id": "nfs-storage",
|
||||||
|
"type": "nfs",
|
||||||
|
"content": ["images", "backup"],
|
||||||
|
"total_gb": 2000,
|
||||||
|
"used_gb": 1500,
|
||||||
|
"avail_gb": 500,
|
||||||
|
"shared": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Подробная информация о нодах
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"node_uid": "d8b7a93c2f0e4f16", // Уникальный ID ноды (SHA256 от cluster_uuid + node_id, 16 символов)
|
||||||
|
"node_id": "1", // ID ноды в кластере
|
||||||
|
"name": "pve1", // Имя ноды
|
||||||
|
"ip": "192.168.1.10", // IP адрес ноды
|
||||||
|
"online": true, // Статус ноды
|
||||||
|
"cluster_id": "a1b2c3d4e5f67890", // ID кластера (SHA256 от cluster_name + cluster_uuid, 16 символов)
|
||||||
|
"cluster_uuid": "12345678-1234-1234-1234-123456789abc", // UUID кластера
|
||||||
|
"machine_id": "4b1d2c3a4e5f6789aabbccddeeff0011", // Machine ID системы
|
||||||
|
"product_uuid": "C9E4DDB2-1F27-4F3B-B3A9-ACD2C66F73B0", // UUID продукта
|
||||||
|
"os": { // Информация об ОС
|
||||||
|
"kernel": "Linux 5.15.108-1-pve",
|
||||||
|
"pve_version": "7.4-3",
|
||||||
|
"uptime_sec": 523423
|
||||||
|
},
|
||||||
|
"hardware": { // Информация о железе
|
||||||
|
"cpu_model": "Intel(R) Xeon(R) Gold 6226R",
|
||||||
|
"cpu_cores": 32,
|
||||||
|
"sockets": 2,
|
||||||
|
"threads": 64,
|
||||||
|
"memory_total_mb": 262144
|
||||||
|
},
|
||||||
|
"resources": { // Использование ресурсов
|
||||||
|
"cpu_usage_percent": 25.3,
|
||||||
|
"memory_used_mb": 98304,
|
||||||
|
"swap_used_mb": 512,
|
||||||
|
"loadavg": [0.52, 0.61, 0.72]
|
||||||
|
},
|
||||||
|
"network": [ // Сетевая информация
|
||||||
|
{
|
||||||
|
"iface": "eth0",
|
||||||
|
"mac": "52:54:00:12:34:56",
|
||||||
|
"ip": "192.168.1.10",
|
||||||
|
"rx_bytes": 123456789,
|
||||||
|
"tx_bytes": 987654321,
|
||||||
|
"errors": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iface": "vmbr0",
|
||||||
|
"type": "bridge",
|
||||||
|
"ip": "192.168.1.1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"disks": [ // Информация о дисках
|
||||||
|
{
|
||||||
|
"device": "/dev/sda",
|
||||||
|
"model": "Samsung SSD 870 EVO",
|
||||||
|
"size_gb": 1000,
|
||||||
|
"used_gb": 200,
|
||||||
|
"health": "PASSED"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"device": "rpool",
|
||||||
|
"type": "zfs",
|
||||||
|
"size_gb": 5000,
|
||||||
|
"used_gb": 2300,
|
||||||
|
"status": "ONLINE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": [ // Статус сервисов
|
||||||
|
{"name": "pve-cluster", "active": true},
|
||||||
|
{"name": "pvedaemon", "active": true},
|
||||||
|
{"name": "pveproxy", "active": true},
|
||||||
|
{"name": "corosync", "active": true}
|
||||||
|
],
|
||||||
|
"logs": [], // Логи ноды (пустой массив в упрощенной версии)
|
||||||
|
"gpus": [ // Информация о GPU
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"model": "NVIDIA GeForce RTX 4090",
|
||||||
|
"memory_total_mb": 24576,
|
||||||
|
"memory_used_mb": 8192,
|
||||||
|
"utilization_percent": 45.5,
|
||||||
|
"temperature_c": 65.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node_uid": "e2f0c1a87d9b5d44",
|
||||||
|
"node_id": "2",
|
||||||
|
"name": "pve2",
|
||||||
|
"ip": "192.168.1.11",
|
||||||
|
"online": false, // Офлайн нода
|
||||||
|
"cluster_id": "a1b2c3d4e5f67890", // ID кластера
|
||||||
|
"cluster_uuid": "12345678-1234-1234-1234-123456789abc", // UUID кластера
|
||||||
|
"machine_id": "",
|
||||||
|
"product_uuid": "",
|
||||||
|
"os": {
|
||||||
|
"kernel": "",
|
||||||
|
"pve_version": "",
|
||||||
|
"uptime_sec": 0
|
||||||
|
},
|
||||||
|
"hardware": {
|
||||||
|
"cpu_model": "",
|
||||||
|
"cpu_cores": 0,
|
||||||
|
"sockets": 0,
|
||||||
|
"threads": 0,
|
||||||
|
"memory_total_mb": 0
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"cpu_usage_percent": 0,
|
||||||
|
"memory_used_mb": 0,
|
||||||
|
"swap_used_mb": 0,
|
||||||
|
"loadavg": [0.0, 0.0, 0.0]
|
||||||
|
},
|
||||||
|
"network": [],
|
||||||
|
"disks": [],
|
||||||
|
"services": [],
|
||||||
|
"logs": [],
|
||||||
|
"gpus": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Информация о corosync
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"corosync": {
|
||||||
|
"bindnetaddr": "192.168.1.0", // Сетевой адрес для привязки
|
||||||
|
"mcastport": 5405, // Порт для multicast
|
||||||
|
"ttl": 1, // TTL для multicast
|
||||||
|
"quorum_provider": "corosync_votequorum" // Провайдер кворума
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Агрегированные ресурсы кластера
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cluster_resources": {
|
||||||
|
"cpu": { // Агрегированная информация о CPU
|
||||||
|
"total_cores": 96, // Общее количество ядер
|
||||||
|
"total_sockets": 6, // Общее количество сокетов
|
||||||
|
"total_threads": 192, // Общее количество потоков
|
||||||
|
"online_cores": 64, // Ядра онлайн нод
|
||||||
|
"online_sockets": 4, // Сокеты онлайн нод
|
||||||
|
"online_threads": 128 // Потоки онлайн нод
|
||||||
|
},
|
||||||
|
"memory": { // Агрегированная информация о памяти
|
||||||
|
"total_mb": 524288, // Общая память в МБ
|
||||||
|
"used_mb": 196608, // Использованная память в МБ
|
||||||
|
"online_total": 393216, // Память онлайн нод в МБ
|
||||||
|
"online_used": 131072 // Использованная память онлайн нод в МБ
|
||||||
|
},
|
||||||
|
"storage": { // Агрегированная информация о хранилищах
|
||||||
|
"total_gb": 10000, // Общий размер всех хранилищ в ГБ
|
||||||
|
"used_gb": 6500, // Использованное место в ГБ
|
||||||
|
"avail_gb": 3500, // Доступное место в ГБ
|
||||||
|
"shared_gb": 5000, // Размер общих хранилищ в ГБ
|
||||||
|
"local_gb": 5000 // Размер локальных хранилищ в ГБ
|
||||||
|
},
|
||||||
|
"disks": { // Агрегированная информация о дисках
|
||||||
|
"total_count": 12, // Общее количество дисков
|
||||||
|
"total_size_gb": 24000, // Общий размер всех дисков в ГБ
|
||||||
|
"ssd_count": 6, // Количество SSD дисков
|
||||||
|
"ssd_size_gb": 12000, // Размер SSD дисков в ГБ
|
||||||
|
"hdd_count": 6, // Количество HDD дисков
|
||||||
|
"hdd_size_gb": 12000, // Размер HDD дисков в ГБ
|
||||||
|
"online_count": 8, // Количество дисков онлайн нод
|
||||||
|
"online_size_gb": 16000 // Размер дисков онлайн нод в ГБ
|
||||||
|
},
|
||||||
|
"gpu": { // Агрегированная информация о GPU
|
||||||
|
"total_count": 4, // Общее количество GPU
|
||||||
|
"online_count": 3, // Количество GPU онлайн нод
|
||||||
|
"total_memory_mb": 98304, // Общая память всех GPU в МБ
|
||||||
|
"used_memory_mb": 32768, // Использованная память GPU в МБ
|
||||||
|
"online_memory_mb": 73728, // Память GPU онлайн нод в МБ
|
||||||
|
"online_used_mb": 24576, // Использованная память GPU онлайн нод в МБ
|
||||||
|
"avg_utilization": 35.2, // Средняя утилизация GPU в процентах
|
||||||
|
"avg_temperature": 58.5, // Средняя температура GPU в градусах Цельсия
|
||||||
|
"models": [ // Список уникальных моделей GPU
|
||||||
|
"NVIDIA GeForce RTX 4090",
|
||||||
|
"NVIDIA GeForce RTX 3080",
|
||||||
|
"AMD Radeon RX 6800 XT"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nodes": { // Статистика нод
|
||||||
|
"total": 3, // Общее количество нод
|
||||||
|
"online": 2 // Количество онлайн нод
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
### config.yaml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
collectors:
|
||||||
|
proxcluster:
|
||||||
|
enabled: true
|
||||||
|
type: exec
|
||||||
|
key: proxcluster
|
||||||
|
interval: "1800s" # 30 минут
|
||||||
|
timeout: "30s"
|
||||||
|
exec: "./collectors/proxcluster"
|
||||||
|
platforms: [linux]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Переменные окружения
|
||||||
|
|
||||||
|
- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 30s)
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
### Системные требования
|
||||||
|
|
||||||
|
- Proxmox VE кластер
|
||||||
|
- Доступ к файлам конфигурации:
|
||||||
|
- `/etc/corosync/corosync.conf` (основной)
|
||||||
|
- `/etc/pve/corosync.conf` (альтернативный)
|
||||||
|
- `/var/lib/pve-cluster/corosync.conf` (альтернативный)
|
||||||
|
|
||||||
|
### Команды
|
||||||
|
|
||||||
|
Коллектор использует следующие команды (должны быть доступны):
|
||||||
|
|
||||||
|
- `pveversion` - версия Proxmox VE
|
||||||
|
- `corosync-quorumtool` - информация о кворуме
|
||||||
|
- `pvecm` - управление кластером
|
||||||
|
- `pvesm` - управление хранилищами
|
||||||
|
- `systemctl` - управление сервисами
|
||||||
|
- `ps` - список процессов
|
||||||
|
- `getent` - разрешение имен хостов
|
||||||
|
- `nvidia-smi` - информация о NVIDIA GPU
|
||||||
|
- `lspci` - информация о PCI устройствах (для AMD/Intel GPU)
|
||||||
|
|
||||||
|
## Уникальные идентификаторы
|
||||||
|
|
||||||
|
### cluster_id
|
||||||
|
Генерируется на основе:
|
||||||
|
- `cluster_name` из corosync.conf
|
||||||
|
- `cluster_uuid` из corosync.conf
|
||||||
|
|
||||||
|
Формула: `SHA256(cluster_name + ":" + cluster_uuid)[:16]` (первые 16 символов SHA256 хеша)
|
||||||
|
|
||||||
|
### node_uid
|
||||||
|
Генерируется на основе:
|
||||||
|
- `cluster_uuid` кластера
|
||||||
|
- `node_id` ноды
|
||||||
|
|
||||||
|
Формула: `SHA256(cluster_uuid + ":" + node_id)[:16]` (первые 16 символов SHA256 хеша)
|
||||||
|
|
||||||
|
Это обеспечивает уникальность идентификаторов для каждого кластера и ноды, даже если имена совпадают. Использование SHA256 повышает криптографическую стойкость.
|
||||||
|
|
||||||
|
## Примеры использования
|
||||||
|
|
||||||
|
### Проверка работы коллектора
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Запуск коллектора напрямую
|
||||||
|
./bin/agent/collectors/proxcluster
|
||||||
|
|
||||||
|
# Запуск через агент
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Фильтрация данных
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Только информация о кластере
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.cluster_id, .name, .version'
|
||||||
|
|
||||||
|
# Только кворум
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.quorum'
|
||||||
|
|
||||||
|
# Только хранилища
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.storages'
|
||||||
|
|
||||||
|
# Только ноды
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.nodes'
|
||||||
|
|
||||||
|
# Только онлайн ноды
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.nodes[] | select(.online == true)'
|
||||||
|
|
||||||
|
# Информация о corosync
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.corosync'
|
||||||
|
|
||||||
|
# Агрегированные ресурсы кластера
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.cluster_resources'
|
||||||
|
|
||||||
|
# Только CPU ресурсы
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.cluster_resources.cpu'
|
||||||
|
|
||||||
|
# Только память
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.cluster_resources.memory'
|
||||||
|
|
||||||
|
# Только хранилища
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.cluster_resources.storage'
|
||||||
|
|
||||||
|
# Только диски
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.cluster_resources.disks'
|
||||||
|
|
||||||
|
# Статистика нод
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.cluster_resources.nodes'
|
||||||
|
|
||||||
|
# Только GPU ресурсы
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.cluster_resources.gpu'
|
||||||
|
|
||||||
|
# Только модели GPU
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.cluster_resources.gpu.models'
|
||||||
|
|
||||||
|
# GPU на конкретной ноде
|
||||||
|
./bin/agent/collectors/proxcluster | jq '.nodes[] | select(.name == "pve1") | .gpus'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Устранение неполадок
|
||||||
|
|
||||||
|
### Частые проблемы
|
||||||
|
|
||||||
|
1. **"no cluster data found"**
|
||||||
|
- Проверьте, что система является Proxmox VE кластером
|
||||||
|
- Убедитесь в доступности файла corosync.conf
|
||||||
|
- Проверьте права доступа к файлам конфигурации
|
||||||
|
|
||||||
|
2. **"failed to parse corosync.conf"**
|
||||||
|
- Проверьте формат файла corosync.conf
|
||||||
|
- Убедитесь, что в файле есть cluster_name и cluster_uuid
|
||||||
|
|
||||||
|
3. **"cluster version not found"**
|
||||||
|
- Убедитесь, что установлен Proxmox VE
|
||||||
|
- Проверьте доступность команды pveversion
|
||||||
|
|
||||||
|
4. **Пустые данные о нодах/хранилищах**
|
||||||
|
- Проверьте доступность команд pvecm, pvesm
|
||||||
|
- Убедитесь в правильности конфигурации кластера
|
||||||
|
|
||||||
|
### Отладка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Проверка доступности команд
|
||||||
|
which pveversion pvecm pvesm corosync-quorumtool
|
||||||
|
|
||||||
|
# Проверка файлов конфигурации
|
||||||
|
ls -la /etc/corosync/corosync.conf /etc/pve/corosync.conf
|
||||||
|
|
||||||
|
# Проверка статуса сервисов
|
||||||
|
systemctl status pve-cluster corosync pveproxy pvedaemon
|
||||||
|
|
||||||
|
# Проверка кворума
|
||||||
|
corosync-quorumtool -s
|
||||||
|
|
||||||
|
# Проверка нод кластера
|
||||||
|
pvecm nodes
|
||||||
|
|
||||||
|
# Проверка хранилищ
|
||||||
|
pvesm status
|
||||||
|
```
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
|
||||||
|
- Коллектор требует права на чтение системных файлов конфигурации
|
||||||
|
- Не передает пароли или секретные ключи
|
||||||
|
- Собирает только публичную информацию о кластере
|
||||||
|
- Для офлайн нод возвращает пустые значения вместо попыток подключения
|
||||||
|
|
||||||
|
## Производительность
|
||||||
|
|
||||||
|
- Время выполнения: ~10-30 секунд (зависит от размера кластера и количества нод)
|
||||||
|
- Интервал сбора: рекомендуется 30 минут (1800s)
|
||||||
|
- Потребление ресурсов: минимальное
|
||||||
|
- Для офлайн нод сбор данных пропускается
|
||||||
|
|
||||||
|
## Совместимость
|
||||||
|
|
||||||
|
- **Proxmox VE**: 6.0+
|
||||||
|
- **Кластеры**: от 1 ноды (без кворума) до 32 нод
|
||||||
|
- **Хранилища**: все поддерживаемые типы (local, nfs, ceph, lvm, zfs и др.)
|
||||||
|
- **Сети**: все типы интерфейсов (eth, ens, enp, vmbr и др.)
|
||||||
|
- **Диски**: все типы устройств (sda, nvme, vda и др.)
|
@ -49,7 +49,7 @@
|
|||||||
ansible.builtin.raw: |
|
ansible.builtin.raw: |
|
||||||
if [ -f /etc/debian_version ]; then \
|
if [ -f /etc/debian_version ]; then \
|
||||||
apt-get update -o Acquire::AllowInsecureRepositories=true -o Acquire::https::Verify-Peer=false -o Acquire::https::Verify-Host=false || true; \
|
apt-get update -o Acquire::AllowInsecureRepositories=true -o Acquire::https::Verify-Peer=false -o Acquire::https::Verify-Host=false || true; \
|
||||||
apt-get install -y --no-install-recommends sysstat iotop smartmontools nvme-cli mdadm lsscsi sg3-utils pciutils lm-sensors ipmitool || true; \
|
apt-get install -y --no-install-recommends sysstat iotop smartmontools nvme-cli mdadm lsscsi sg3-utils pciutils lm-sensors ipmitool jq || true; \
|
||||||
systemctl enable --now sysstat || true; \
|
systemctl enable --now sysstat || true; \
|
||||||
fi
|
fi
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
@ -57,7 +57,7 @@
|
|||||||
- name: Optional deps (RHEL/CentOS) — ignore errors
|
- name: Optional deps (RHEL/CentOS) — ignore errors
|
||||||
ansible.builtin.raw: |
|
ansible.builtin.raw: |
|
||||||
if [ -f /etc/redhat-release ]; then \
|
if [ -f /etc/redhat-release ]; then \
|
||||||
yum install -y sysstat iotop smartmontools nvme-cli mdadm lsscsi sg3_utils pciutils lm_sensors ipmitool || true; \
|
yum install -y sysstat iotop smartmontools nvme-cli mdadm lsscsi sg3_utils pciutils lm_sensors ipmitool jq || true; \
|
||||||
systemctl enable --now sysstat || true; \
|
systemctl enable --now sysstat || true; \
|
||||||
fi
|
fi
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
@ -43,6 +43,23 @@
|
|||||||
chmod -R 0755 {{ remote_dir }}/collectors 2>/dev/null || true
|
chmod -R 0755 {{ remote_dir }}/collectors 2>/dev/null || true
|
||||||
rm -rf {{ tmp_dir }}
|
rm -rf {{ tmp_dir }}
|
||||||
|
|
||||||
|
- name: Optional deps (Debian/Ubuntu) — ignore errors
|
||||||
|
ansible.builtin.raw: |
|
||||||
|
if [ -f /etc/debian_version ]; then \
|
||||||
|
apt-get update -o Acquire::AllowInsecureRepositories=true -o Acquire::https::Verify-Peer=false -o Acquire::https::Verify-Host=false || true; \
|
||||||
|
apt-get install -y --no-install-recommends sysstat iotop smartmontools nvme-cli mdadm lsscsi sg3-utils pciutils lm-sensors ipmitool jq || true; \
|
||||||
|
systemctl enable --now sysstat || true; \
|
||||||
|
fi
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Optional deps (RHEL/CentOS) — ignore errors
|
||||||
|
ansible.builtin.raw: |
|
||||||
|
if [ -f /etc/redhat-release ]; then \
|
||||||
|
yum install -y sysstat iotop smartmontools nvme-cli mdadm lsscsi sg3_utils pciutils lm_sensors ipmitool jq || true; \
|
||||||
|
systemctl enable --now sysstat || true; \
|
||||||
|
fi
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: Install/refresh systemd unit
|
- name: Install/refresh systemd unit
|
||||||
ansible.builtin.raw: |
|
ansible.builtin.raw: |
|
||||||
cat >/etc/systemd/system/sensusagent.service <<'UNIT'
|
cat >/etc/systemd/system/sensusagent.service <<'UNIT'
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
[targets]
|
[targets]
|
||||||
# example:
|
# example:
|
||||||
# server1 ansible_host=1.2.3.4 ansible_user=root
|
# server1 ansible_host=1.2.3.4 ansible_user=root
|
||||||
kube_ansible ansible_host=10.14.246.9 ansible_user=devops
|
#kube_ansible ansible_host=10.14.246.9 ansible_user=devops
|
||||||
videotest7 ansible_host=10.13.37.186 ansible_user=devops
|
#videotest7 ansible_host=10.13.37.186 ansible_user=devops
|
||||||
videotest8 ansible_host=10.13.37.187 ansible_user=devops
|
#videotest8 ansible_host=10.13.37.187 ansible_user=devops
|
||||||
|
pnode02 ansible_host=10.14.253.12 ansible_user=devops
|
||||||
|
dbrain01 ansible_host=10.14.246.75 ansible_user=devops
|
||||||
|
@ -17,7 +17,9 @@ import (
|
|||||||
|
|
||||||
// collectDocker собирает информацию о докере на macOS через docker CLI.
|
// collectDocker собирает информацию о докере на macOS через docker CLI.
|
||||||
func collectDocker(ctx context.Context) (map[string]any, error) {
|
func collectDocker(ctx context.Context) (map[string]any, error) {
|
||||||
res := map[string]any{}
|
res := map[string]any{
|
||||||
|
"collector_name": "docker",
|
||||||
|
}
|
||||||
// краткие версии
|
// краткие версии
|
||||||
res["versions"] = versionsDarwin(ctx)
|
res["versions"] = versionsDarwin(ctx)
|
||||||
|
|
||||||
|
@ -19,7 +19,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func collectDocker(ctx context.Context) (map[string]any, error) {
|
func collectDocker(ctx context.Context) (map[string]any, error) {
|
||||||
res := map[string]any{}
|
res := map[string]any{
|
||||||
|
"collector_name": "docker",
|
||||||
|
}
|
||||||
// краткие версии
|
// краткие версии
|
||||||
res["versions"] = versions(ctx)
|
res["versions"] = versions(ctx)
|
||||||
|
|
||||||
|
@ -7,28 +7,149 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// collectGPU возвращает данные в формате {"gpu": [ {...}, ... ]}
|
// collectGPU возвращает данные в формате {"gpu": [ {...}, ... ], "summary": {...}, "vms": [ {...}, ... ]}
|
||||||
func collectGPU(ctx context.Context) (map[string]any, error) {
|
func collectGPU(ctx context.Context) (map[string]any, error) {
|
||||||
|
var gpuArray []map[string]any
|
||||||
|
|
||||||
// Сначала пробуем NVIDIA
|
// Сначала пробуем NVIDIA
|
||||||
if exists("nvidia-smi") {
|
if exists("nvidia-smi") {
|
||||||
if arr := collectNvidia(ctx); len(arr) > 0 {
|
if arr := collectNvidia(ctx); len(arr) > 0 {
|
||||||
return map[string]any{"gpu": arr}, nil
|
gpuArray = arr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Затем AMD ROCm
|
// Затем AMD ROCm
|
||||||
if exists("rocm-smi") {
|
if exists("rocm-smi") && len(gpuArray) == 0 {
|
||||||
if arr := collectRocm(ctx); len(arr) > 0 {
|
if arr := collectRocm(ctx); len(arr) > 0 {
|
||||||
return map[string]any{"gpu": arr}, nil
|
gpuArray = arr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return map[string]any{"gpu": []any{}}, nil
|
|
||||||
|
result := map[string]any{
|
||||||
|
"collector_name": "gpu",
|
||||||
|
"gpu": gpuArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем агрегированную статистику
|
||||||
|
if len(gpuArray) > 0 {
|
||||||
|
result["summary"] = calculateGPUSummary(gpuArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем информацию о виртуальных машинах
|
||||||
|
vmInfo, err := collectVMInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
result["vms"] = []any{}
|
||||||
|
} else {
|
||||||
|
result["vms"] = vmInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateGPUSummary вычисляет агрегированную статистику по всем GPU
|
||||||
|
func calculateGPUSummary(gpus []map[string]any) map[string]any {
|
||||||
|
if len(gpus) == 0 {
|
||||||
|
return map[string]any{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Подсчет GPU по моделям
|
||||||
|
modelCount := make(map[string]int)
|
||||||
|
|
||||||
|
// Агрегированные метрики
|
||||||
|
totalMemMB := 0
|
||||||
|
totalUsedMemMB := 0
|
||||||
|
totalWatt := 0.0
|
||||||
|
totalUtilization := 0
|
||||||
|
validUtilizationCount := 0
|
||||||
|
|
||||||
|
// Статистика по температуре
|
||||||
|
minTemp := 999.0
|
||||||
|
maxTemp := -999.0
|
||||||
|
totalTemp := 0.0
|
||||||
|
validTempCount := 0
|
||||||
|
|
||||||
|
for _, gpu := range gpus {
|
||||||
|
// Подсчет по моделям
|
||||||
|
if name, ok := gpu["name"].(string); ok && name != "" {
|
||||||
|
modelCount[name]++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Суммарная память
|
||||||
|
if memTotal, ok := gpu["mem_total_mb"].(int); ok {
|
||||||
|
totalMemMB += memTotal
|
||||||
|
}
|
||||||
|
|
||||||
|
// Используемая память
|
||||||
|
if memUsed, ok := gpu["mem_used_mb"].(int); ok {
|
||||||
|
totalUsedMemMB += memUsed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Суммарное потребление
|
||||||
|
if power, ok := gpu["power_watt"].(float64); ok {
|
||||||
|
totalWatt += power
|
||||||
|
}
|
||||||
|
|
||||||
|
// Средняя утилизация
|
||||||
|
if util, ok := gpu["gpu_util_pct"].(int); ok && util >= 0 {
|
||||||
|
totalUtilization += util
|
||||||
|
validUtilizationCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Статистика по температуре
|
||||||
|
if temp, ok := gpu["temperature_c"].(int); ok && temp >= 0 {
|
||||||
|
tempFloat := float64(temp)
|
||||||
|
if tempFloat < minTemp {
|
||||||
|
minTemp = tempFloat
|
||||||
|
}
|
||||||
|
if tempFloat > maxTemp {
|
||||||
|
maxTemp = tempFloat
|
||||||
|
}
|
||||||
|
totalTemp += tempFloat
|
||||||
|
validTempCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вычисляем среднюю утилизацию
|
||||||
|
avgUtilization := 0.0
|
||||||
|
if validUtilizationCount > 0 {
|
||||||
|
avgUtilization = float64(totalUtilization) / float64(validUtilizationCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вычисляем среднюю температуру
|
||||||
|
avgTemp := 0.0
|
||||||
|
if validTempCount > 0 {
|
||||||
|
avgTemp = totalTemp / float64(validTempCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Формируем результат
|
||||||
|
summary := map[string]any{
|
||||||
|
"total_count": len(gpus),
|
||||||
|
"models": modelCount,
|
||||||
|
"total_mem_mb": totalMemMB,
|
||||||
|
"total_used_mem_mb": totalUsedMemMB,
|
||||||
|
"total_watt": totalWatt,
|
||||||
|
"avg_utilization_pct": avgUtilization,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем статистику по температуре, если есть валидные данные
|
||||||
|
if validTempCount > 0 {
|
||||||
|
summary["temperature_c"] = map[string]any{
|
||||||
|
"min": minTemp,
|
||||||
|
"max": maxTemp,
|
||||||
|
"avg": avgTemp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary
|
||||||
}
|
}
|
||||||
|
|
||||||
// collectNvidia парсит вывод nvidia-smi в csv,noheader,nounits
|
// collectNvidia парсит вывод nvidia-smi в csv,noheader,nounits
|
||||||
@ -181,4 +302,161 @@ func firstString(m map[string]any, keys ...string) (string, bool) {
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generateVMID создает уникальный ID виртуальной машины на основе cluster_uuid + vm_id
|
||||||
|
func generateVMID(clusterUUID, vmID string) string {
|
||||||
|
base := clusterUUID + ":" + vmID
|
||||||
|
hash := sha256.Sum256([]byte(base))
|
||||||
|
return hex.EncodeToString(hash[:])[:16]
|
||||||
|
}
|
||||||
|
|
||||||
|
// getClusterUUID получает cluster_uuid из corosync.conf
|
||||||
|
func getClusterUUID() string {
|
||||||
|
// Пробуем разные пути к corosync.conf
|
||||||
|
paths := []string{
|
||||||
|
"/etc/corosync/corosync.conf",
|
||||||
|
"/etc/pve/corosync.conf",
|
||||||
|
"/var/lib/pve-cluster/corosync.conf",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
if data, err := os.ReadFile(path); err == nil {
|
||||||
|
lines := strings.Split(string(data), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if strings.HasPrefix(line, "cluster_uuid:") {
|
||||||
|
parts := strings.SplitN(line, ":", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
return strings.TrimSpace(parts[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// collectVMInfo собирает информацию о виртуальных машинах через pvesh
|
||||||
|
func collectVMInfo(ctx context.Context) ([]map[string]any, error) {
|
||||||
|
vms := []map[string]any{}
|
||||||
|
|
||||||
|
// Проверяем наличие pvesh
|
||||||
|
if !exists("pvesh") {
|
||||||
|
return vms, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем cluster_uuid
|
||||||
|
clusterUUID := getClusterUUID()
|
||||||
|
|
||||||
|
// Получаем список всех нод
|
||||||
|
out, err := run(ctx, "pvesh", "get", "/nodes", "--output-format", "json")
|
||||||
|
if err != nil {
|
||||||
|
return vms, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodesData []map[string]any
|
||||||
|
if err := json.Unmarshal([]byte(out), &nodesData); err != nil {
|
||||||
|
return vms, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем каждую ноду
|
||||||
|
for _, node := range nodesData {
|
||||||
|
nodeName := ""
|
||||||
|
if name, ok := node["node"].(string); ok {
|
||||||
|
nodeName = name
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeName == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем VM на ноде
|
||||||
|
vmOut, err := run(ctx, "pvesh", "get", fmt.Sprintf("/nodes/%s/qemu", nodeName), "--output-format", "json")
|
||||||
|
if err == nil {
|
||||||
|
var vmData []map[string]any
|
||||||
|
if err := json.Unmarshal([]byte(vmOut), &vmData); err == nil {
|
||||||
|
for _, vm := range vmData {
|
||||||
|
vmID := ""
|
||||||
|
if id, ok := vm["vmid"].(float64); ok {
|
||||||
|
vmID = fmt.Sprintf("%.0f", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
vmInfo := map[string]any{
|
||||||
|
"vmid": vm["vmid"],
|
||||||
|
"name": vm["name"],
|
||||||
|
"status": vm["status"],
|
||||||
|
"node": nodeName,
|
||||||
|
"cpu": vm["cpu"],
|
||||||
|
"maxcpu": vm["maxcpu"],
|
||||||
|
"mem": vm["mem"],
|
||||||
|
"maxmem": vm["maxmem"],
|
||||||
|
"disk": vm["disk"],
|
||||||
|
"maxdisk": vm["maxdisk"],
|
||||||
|
"uptime": vm["uptime"],
|
||||||
|
"template": vm["template"],
|
||||||
|
"pid": vm["pid"],
|
||||||
|
"netin": vm["netin"],
|
||||||
|
"netout": vm["netout"],
|
||||||
|
"diskread": vm["diskread"],
|
||||||
|
"diskwrite": vm["diskwrite"],
|
||||||
|
"guest_agent": vm["guest_agent"],
|
||||||
|
"type": "qemu",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Генерируем уникальный vm_id
|
||||||
|
if vmID != "" && clusterUUID != "" {
|
||||||
|
vmInfo["vm_id"] = generateVMID(clusterUUID, vmID)
|
||||||
|
}
|
||||||
|
|
||||||
|
vms = append(vms, vmInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем контейнеры на ноде
|
||||||
|
ctOut, err := run(ctx, "pvesh", "get", fmt.Sprintf("/nodes/%s/lxc", nodeName), "--output-format", "json")
|
||||||
|
if err == nil {
|
||||||
|
var ctData []map[string]any
|
||||||
|
if err := json.Unmarshal([]byte(ctOut), &ctData); err == nil {
|
||||||
|
for _, ct := range ctData {
|
||||||
|
ctID := ""
|
||||||
|
if id, ok := ct["vmid"].(float64); ok {
|
||||||
|
ctID = fmt.Sprintf("%.0f", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctInfo := map[string]any{
|
||||||
|
"vmid": ct["vmid"],
|
||||||
|
"name": ct["name"],
|
||||||
|
"status": ct["status"],
|
||||||
|
"node": nodeName,
|
||||||
|
"cpu": ct["cpu"],
|
||||||
|
"maxcpu": ct["maxcpu"],
|
||||||
|
"mem": ct["mem"],
|
||||||
|
"maxmem": ct["maxmem"],
|
||||||
|
"disk": ct["disk"],
|
||||||
|
"maxdisk": ct["maxdisk"],
|
||||||
|
"uptime": ct["uptime"],
|
||||||
|
"template": ct["template"],
|
||||||
|
"pid": ct["pid"],
|
||||||
|
"netin": ct["netin"],
|
||||||
|
"netout": ct["netout"],
|
||||||
|
"diskread": ct["diskread"],
|
||||||
|
"diskwrite": ct["diskwrite"],
|
||||||
|
"type": "lxc",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Генерируем уникальный vm_id для контейнера
|
||||||
|
if ctID != "" && clusterUUID != "" {
|
||||||
|
ctInfo["vm_id"] = generateVMID(clusterUUID, ctID)
|
||||||
|
}
|
||||||
|
|
||||||
|
vms = append(vms, ctInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vms, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,9 @@ import (
|
|||||||
|
|
||||||
// collectHBA собирает агрегированный ответ по HBA/RAID контроллерам и массивам.
|
// collectHBA собирает агрегированный ответ по HBA/RAID контроллерам и массивам.
|
||||||
func collectHBA(ctx context.Context) (map[string]any, error) {
|
func collectHBA(ctx context.Context) (map[string]any, error) {
|
||||||
result := map[string]any{}
|
result := map[string]any{
|
||||||
|
"collector_name": "hba",
|
||||||
|
}
|
||||||
|
|
||||||
ctrls := listControllers(ctx)
|
ctrls := listControllers(ctx)
|
||||||
if len(ctrls) > 0 { result["controllers"] = ctrls }
|
if len(ctrls) > 0 { result["controllers"] = ctrls }
|
||||||
|
@ -18,7 +18,9 @@ import (
|
|||||||
// collectKubernetes собирает сводную информацию по кластеру
|
// collectKubernetes собирает сводную информацию по кластеру
|
||||||
func collectKubernetes(ctx context.Context) (map[string]any, error) {
|
func collectKubernetes(ctx context.Context) (map[string]any, error) {
|
||||||
if _, err := exec.LookPath("kubectl"); err != nil { return nil, nil }
|
if _, err := exec.LookPath("kubectl"); err != nil { return nil, nil }
|
||||||
res := map[string]any{}
|
res := map[string]any{
|
||||||
|
"collector_name": "kubernetes",
|
||||||
|
}
|
||||||
|
|
||||||
// Метрики из metrics.k8s.io (если доступно)
|
// Метрики из metrics.k8s.io (если доступно)
|
||||||
nodeUsage := k8sNodeUsage(ctx)
|
nodeUsage := k8sNodeUsage(ctx)
|
||||||
|
@ -12,6 +12,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func collectInfo(ctx context.Context) (map[string]any, error) {
|
func collectInfo(ctx context.Context) (map[string]any, error) {
|
||||||
|
result := map[string]any{
|
||||||
|
"collector_name": "macos",
|
||||||
|
}
|
||||||
|
|
||||||
// CPU
|
// CPU
|
||||||
cores := toIntSafe(sysctlTrim(ctx, "hw.ncpu"))
|
cores := toIntSafe(sysctlTrim(ctx, "hw.ncpu"))
|
||||||
cpuUsage := cpuUsagePercent(ctx)
|
cpuUsage := cpuUsagePercent(ctx)
|
||||||
@ -38,29 +42,27 @@ func collectInfo(ctx context.Context) (map[string]any, error) {
|
|||||||
// GPU info with VRAM totals and attempt to get usage via ioreg
|
// GPU info with VRAM totals and attempt to get usage via ioreg
|
||||||
gpus, gpuCount := gpuInfo(ctx)
|
gpus, gpuCount := gpuInfo(ctx)
|
||||||
|
|
||||||
result := map[string]any{
|
result["cpu"] = map[string]any{
|
||||||
"cpu": map[string]any{
|
"cores": cores,
|
||||||
"cores": cores,
|
"usage_percent": cpuUsage,
|
||||||
"usage_percent": cpuUsage,
|
}
|
||||||
},
|
result["ram"] = ram
|
||||||
"ram": ram,
|
result["disks"] = map[string]any{
|
||||||
"disks": map[string]any{
|
"by_mount": disks,
|
||||||
"by_mount": disks,
|
"total_bytes": totalDisk,
|
||||||
"total_bytes": totalDisk,
|
"used_bytes": usedDisk,
|
||||||
"used_bytes": usedDisk,
|
"nvme": nvmeCount,
|
||||||
"nvme": nvmeCount,
|
"ssd": ssdCount,
|
||||||
"ssd": ssdCount,
|
"hdd": hddCount,
|
||||||
"hdd": hddCount,
|
}
|
||||||
},
|
result["gpu"] = map[string]any{
|
||||||
"gpu": map[string]any{
|
"count": gpuCount,
|
||||||
"count": gpuCount,
|
"devices": gpus,
|
||||||
"devices": gpus,
|
}
|
||||||
},
|
result["load"] = map[string]any{
|
||||||
"load": map[string]any{
|
"1m": l1,
|
||||||
"1m": l1,
|
"5m": l5,
|
||||||
"5m": l5,
|
"15m": l15,
|
||||||
"15m": l15,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
44
src/collectors/proxcluster/main.go
Normal file
44
src/collectors/proxcluster/main.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// Автор: Сергей Антропов, сайт: https://devops.org.ru
|
||||||
|
// Коллектор proxcluster на Go. Собирает информацию о Proxmox кластере.
|
||||||
|
// Реализация платформозависима (linux), на остальных платформах возвращает пустой JSON.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// collectProxCluster реализуется в файлах с билд-тегами под конкретные ОС.
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Таймаут можно переопределить окружением COLLECTOR_TIMEOUT
|
||||||
|
timeout := parseDurationOr("COLLECTOR_TIMEOUT", 30*time.Second)
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
data, err := collectProxCluster(ctx)
|
||||||
|
if err != nil || data == nil {
|
||||||
|
fmt.Println("{}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
enc := json.NewEncoder(os.Stdout)
|
||||||
|
enc.SetEscapeHTML(false)
|
||||||
|
_ = enc.Encode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDurationOr(env string, def time.Duration) time.Duration {
|
||||||
|
v := strings.TrimSpace(os.Getenv(env))
|
||||||
|
if v == "" {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
d, err := time.ParseDuration(v)
|
||||||
|
if err != nil {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
1489
src/collectors/proxcluster/proxcluster_linux.go
Normal file
1489
src/collectors/proxcluster/proxcluster_linux.go
Normal file
File diff suppressed because it is too large
Load Diff
16
src/collectors/proxcluster/proxcluster_unsupported.go
Normal file
16
src/collectors/proxcluster/proxcluster_unsupported.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Автор: Сергей Антропов, сайт: https://devops.org.ru
|
||||||
|
// Заглушка для неподдерживаемых платформ.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// collectProxCluster возвращает пустой результат для неподдерживаемых платформ.
|
||||||
|
func collectProxCluster(ctx context.Context) (map[string]any, error) {
|
||||||
|
return nil, errors.New("proxcluster collector is not supported on this platform")
|
||||||
|
}
|
@ -16,7 +16,9 @@ import (
|
|||||||
|
|
||||||
// collectSensors собирает сводную информацию по температуре/вентиляторам/питанию и статусам chassis.
|
// collectSensors собирает сводную информацию по температуре/вентиляторам/питанию и статусам chassis.
|
||||||
func collectSensors(ctx context.Context) (map[string]any, error) {
|
func collectSensors(ctx context.Context) (map[string]any, error) {
|
||||||
res := map[string]any{}
|
res := map[string]any{
|
||||||
|
"collector_name": "sensors",
|
||||||
|
}
|
||||||
if lm := collectLmSensors(ctx); len(lm) > 0 { res["lm_sensors"] = lm }
|
if lm := collectLmSensors(ctx); len(lm) > 0 { res["lm_sensors"] = lm }
|
||||||
if ipmi := collectIPMI(ctx); len(ipmi) > 0 { res["ipmi"] = ipmi }
|
if ipmi := collectIPMI(ctx); len(ipmi) > 0 { res["ipmi"] = ipmi }
|
||||||
if len(res) == 0 { return nil, nil }
|
if len(res) == 0 { return nil, nil }
|
||||||
|
@ -22,7 +22,9 @@ import (
|
|||||||
// синхронизация времени и обновления) и возвращает их одним JSON-блоком.
|
// синхронизация времени и обновления) и возвращает их одним JSON-блоком.
|
||||||
// Используется как основной вход в коллекторе system для Linux.
|
// Используется как основной вход в коллекторе system для Linux.
|
||||||
func collectSystem(ctx context.Context) (map[string]any, error) {
|
func collectSystem(ctx context.Context) (map[string]any, error) {
|
||||||
result := map[string]any{}
|
result := map[string]any{
|
||||||
|
"collector_name": "system",
|
||||||
|
}
|
||||||
|
|
||||||
cpu, err := collectCPU(ctx)
|
cpu, err := collectCPU(ctx)
|
||||||
if err == nil { result["cpu"] = cpu }
|
if err == nil { result["cpu"] = cpu }
|
||||||
|
@ -25,6 +25,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
out := map[string]any{
|
out := map[string]any{
|
||||||
|
"collector_name": "uptime",
|
||||||
"seconds": secs,
|
"seconds": secs,
|
||||||
"human": humanize(time.Duration(secs) * time.Second),
|
"human": humanize(time.Duration(secs) * time.Second),
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user