diff --git a/Makefile b/Makefile index faa543d..1258049 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,8 @@ collectors: 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 && \ - CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/proxnode ./src/collectors/proxnode"; \ + CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/proxnode ./src/collectors/proxnode && \ + CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/proxvms ./src/collectors/proxvms"; \ fi @# Убедимся, что скрипты исполняемые @chmod +x ./bin/agent/collectors/*.sh 2>/dev/null || true @@ -87,7 +88,8 @@ collectors-linux: 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 && \ - CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/proxnode ./src/collectors/proxnode" + CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/proxnode ./src/collectors/proxnode && \ + CGO_ENABLED=0 go build -trimpath -o ./bin/agent/collectors/proxvms ./src/collectors/proxvms" collectors-windows: # Кросс-сборка коллекторов для Windows diff --git a/bin/agent/config.yaml b/bin/agent/config.yaml index 5352a7d..8e21438 100644 --- a/bin/agent/config.yaml +++ b/bin/agent/config.yaml @@ -95,7 +95,7 @@ collectors: exec: "./collectors/kubernetes" platforms: [linux] proxnode: - enabled: true + enabled: false type: exec key: proxnode interval: "1800s" @@ -103,12 +103,20 @@ collectors: exec: "./collectors/proxnode" platforms: [linux] proxcluster: - enabled: true + enabled: false type: exec key: proxcluster interval: "1800s" timeout: "600s" exec: "./collectors/proxcluster" platforms: [linux] + proxvms: + enabled: true + type: exec + key: proxvms + interval: "1800s" + timeout: "300s" + exec: "./collectors/proxvms" + platforms: [linux] diff --git a/docs/collectors.md b/docs/collectors.md index 8a27cea..5601770 100644 --- a/docs/collectors.md +++ b/docs/collectors.md @@ -50,18 +50,29 @@ make collectors-darwin # darwin/arm64 ### Встроенные коллекторы -- **system** - системные метрики (CPU, RAM, сеть, диски, обновления) -- **uptime** - время работы системы -- **macos** - специфичные для macOS метрики -- **hba** - информация о HBA адаптерах -- **sensors** - данные датчиков температуры/напряжения -- **docker** - информация о Docker контейнерах -- **gpu** - информация о GPU устройствах -- **kubernetes** - метрики Kubernetes кластера -- **proxcluster** - информация о Proxmox кластере ⭐ +- **system** - системные метрики (CPU, RAM, сеть, диски, обновления) - Linux +- **uptime** - время работы системы - Linux/macOS +- **macos** - специфичные для macOS метрики (sysctl + system_profiler) - macOS +- **hba** - информация о RAID/HBA контроллерах и массивах - Linux +- **sensors** - данные датчиков температуры/напряжения (lm-sensors, IPMI) - Linux +- **docker** - информация о Docker контейнерах, сетях, томах и версиях - Linux/macOS +- **gpu** - информация о GPU устройствах (NVIDIA/AMD) с агрегированной статистикой - Linux +- **kubernetes** - метрики Kubernetes кластера через kubectl - Linux/macOS +- **proxcluster** - информация о Proxmox кластере (ноды, хранилища, кворум) - Linux ⭐ +- **proxnode** - информация о Proxmox ноде (ресурсы, сервисы, диски) - Linux ⭐ +- **proxvms** - информация о виртуальных машинах и контейнерах Proxmox - Linux ⭐ ### Документация коллекторов - [proxcluster](collectors/proxcluster.md) - сбор информации о Proxmox кластере - [gpu](collectors/gpu.md) - сбор информации о GPU устройствах с агрегированной статистикой +- [proxnode](collectors/proxnode.md) - сбор информации о Proxmox ноде +- [proxvms](collectors/proxvms.md) - сбор информации о виртуальных машинах и контейнерах Proxmox +- [system](collectors/system.md) - сбор системных метрик +- [docker](collectors/docker.md) - сбор информации о Docker контейнерах +- [hba](collectors/hba.md) - сбор информации о RAID/HBA контроллерах +- [sensors](collectors/sensors.md) - сбор данных датчиков +- [kubernetes](collectors/kubernetes.md) - сбор метрик Kubernetes кластера +- [macos](collectors/macos.md) - сбор специфичных для macOS метрик +- [uptime](collectors/uptime.md) - сбор времени работы системы diff --git a/docs/collectors/docker.md b/docs/collectors/docker.md new file mode 100644 index 0000000..4c24eb3 --- /dev/null +++ b/docs/collectors/docker.md @@ -0,0 +1,297 @@ +# Коллектор docker + +**Автор:** Сергей Антропов +**Сайт:** https://devops.org.ru + +## Описание + +Коллектор `docker` собирает информацию о Docker контейнерах, сетях, томах и версиях Docker. Предоставляет детальную информацию о состоянии Docker окружения. + +## Поддерживаемые платформы + +- **Linux**: Полная поддержка +- **macOS**: Базовая поддержка +- **Windows**: Не поддерживается (возвращает пустой JSON) + +## Собираемые данные + +### Информация о версии Docker + +```json +{ + "docker_version": { + "version": "24.0.7", // Версия Docker + "api_version": "1.43", // Версия API + "go_version": "go1.20.10", // Версия Go + "git_commit": "afdd53b", // Git commit + "build_time": "2023-10-25T18:00:00.000000000+00:00", // Время сборки + "os": "linux", // Операционная система + "arch": "amd64" // Архитектура + } +} +``` + +### Информация о контейнерах + +```json +{ + "containers": [ + { + "id": "a1b2c3d4e5f6", // ID контейнера + "name": "web-server", // Имя контейнера + "image": "nginx:latest", // Образ + "status": "running", // Статус (running, stopped, paused) + "state": "running", // Состояние + "created": "2024-01-01T12:00:00Z", // Время создания + "started": "2024-01-01T12:00:00Z", // Время запуска + "ports": [ // Публичные порты + { + "private_port": 80, + "public_port": 8080, + "type": "tcp" + } + ], + "mounts": [ // Точки монтирования + { + "source": "/host/path", + "destination": "/container/path", + "mode": "rw", + "type": "bind" + } + ], + "networks": ["bridge"], // Сети + "labels": { // Метки + "com.example.service": "web" + }, + "restart_policy": "unless-stopped", // Политика перезапуска + "cpu_usage": 25.5, // Использование CPU в процентах + "memory_usage_mb": 128, // Использование памяти в МБ + "memory_limit_mb": 512 // Лимит памяти в МБ + } + ] +} +``` + +### Информация о сетях + +```json +{ + "networks": [ + { + "id": "n1b2c3d4e5f6", // ID сети + "name": "bridge", // Имя сети + "driver": "bridge", // Драйвер сети + "scope": "local", // Область действия + "ipam": { // IP Address Management + "driver": "default", + "config": [ + { + "subnet": "172.17.0.0/16", + "gateway": "172.17.0.1" + } + ] + }, + "containers": 3, // Количество контейнеров + "created": "2024-01-01T12:00:00Z" // Время создания + } + ] +} +``` + +### Информация о томах + +```json +{ + "volumes": [ + { + "name": "my-volume", // Имя тома + "driver": "local", // Драйвер тома + "mountpoint": "/var/lib/docker/volumes/my-volume/_data", // Точка монтирования + "created": "2024-01-01T12:00:00Z", // Время создания + "labels": { // Метки + "com.example.volume": "data" + }, + "size_bytes": 1073741824, // Размер в байтах + "containers": 2 // Количество контейнеров + } + ] +} +``` + +### Статистика Docker + +```json +{ + "stats": { + "containers_total": 5, // Общее количество контейнеров + "containers_running": 3, // Запущенные контейнеры + "containers_stopped": 2, // Остановленные контейнеры + "images_total": 15, // Общее количество образов + "networks_total": 3, // Общее количество сетей + "volumes_total": 5, // Общее количество томов + "total_cpu_usage": 45.2, // Общее использование CPU + "total_memory_usage_mb": 1024, // Общее использование памяти в МБ + "total_memory_limit_mb": 2048 // Общий лимит памяти в МБ + } +} +``` + +## Конфигурация + +### config.yaml + +```yaml +collectors: + docker: + enabled: true + type: exec + key: docker + interval: "60s" # 1 минута + timeout: "8s" + exec: "./collectors/docker" + platforms: [linux, darwin] +``` + +### Переменные окружения + +- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 8s) + +## Требования + +### Системные требования + +- Docker Engine +- Доступ к Docker API +- Права на выполнение Docker команд + +### Команды + +Коллектор использует следующие команды (должны быть доступны): + +- `docker` - основная команда Docker +- `docker version` - версия Docker +- `docker ps` - список контейнеров +- `docker images` - список образов +- `docker network ls` - список сетей +- `docker volume ls` - список томов +- `docker stats` - статистика контейнеров + +## Примеры использования + +### Проверка работы коллектора + +```bash +# Запуск коллектора напрямую +./bin/agent/collectors/docker + +# Запуск через агент +make run +``` + +### Фильтрация данных + +```bash +# Версия Docker +./bin/agent/collectors/docker | jq '.docker_version' + +# Все контейнеры +./bin/agent/collectors/docker | jq '.containers' + +# Только запущенные контейнеры +./bin/agent/collectors/docker | jq '.containers[] | select(.status == "running")' + +# Контейнеры с высоким использованием CPU (>50%) +./bin/agent/collectors/docker | jq '.containers[] | select(.cpu_usage > 50)' + +# Контейнеры с высоким использованием памяти (>500MB) +./bin/agent/collectors/docker | jq '.containers[] | select(.memory_usage_mb > 500)' + +# Сети +./bin/agent/collectors/docker | jq '.networks' + +# Тома +./bin/agent/collectors/docker | jq '.volumes' + +# Статистика +./bin/agent/collectors/docker | jq '.stats' + +# Общее количество контейнеров +./bin/agent/collectors/docker | jq '.stats.containers_total' + +# Общее использование CPU +./bin/agent/collectors/docker | jq '.stats.total_cpu_usage' + +# Общее использование памяти +./bin/agent/collectors/docker | jq '.stats.total_memory_usage_mb' +``` + +## Устранение неполадок + +### Частые проблемы + +1. **"Docker not found"** + - Убедитесь, что Docker установлен + - Проверьте доступность команды `docker` + - Убедитесь, что Docker daemon запущен + +2. **"Permission denied"** + - Добавьте пользователя в группу `docker` + - Или запустите с правами `sudo` + +3. **"Cannot connect to Docker daemon"** + - Проверьте статус Docker daemon + - Убедитесь, что Docker socket доступен + +4. **Пустые данные о контейнерах** + - Проверьте права доступа к Docker API + - Убедитесь в корректности конфигурации Docker + +### Отладка + +```bash +# Проверка установки Docker +docker --version + +# Проверка статуса Docker daemon +systemctl status docker + +# Проверка доступности Docker API +docker info + +# Проверка контейнеров +docker ps -a + +# Проверка образов +docker images + +# Проверка сетей +docker network ls + +# Проверка томов +docker volume ls + +# Проверка статистики +docker stats --no-stream +``` + +## Безопасность + +- Коллектор требует права на доступ к Docker API +- Не передает пароли или секретные ключи +- Собирает только публичную информацию о контейнерах +- Не выполняет привилегированные операции + +## Производительность + +- Время выполнения: ~2-8 секунд +- Интервал сбора: рекомендуется 1 минута (60s) +- Потребление ресурсов: минимальное +- Собирает только локальную информацию о Docker + +## Совместимость + +- **Docker**: 20.0+ +- **Платформы**: Linux, macOS +- **Архитектуры**: x86_64, ARM64 +- **Сети**: bridge, overlay, macvlan и др. +- **Тома**: local, nfs, cifs и др. diff --git a/docs/collectors/hba.md b/docs/collectors/hba.md new file mode 100644 index 0000000..513a2c5 --- /dev/null +++ b/docs/collectors/hba.md @@ -0,0 +1,252 @@ +# Коллектор hba + +**Автор:** Сергей Антропов +**Сайт:** https://devops.org.ru + +## Описание + +Коллектор `hba` собирает информацию о RAID/HBA контроллерах и массивах в Linux системе. Предоставляет детальную информацию о состоянии контроллеров, дисков и RAID массивов. + +## Поддерживаемые платформы + +- **Linux**: Полная поддержка +- **macOS/Windows**: Не поддерживается (возвращает пустой JSON) + +## Собираемые данные + +### Информация о RAID контроллерах + +```json +{ + "controllers": [ + { + "id": 0, // ID контроллера + "name": "MegaRAID SAS 9361-8i", // Название контроллера + "firmware_version": "23.34.0-0019", // Версия прошивки + "driver_version": "07.710.06.00", // Версия драйвера + "pci_address": "0000:01:00.0", // PCI адрес + "status": "Optimal", // Статус контроллера + "temperature": 45, // Температура в градусах Цельсия + "battery_status": "Optimal", // Статус батареи + "cache_size_mb": 1024, // Размер кэша в МБ + "raid_levels": ["RAID0", "RAID1", "RAID5", "RAID6", "RAID10"], // Поддерживаемые уровни RAID + "arrays": [ // RAID массивы + { + "id": 0, // ID массива + "name": "Array0", // Имя массива + "raid_level": "RAID5", // Уровень RAID + "status": "Optimal", // Статус массива + "size_gb": 2000, // Размер массива в ГБ + "used_gb": 1500, // Использовано в ГБ + "free_gb": 500, // Свободно в ГБ + "disks": [ // Диски в массиве + { + "id": 0, // ID диска + "model": "ST4000NM0033", // Модель диска + "size_gb": 4000, // Размер диска в ГБ + "status": "Online", // Статус диска + "temperature": 35, // Температура диска + "serial": "Z1Z2A3B4", // Серийный номер + "firmware": "SN04", // Версия прошивки + "slot": 0 // Слот диска + } + ] + } + ] + } + ] +} +``` + +### Информация о HBA адаптерах + +```json +{ + "hba_adapters": [ + { + "id": 1, // ID адаптера + "name": "LSI SAS 9300-8e", // Название адаптера + "driver": "mpt3sas", // Драйвер + "firmware_version": "15.00.00.00", // Версия прошивки + "pci_address": "0000:02:00.0", // PCI адрес + "status": "Active", // Статус адаптера + "ports": 8, // Количество портов + "connected_devices": 4, // Количество подключенных устройств + "devices": [ // Подключенные устройства + { + "id": 0, // ID устройства + "model": "ST4000NM0033", // Модель устройства + "size_gb": 4000, // Размер в ГБ + "status": "Online", // Статус устройства + "port": 0, // Порт подключения + "serial": "Z1Z2A3B4" // Серийный номер + } + ] + } + ] +} +``` + +### Статистика + +```json +{ + "stats": { + "controllers_total": 1, // Общее количество контроллеров + "hba_adapters_total": 1, // Общее количество HBA адаптеров + "arrays_total": 1, // Общее количество массивов + "disks_total": 4, // Общее количество дисков + "arrays_optimal": 1, // Количество оптимальных массивов + "arrays_degraded": 0, // Количество деградированных массивов + "arrays_failed": 0, // Количество неисправных массивов + "disks_online": 4, // Количество онлайн дисков + "disks_failed": 0, // Количество неисправных дисков + "total_capacity_gb": 8000, // Общая емкость в ГБ + "used_capacity_gb": 1500, // Использованная емкость в ГБ + "free_capacity_gb": 6500 // Свободная емкость в ГБ + } +} +``` + +## Конфигурация + +### config.yaml + +```yaml +collectors: + hba: + enabled: true + type: exec + key: hba + interval: "300s" # 5 минут + timeout: "8s" + exec: "./collectors/hba" + platforms: [linux] +``` + +### Переменные окружения + +- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 8s) + +## Требования + +### Системные требования + +- Linux система с RAID/HBA контроллерами +- Установленные утилиты для управления контроллерами +- Права на чтение информации о контроллерах + +### Команды + +Коллектор использует следующие команды (должны быть доступны): + +- `storcli` - утилита для LSI/Broadcom контроллеров +- `megacli` - утилита для LSI контроллеров +- `arcconf` - утилита для Adaptec контроллеров +- `lspci` - информация о PCI устройствах +- `lshw` - информация об оборудовании + +## Примеры использования + +### Проверка работы коллектора + +```bash +# Запуск коллектора напрямую +./bin/agent/collectors/hba + +# Запуск через агент +make run +``` + +### Фильтрация данных + +```bash +# Все контроллеры +./bin/agent/collectors/hba | jq '.controllers' + +# Статус контроллеров +./bin/agent/collectors/hba | jq '.controllers[] | {name, status, temperature}' + +# RAID массивы +./bin/agent/collectors/hba | jq '.controllers[].arrays' + +# Только оптимальные массивы +./bin/agent/collectors/hba | jq '.controllers[].arrays[] | select(.status == "Optimal")' + +# Диски с высокой температурой (>40°C) +./bin/agent/collectors/hba | jq '.controllers[].arrays[].disks[] | select(.temperature > 40)' + +# HBA адаптеры +./bin/agent/collectors/hba | jq '.hba_adapters' + +# Статистика +./bin/agent/collectors/hba | jq '.stats' + +# Общая емкость +./bin/agent/collectors/hba | jq '.stats.total_capacity_gb' + +# Использованная емкость +./bin/agent/collectors/hba | jq '.stats.used_capacity_gb' +``` + +## Устранение неполадок + +### Частые проблемы + +1. **"No RAID controllers found"** + - Убедитесь, что RAID контроллеры установлены + - Проверьте доступность утилит управления + - Убедитесь в правильности прав доступа + +2. **"Permission denied"** + - Запустите с правами `sudo` + - Или добавьте пользователя в соответствующие группы + +3. **"Command not found"** + - Установите утилиты управления контроллерами + - Проверьте PATH для команд + +### Отладка + +```bash +# Проверка доступности команд +which storcli megacli arcconf lspci lshw + +# Проверка PCI устройств +lspci | grep -i raid +lspci | grep -i hba + +# Проверка контроллеров (LSI/Broadcom) +sudo storcli show + +# Проверка контроллеров (LSI) +sudo megacli -AdpAllInfo -aALL + +# Проверка контроллеров (Adaptec) +sudo arcconf getconfig 1 + +# Проверка оборудования +sudo lshw -class storage +``` + +## Безопасность + +- Коллектор требует права на чтение информации о контроллерах +- Не передает пароли или секретные ключи +- Собирает только публичную информацию о контроллерах +- Не выполняет привилегированные операции + +## Производительность + +- Время выполнения: ~2-8 секунд +- Интервал сбора: рекомендуется 5 минут (300s) +- Потребление ресурсов: минимальное +- Собирает только локальную информацию о контроллерах + +## Совместимость + +- **RAID контроллеры**: LSI/Broadcom, Adaptec, Intel +- **HBA адаптеры**: LSI, QLogic, Emulex +- **RAID уровни**: RAID0, RAID1, RAID5, RAID6, RAID10 +- **Диски**: SATA, SAS, NVMe +- **Linux**: все дистрибутивы diff --git a/docs/collectors/kubernetes.md b/docs/collectors/kubernetes.md new file mode 100644 index 0000000..5dbee6f --- /dev/null +++ b/docs/collectors/kubernetes.md @@ -0,0 +1,347 @@ +# Коллектор kubernetes + +**Автор:** Сергей Антропов +**Сайт:** https://devops.org.ru + +## Описание + +Коллектор `kubernetes` собирает агрегированную информацию о Kubernetes кластере через kubectl. Предоставляет детальную информацию о нодах, подах, сервисах и других ресурсах кластера. + +## Поддерживаемые платформы + +- **Linux**: Полная поддержка +- **macOS**: Полная поддержка +- **Windows**: Не поддерживается (возвращает пустой JSON) + +## Собираемые данные + +### Информация о кластере + +```json +{ + "cluster": { + "name": "production-cluster", // Имя кластера + "version": "v1.28.2", // Версия Kubernetes + "context": "production", // Контекст kubectl + "server": "https://kubernetes.default.svc.cluster.local:443" // Сервер API + } +} +``` + +### Информация о нодах + +```json +{ + "nodes": [ + { + "name": "worker-1", // Имя ноды + "status": "Ready", // Статус ноды + "roles": ["worker"], // Роли ноды + "version": "v1.28.2", // Версия kubelet + "os": "linux", // Операционная система + "arch": "amd64", // Архитектура + "kernel": "5.4.0-74-generic", // Версия ядра + "container_runtime": "containerd://1.6.6", // Контейнерный runtime + "capacity": { // Емкость ноды + "cpu": "4", // CPU (cores) + "memory": "8Gi", // Память + "pods": "110", // Максимум подов + "ephemeral_storage": "20Gi" // Эфемерное хранилище + }, + "allocatable": { // Доступные ресурсы + "cpu": "3920m", // CPU (millicores) + "memory": "7.5Gi", // Память + "pods": "110", // Максимум подов + "ephemeral_storage": "18Gi" // Эфемерное хранилище + }, + "conditions": [ // Условия ноды + { + "type": "Ready", + "status": "True", + "last_heartbeat": "2024-01-01T12:00:00Z" + } + ], + "taints": [], // Taints ноды + "labels": { // Метки ноды + "kubernetes.io/hostname": "worker-1", + "node-role.kubernetes.io/worker": "" + } + } + ] +} +``` + +### Информация о подах + +```json +{ + "pods": [ + { + "name": "web-server-7d4b8c9f6-abc12", // Имя пода + "namespace": "default", // Namespace + "node": "worker-1", // Нода + "status": "Running", // Статус пода + "phase": "Running", // Фаза пода + "restart_count": 0, // Количество перезапусков + "age": "2d", // Возраст пода + "containers": [ // Контейнеры в поде + { + "name": "web-server", // Имя контейнера + "image": "nginx:1.21", // Образ + "ready": true, // Готовность + "restart_count": 0, // Количество перезапусков + "state": "running" // Состояние + } + ], + "labels": { // Метки пода + "app": "web-server", + "version": "v1.0.0" + }, + "requests": { // Запрошенные ресурсы + "cpu": "100m", // CPU + "memory": "128Mi" // Память + }, + "limits": { // Лимиты ресурсов + "cpu": "500m", // CPU + "memory": "512Mi" // Память + } + } + ] +} +``` + +### Информация о сервисах + +```json +{ + "services": [ + { + "name": "web-server-service", // Имя сервиса + "namespace": "default", // Namespace + "type": "ClusterIP", // Тип сервиса + "cluster_ip": "10.96.0.1", // Cluster IP + "external_ip": "", // External IP + "ports": [ // Порты + { + "name": "http", + "port": 80, + "target_port": 8080, + "protocol": "TCP" + } + ], + "selector": { // Селектор + "app": "web-server" + }, + "labels": { // Метки сервиса + "app": "web-server" + } + } + ] +} +``` + +### Информация о деплойментах + +```json +{ + "deployments": [ + { + "name": "web-server", // Имя деплоймента + "namespace": "default", // Namespace + "replicas": 3, // Желаемое количество реплик + "ready_replicas": 3, // Готовые реплики + "available_replicas": 3, // Доступные реплики + "updated_replicas": 3, // Обновленные реплики + "strategy": "RollingUpdate", // Стратегия обновления + "labels": { // Метки деплоймента + "app": "web-server" + } + } + ] +} +``` + +### Статистика кластера + +```json +{ + "stats": { + "nodes_total": 3, // Общее количество нод + "nodes_ready": 3, // Готовые ноды + "nodes_not_ready": 0, // Неготовые ноды + "pods_total": 15, // Общее количество подов + "pods_running": 12, // Запущенные поды + "pods_pending": 2, // Ожидающие поды + "pods_failed": 1, // Неудачные поды + "services_total": 5, // Общее количество сервисов + "deployments_total": 3, // Общее количество деплойментов + "namespaces_total": 4, // Общее количество namespace + "total_cpu_cores": 12, // Общее количество CPU ядер + "total_memory_gb": 24, // Общая память в ГБ + "used_cpu_cores": 6, // Использованные CPU ядра + "used_memory_gb": 12 // Использованная память в ГБ + } +} +``` + +## Конфигурация + +### config.yaml + +```yaml +collectors: + kubernetes: + enabled: true + type: exec + key: kubernetes + interval: "300s" # 5 минут + timeout: "12s" + exec: "./collectors/kubernetes" + platforms: [linux, darwin] +``` + +### Переменные окружения + +- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 12s) +- `KUBECONFIG`: Путь к файлу конфигурации kubectl + +## Требования + +### Системные требования + +- Kubernetes кластер +- Настроенный kubeconfig +- Доступ к Kubernetes API +- Права на чтение ресурсов кластера + +### Команды + +Коллектор использует следующие команды (должны быть доступны): + +- `kubectl` - утилита командной строки Kubernetes +- `kubectl get nodes` - список нод +- `kubectl get pods` - список подов +- `kubectl get services` - список сервисов +- `kubectl get deployments` - список деплойментов +- `kubectl get namespaces` - список namespace + +## Примеры использования + +### Проверка работы коллектора + +```bash +# Запуск коллектора напрямую +./bin/agent/collectors/kubernetes + +# Запуск через агент +make run +``` + +### Фильтрация данных + +```bash +# Информация о кластере +./bin/agent/collectors/kubernetes | jq '.cluster' + +# Все ноды +./bin/agent/collectors/kubernetes | jq '.nodes' + +# Только готовые ноды +./bin/agent/collectors/kubernetes | jq '.nodes[] | select(.status == "Ready")' + +# Все поды +./bin/agent/collectors/kubernetes | jq '.pods' + +# Только запущенные поды +./bin/agent/collectors/kubernetes | jq '.pods[] | select(.status == "Running")' + +# Поды с определенным namespace +./bin/agent/collectors/kubernetes | jq '.pods[] | select(.namespace == "default")' + +# Все сервисы +./bin/agent/collectors/kubernetes | jq '.services' + +# Все деплойменты +./bin/agent/collectors/kubernetes | jq '.deployments' + +# Статистика кластера +./bin/agent/collectors/kubernetes | jq '.stats' + +# Общее количество нод +./bin/agent/collectors/kubernetes | jq '.stats.nodes_total' + +# Общее количество подов +./bin/agent/collectors/kubernetes | jq '.stats.pods_total' + +# Использование ресурсов +./bin/agent/collectors/kubernetes | jq '.stats | {total_cpu_cores, used_cpu_cores, total_memory_gb, used_memory_gb}' +``` + +## Устранение неполадок + +### Частые проблемы + +1. **"kubectl not found"** + - Убедитесь, что kubectl установлен + - Проверьте PATH для команды kubectl + +2. **"Unable to connect to the server"** + - Проверьте конфигурацию kubeconfig + - Убедитесь в доступности Kubernetes API + - Проверьте права доступа к кластеру + +3. **"Permission denied"** + - Проверьте права доступа к ресурсам кластера + - Убедитесь в правильности RBAC настроек + +4. **"Context not found"** + - Проверьте конфигурацию kubeconfig + - Убедитесь в правильности контекста + +### Отладка + +```bash +# Проверка установки kubectl +kubectl version --client + +# Проверка подключения к кластеру +kubectl cluster-info + +# Проверка конфигурации +kubectl config view + +# Проверка текущего контекста +kubectl config current-context + +# Проверка прав доступа +kubectl auth can-i get pods +kubectl auth can-i get nodes +kubectl auth can-i get services + +# Проверка ресурсов +kubectl get nodes +kubectl get pods --all-namespaces +kubectl get services --all-namespaces +``` + +## Безопасность + +- Коллектор требует права на чтение ресурсов кластера +- Не передает пароли или секретные ключи +- Собирает только публичную информацию о кластере +- Не выполняет привилегированные операции + +## Производительность + +- Время выполнения: ~5-12 секунд +- Интервал сбора: рекомендуется 5 минут (300s) +- Потребление ресурсов: минимальное +- Собирает только локальную информацию о кластере + +## Совместимость + +- **Kubernetes**: 1.20+ +- **Платформы**: Linux, macOS +- **Архитектуры**: x86_64, ARM64 +- **Типы нод**: master, worker +- **Контейнерные runtime**: containerd, docker, cri-o diff --git a/docs/collectors/macos.md b/docs/collectors/macos.md new file mode 100644 index 0000000..768ab2b --- /dev/null +++ b/docs/collectors/macos.md @@ -0,0 +1,344 @@ +# Коллектор macos + +**Автор:** Сергей Антропов +**Сайт:** https://devops.org.ru + +## Описание + +Коллектор `macos` собирает специфичные для macOS метрики через sysctl и system_profiler. Предоставляет детальную информацию о железе, системе и производительности macOS системы. + +## Поддерживаемые платформы + +- **macOS**: Полная поддержка +- **Linux/Windows**: Не поддерживается (возвращает пустой JSON) + +## Собираемые данные + +### Информация о системе + +```json +{ + "system": { + "hostname": "MacBook-Pro", // Имя хоста + "os_version": "macOS 14.0", // Версия macOS + "build_version": "23A344", // Версия сборки + "kernel_version": "Darwin 23.0.0", // Версия ядра + "uptime_seconds": 86400, // Время работы в секундах + "boot_time": "2024-01-01T00:00:00Z", // Время загрузки + "timezone": "Europe/Moscow" // Часовой пояс + } +} +``` + +### Информация о железе + +```json +{ + "hardware": { + "model": "MacBook Pro", // Модель Mac + "model_identifier": "MacBookPro18,1", // Идентификатор модели + "serial_number": "FVF123456789", // Серийный номер + "chip": "Apple M1 Pro", // Чип + "cpu": { // Информация о CPU + "name": "Apple M1 Pro", // Название CPU + "cores": 10, // Количество ядер + "performance_cores": 8, // Ядра производительности + "efficiency_cores": 2, // Энергоэффективные ядра + "frequency_mhz": 3200 // Частота в МГц + }, + "memory": { // Информация о памяти + "total_gb": 16, // Общая память в ГБ + "type": "LPDDR5", // Тип памяти + "speed_mhz": 6400 // Скорость памяти в МГц + }, + "storage": [ // Информация о хранилище + { + "name": "APPLE SSD AP1024N", // Название накопителя + "size_gb": 1024, // Размер в ГБ + "type": "SSD", // Тип накопителя + "interface": "PCIe", // Интерфейс + "serial": "C1234567890" // Серийный номер + } + ], + "graphics": [ // Информация о графике + { + "name": "Apple M1 Pro", // Название GPU + "type": "Integrated", // Тип GPU + "memory_mb": 0 // Память GPU в МБ (0 для integrated) + } + ] + } +} +``` + +### Информация о сети + +```json +{ + "network": { + "interfaces": [ // Сетевые интерфейсы + { + "name": "en0", // Имя интерфейса + "type": "Ethernet", // Тип интерфейса + "status": "Active", // Статус интерфейса + "speed_mbps": 1000, // Скорость в Мбит/с + "mac_address": "00:11:22:33:44:55", // MAC адрес + "ip_addresses": [ // IP адреса + "192.168.1.100" + ] + }, + { + "name": "en1", + "type": "Wi-Fi", + "status": "Active", + "speed_mbps": 866, + "mac_address": "00:11:22:33:44:56", + "ip_addresses": [ + "192.168.1.101" + ] + } + ], + "wifi": { // Информация о Wi-Fi + "ssid": "MyNetwork", // Имя сети + "security": "WPA2", // Тип безопасности + "signal_strength": -45, // Сила сигнала в dBm + "channel": 6, // Канал + "frequency_mhz": 2437 // Частота в МГц + } + } +} +``` + +### Информация о батарее + +```json +{ + "battery": { + "present": true, // Присутствует ли батарея + "charge_percent": 85, // Заряд в процентах + "cycle_count": 150, // Количество циклов + "condition": "Normal", // Состояние батареи + "power_source": "Battery Power", // Источник питания + "time_remaining": "3:45", // Оставшееся время + "voltage": 12.5, // Напряжение в В + "current": -1500, // Ток в мА (отрицательный = разряд) + "temperature": 25.0 // Температура в градусах Цельсия + } +} +``` + +### Информация о производительности + +```json +{ + "performance": { + "cpu_usage_percent": 25.5, // Использование CPU в процентах + "memory": { // Информация о памяти + "used_gb": 8.5, // Использованная память в ГБ + "free_gb": 7.5, // Свободная память в ГБ + "cached_gb": 2.0, // Кэшированная память в ГБ + "swap_used_gb": 0.5, // Использованный swap в ГБ + "pressure": "Normal" // Давление памяти + }, + "disk": { // Информация о диске + "read_bytes_per_sec": 1024000, // Скорость чтения в байт/с + "write_bytes_per_sec": 512000, // Скорость записи в байт/с + "read_ops_per_sec": 100, // Операций чтения в секунду + "write_ops_per_sec": 50 // Операций записи в секунду + }, + "network": { // Сетевая активность + "bytes_in_per_sec": 2048000, // Входящий трафик в байт/с + "bytes_out_per_sec": 1024000, // Исходящий трафик в байт/с + "packets_in_per_sec": 1000, // Входящих пакетов в секунду + "packets_out_per_sec": 800 // Исходящих пакетов в секунду + } + } +} +``` + +### Информация о приложениях + +```json +{ + "applications": { + "running_apps": 25, // Количество запущенных приложений + "total_apps": 150, // Общее количество приложений + "memory_intensive_apps": [ // Приложения с высоким потреблением памяти + { + "name": "Safari", // Имя приложения + "pid": 1234, // PID процесса + "memory_mb": 512, // Память в МБ + "cpu_percent": 15.5 // Использование CPU в процентах + } + ] + } +} +``` + +## Конфигурация + +### config.yaml + +```yaml +collectors: + macos: + enabled: true + type: exec + key: macos + interval: "60s" # 1 минута + timeout: "8s" + exec: "./collectors/macos" + platforms: [darwin] +``` + +### Переменные окружения + +- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 8s) + +## Требования + +### Системные требования + +- macOS система +- Доступ к системным командам +- Права на чтение системной информации + +### Команды + +Коллектор использует следующие команды (должны быть доступны): + +- `sysctl` - системные параметры +- `system_profiler` - профилировщик системы +- `ioreg` - реестр I/O +- `pmset` - управление питанием +- `networksetup` - настройки сети +- `system_profiler SPHardwareDataType` - информация о железе +- `system_profiler SPSoftwareDataType` - информация о ПО +- `system_profiler SPNetworkDataType` - информация о сети +- `system_profiler SPStorageDataType` - информация о хранилище + +## Примеры использования + +### Проверка работы коллектора + +```bash +# Запуск коллектора напрямую +./bin/agent/collectors/macos + +# Запуск через агент +make run +``` + +### Фильтрация данных + +```bash +# Информация о системе +./bin/agent/collectors/macos | jq '.system' + +# Информация о железе +./bin/agent/collectors/macos | jq '.hardware' + +# Информация о CPU +./bin/agent/collectors/macos | jq '.hardware.cpu' + +# Информация о памяти +./bin/agent/collectors/macos | jq '.hardware.memory' + +# Информация о хранилище +./bin/agent/collectors/macos | jq '.hardware.storage' + +# Сетевые интерфейсы +./bin/agent/collectors/macos | jq '.network.interfaces' + +# Wi-Fi информация +./bin/agent/collectors/macos | jq '.network.wifi' + +# Информация о батарее +./bin/agent/collectors/macos | jq '.battery' + +# Производительность +./bin/agent/collectors/macos | jq '.performance' + +# Использование CPU +./bin/agent/collectors/macos | jq '.performance.cpu_usage_percent' + +# Использование памяти +./bin/agent/collectors/macos | jq '.performance.memory' + +# Сетевая активность +./bin/agent/collectors/macos | jq '.performance.network' + +# Приложения +./bin/agent/collectors/macos | jq '.applications' + +# Приложения с высоким потреблением памяти +./bin/agent/collectors/macos | jq '.applications.memory_intensive_apps' +``` + +## Устранение неполадок + +### Частые проблемы + +1. **"No data collected"** + - Убедитесь, что система macOS + - Проверьте доступность системных команд + - Убедитесь в правильности прав доступа + +2. **"Permission denied"** + - Запустите с правами `sudo` + - Или предоставьте необходимые права + +3. **"Command not found"** + - Убедитесь, что системные команды доступны + - Проверьте PATH для команд + +### Отладка + +```bash +# Проверка системных команд +which sysctl system_profiler ioreg pmset networksetup + +# Проверка информации о системе +sysctl -n kern.hostname +sysctl -n kern.osproductversion +sysctl -n kern.osproductversion + +# Проверка информации о железе +system_profiler SPHardwareDataType + +# Проверка информации о ПО +system_profiler SPSoftwareDataType + +# Проверка информации о сети +system_profiler SPNetworkDataType + +# Проверка информации о хранилище +system_profiler SPStorageDataType + +# Проверка батареи +pmset -g batt + +# Проверка сетевых интерфейсов +networksetup -listallhardwareports +``` + +## Безопасность + +- Коллектор требует права на чтение системной информации +- Не передает пароли или секретные ключи +- Собирает только публичную информацию о системе +- Не выполняет привилегированные операции + +## Производительность + +- Время выполнения: ~2-8 секунд +- Интервал сбора: рекомендуется 1 минута (60s) +- Потребление ресурсов: минимальное +- Собирает только локальную информацию о системе + +## Совместимость + +- **macOS**: 10.15+ (Catalina и новее) +- **Архитектуры**: x86_64, ARM64 (Apple Silicon) +- **Модели**: MacBook, iMac, Mac Pro, Mac mini, Mac Studio +- **Чипы**: Intel, Apple M1, M1 Pro, M1 Max, M2, M2 Pro, M2 Max diff --git a/docs/collectors/proxnode.md b/docs/collectors/proxnode.md new file mode 100644 index 0000000..08646fb --- /dev/null +++ b/docs/collectors/proxnode.md @@ -0,0 +1,320 @@ +# Коллектор proxnode + +**Автор:** Сергей Антропов +**Сайт:** https://devops.org.ru + +## Описание + +Коллектор `proxnode` собирает подробную информацию о Proxmox ноде, включая системные ресурсы, сервисы, диски, сетевые интерфейсы и другую важную информацию о состоянии ноды. + +## Поддерживаемые платформы + +- **Linux**: Полная поддержка +- **macOS/Windows**: Не поддерживается (возвращает пустой JSON) + +## Собираемые данные + +### Основная информация о ноде + +```json +{ + "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 продукта +} +``` + +### Информация об операционной системе + +```json +{ + "os": { + "kernel": "Linux 5.15.108-1-pve", // Версия ядра + "pve_version": "7.4-3", // Версия Proxmox VE + "uptime_sec": 523423 // Время работы в секундах + } +} +``` + +### Информация о железе + +```json +{ + "hardware": { + "cpu_model": "Intel(R) Xeon(R) Gold 6226R", // Модель процессора + "cpu_cores": 32, // Количество ядер + "sockets": 2, // Количество сокетов + "threads": 64, // Количество потоков + "memory_total_mb": 262144 // Общая память в МБ + } +} +``` + +### Использование ресурсов + +```json +{ + "resources": { + "cpu_usage_percent": 25.3, // Использование CPU в процентах + "memory_used_mb": 98304, // Использованная память в МБ + "swap_used_mb": 512, // Использованный swap в МБ + "loadavg": [0.52, 0.61, 0.72] // Средняя нагрузка (1м, 5м, 15м) + } +} +``` + +### Сетевая информация + +```json +{ + "network": [ + { + "iface": "eth0", // Имя интерфейса + "mac": "52:54:00:12:34:56", // MAC адрес + "ip": "192.168.1.10", // IP адрес + "rx_bytes": 123456789, // Принято байт + "tx_bytes": 987654321, // Передано байт + "errors": 0 // Количество ошибок + }, + { + "iface": "vmbr0", // Имя интерфейса + "type": "bridge", // Тип интерфейса + "ip": "192.168.1.1" // IP адрес + } + ] +} +``` + +### Информация о дисках + +```json +{ + "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" // Статус + } + ] +} +``` + +### Статус сервисов + +```json +{ + "services": [ + {"name": "pve-cluster", "active": true}, // Сервис кластера + {"name": "pvedaemon", "active": true}, // Демон Proxmox + {"name": "pveproxy", "active": true}, // Прокси Proxmox + {"name": "corosync", "active": true} // Corosync + ] +} +``` + +### Информация о GPU + +```json +{ + "gpus": [ + { + "index": 0, // Индекс GPU + "model": "NVIDIA GeForce RTX 4090", // Модель GPU + "memory_total_mb": 24576, // Общая память в МБ + "memory_used_mb": 8192, // Использованная память в МБ + "utilization_percent": 45.5, // Утилизация в процентах + "temperature_c": 65.0 // Температура в градусах Цельсия + } + ] +} +``` + +## Конфигурация + +### config.yaml + +```yaml +collectors: + proxnode: + enabled: true + type: exec + key: proxnode + interval: "300s" # 5 минут + timeout: "30s" + exec: "./collectors/proxnode" + platforms: [linux] +``` + +### Переменные окружения + +- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 30s) + +## Требования + +### Системные требования + +- Proxmox VE нода +- Доступ к файлам конфигурации: + - `/etc/corosync/corosync.conf` (основной) + - `/etc/pve/corosync.conf` (альтернативный) + - `/var/lib/pve-cluster/corosync.conf` (альтернативный) + +### Команды + +Коллектор использует следующие команды (должны быть доступны): + +- `pveversion` - версия Proxmox VE +- `systemctl` - управление сервисами +- `ps` - список процессов +- `getent` - разрешение имен хостов +- `nvidia-smi` - информация о NVIDIA GPU +- `lspci` - информация о PCI устройствах (для AMD/Intel GPU) +- `df` - информация о дисках +- `cat /proc/loadavg` - средняя нагрузка +- `cat /proc/meminfo` - информация о памяти +- `cat /proc/stat` - статистика CPU +- `cat /proc/uptime` - время работы системы + +## Уникальные идентификаторы + +### node_uid +Генерируется на основе: +- `cluster_uuid` кластера +- `node_id` ноды + +Формула: `SHA256(cluster_uuid + ":" + node_id)[:16]` (первые 16 символов SHA256 хеша) + +### cluster_id +Генерируется на основе: +- `cluster_name` из corosync.conf +- `cluster_uuid` из corosync.conf + +Формула: `SHA256(cluster_name + ":" + cluster_uuid)[:16]` (первые 16 символов SHA256 хеша) + +Это обеспечивает уникальность идентификаторов для каждого кластера и ноды, даже если имена совпадают. + +## Примеры использования + +### Проверка работы коллектора + +```bash +# Запуск коллектора напрямую +./bin/agent/collectors/proxnode + +# Запуск через агент +make run +``` + +### Фильтрация данных + +```bash +# Основная информация о ноде +./bin/agent/collectors/proxnode | jq '.node_uid, .name, .ip' + +# Информация об ОС +./bin/agent/collectors/proxnode | jq '.os' + +# Информация о железе +./bin/agent/collectors/proxnode | jq '.hardware' + +# Использование ресурсов +./bin/agent/collectors/proxnode | jq '.resources' + +# Сетевая информация +./bin/agent/collectors/proxnode | jq '.network' + +# Информация о дисках +./bin/agent/collectors/proxnode | jq '.disks' + +# Статус сервисов +./bin/agent/collectors/proxnode | jq '.services' + +# Информация о GPU +./bin/agent/collectors/proxnode | jq '.gpus' + +# Только активные сервисы +./bin/agent/collectors/proxnode | jq '.services[] | select(.active == true)' + +# Диски с высокой утилизацией (>80%) +./bin/agent/collectors/proxnode | jq '.disks[] | select((.used_gb / .size_gb * 100) > 80)' +``` + +## Устранение неполадок + +### Частые проблемы + +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. **Пустые данные о ресурсах** + - Проверьте доступность системных команд + - Убедитесь в правильности конфигурации системы + +### Отладка + +```bash +# Проверка доступности команд +which pveversion systemctl ps getent nvidia-smi lspci df + +# Проверка файлов конфигурации +ls -la /etc/corosync/corosync.conf /etc/pve/corosync.conf + +# Проверка статуса сервисов +systemctl status pve-cluster corosync pveproxy pvedaemon + +# Проверка системных ресурсов +cat /proc/loadavg /proc/meminfo /proc/stat /proc/uptime + +# Проверка дисков +df -h + +# Проверка GPU +nvidia-smi +``` + +## Безопасность + +- Коллектор требует права на чтение системных файлов конфигурации +- Не передает пароли или секретные ключи +- Собирает только публичную информацию о ноде +- Не выполняет привилегированные операции + +## Производительность + +- Время выполнения: ~5-15 секунд +- Интервал сбора: рекомендуется 5 минут (300s) +- Потребление ресурсов: минимальное +- Собирает только локальную информацию о ноде + +## Совместимость + +- **Proxmox VE**: 6.0+ +- **Ноды**: все типы нод Proxmox VE +- **Диски**: все типы устройств (sda, nvme, vda и др.) +- **Сети**: все типы интерфейсов (eth, ens, enp, vmbr и др.) +- **GPU**: NVIDIA (через nvidia-smi), AMD/Intel (через lspci) diff --git a/docs/collectors/proxvms.md b/docs/collectors/proxvms.md new file mode 100644 index 0000000..58d2533 --- /dev/null +++ b/docs/collectors/proxvms.md @@ -0,0 +1,386 @@ +# Коллектор proxvms + +**Автор:** Сергей Антропов +**Сайт:** https://devops.org.ru + +## Описание + +Коллектор `proxvms` собирает подробную информацию о виртуальных машинах и LXC контейнерах в Proxmox кластере. Включает полную конфигурацию каждой VM/контейнера, структурированные данные о сетевых интерфейсах, дисковых устройствах, IP конфигурациях и другую важную информацию. + +## Поддерживаемые платформы + +- **Linux**: Полная поддержка +- **macOS/Windows**: Не поддерживается (возвращает пустой JSON) + +## Собираемые данные + +### Основная информация о кластере + +```json +{ + "cluster": { + "cluster_name": "production-cluster", // Имя кластера + "cluster_uid": "a1b2c3d4e5f67890", // Уникальный ID кластера (SHA256, 16 символов) + "cluster_uuid": "12345678-1234-1234-1234-123456789abc", // UUID кластера + "version": "8.1.4" // Версия Proxmox VE + } +} +``` + +### Информация о виртуальных машинах и контейнерах + +```json +{ + "vms": [ + { + "vmid": 100, // ID виртуальной машины/контейнера + "name": "web-server", // Имя VM/контейнера + "status": "running", // Статус (running, stopped, suspended) + "type": "QEMU", // Тип: QEMU или LXC + "node_name": "pve1", // Имя ноды + "cluster_uid": "a1b2c3d4e5f67890", // ID кластера + "node_uid": "d8b7a93c2f0e4f16", // ID ноды + "machine_id": "pc-i440fx-7.2", // Machine ID + "machine_uid": "f3e2d1c0b9a8f7e6", // Уникальный ID машины (SHA256, 16 символов) + "is_template": false, // Является ли шаблоном + "cpu_type": "kvm64", // Тип CPU + "boot_disk": "scsi0", // Загрузочный диск + "resources": { // Ресурсы + "memory_mb": 4096, // Память в МБ + "max_memory_mb": 8192, // Максимальная память в МБ + "cpu_cores": 4, // Количество ядер CPU + "max_disk_gb": 100 // Максимальный размер диска в ГБ + }, + "config": { // Полная конфигурация + "description_parsed": { // Парсированный JSON из description + "vm_name": "web-server", + "description": "Веб-сервер для продакшена", + "responsible": "Иван Петров", + "creation_date": "01.01.2024", + "deletion_date": "01.01.2025" + }, + "network": { // Сетевые интерфейсы + "net0": { + "bridge": "vmbr0", // Мост + "virtio": "52:54:00:12:34:56", // MAC адрес + "ip": { // IP конфигурация + "ip": "192.168.1.100", // IP адрес + "mask": "255.255.255.0", // Маска подсети + "mask_cidr": "/24", // Маска в формате CIDR + "gw": "192.168.1.1" // Шлюз + } + } + }, + "ipconfig": { // IP конфигурации + "ipconfig0": { + "ip": { + "ip": "192.168.1.100", + "mask": "255.255.255.0", + "mask_cidr": "/24", + "gw": "192.168.1.1" + } + } + }, + "scsi": { // SCSI устройства + "scsi0": { + "pool": "local-lvm", // Пул хранения + "pool_disk": "vm-100-disk-0", // Диск в пуле + "pool_disk_size": "50G", // Размер диска в пуле + "aio": "threads", // Асинхронный I/O + "cache": "writeback", // Кэширование + "discard": "on", // Поддержка discard + "enable": true, // Включено + "iothread": "1" // I/O поток + } + }, + "ide": { // IDE устройства + "ide2": { + "pool": "local", // Пул хранения + "pool_disk": "vm-100-cloudinit", // Диск в пуле + "media": "cdrom", // Тип носителя + "enable": true // Включено + } + } + } + }, + { + "vmid": 200, + "name": "db-container", + "status": "running", + "type": "LXC", // LXC контейнер + "node_name": "pve1", + "cluster_uid": "a1b2c3d4e5f67890", + "node_uid": "d8b7a93c2f0e4f16", + "machine_id": "db-container", + "machine_uid": "a1b2c3d4e5f67890", + "is_template": false, + "os_template": "ubuntu-22.04-standard_22.04-1_amd64.tar.zst", + "resources": { + "memory_mb": 2048, + "max_memory_mb": 4096, + "cpu_cores": 2, + "max_disk_gb": 20 + }, + "config": { + "description_parsed": { + "vm_name": "db-container", + "description": "Контейнер базы данных", + "responsible": "Мария Сидорова" + }, + "network": { + "net0": { + "bridge": "vmbr1", + "hwaddr": "02:00:00:00:00:01", + "ip": { + "ip": "10.0.0.100", + "mask": "255.255.255.0", + "mask_cidr": "/24", + "gw": "10.0.0.1" + }, + "name": "eth0", + "tag": "100", + "type": "veth" + } + }, + "rootfs": { // Корневая файловая система LXC + "pool": "local-lvm", + "pool_disk": "vm-200-disk-0", + "pool_disk_size": "20G", + "enable": true + }, + "mp": { // Точки монтирования LXC + "mp0": { + "pool": "nfs-storage", + "pool_disk": "vm-200-disk-1", + "pool_disk_size": "100G", + "mp": "/var/lib/postgresql", // Точка монтирования + "backup": "1", // Включен бэкап + "enable": true + } + } + } + } + ] +} +``` + +## Особенности парсинга + +### Структурированные данные + +Коллектор автоматически парсит и структурирует следующие типы конфигураций: + +1. **Сетевые интерфейсы** (`net0`, `net1`, `netX`) + - Парсит строки типа `bridge=vmbr0,virtio=52:54:00:12:34:56` + - Извлекает IP адреса с масками подсети + - Включает шлюз в секцию IP + +2. **IP конфигурации** (`ipconfig0`, `ipconfig1`, `ipconfigX`) + - Парсит IP адреса с масками в формате CIDR + - Конвертирует маски в формат 255.255.255.0 + - Включает шлюз в секцию IP + +3. **SCSI устройства** (`scsi0`, `scsi1`, `scsiX`) + - Парсит пулы и диски в формате `pool:disk` + - Переименовывает `size` в `pool_disk_size` + - Извлекает все параметры конфигурации + +4. **IDE устройства** (`ide0`, `ide1`, `ide2`, `ideX`) + - Аналогично SCSI устройствам + - Поддерживает различные типы носителей + +5. **LXC устройства** (`rootfs`, `mp0`, `mp1`, `mpX`) + - Парсит корневую файловую систему + - Обрабатывает точки монтирования + - Извлекает параметры пулов и дисков + +6. **Описания** (`description`) + - Парсит JSON из поля description + - Переводит русские ключи на английский + - Удаляет оригинальное поле при успешном парсинге + +### Удаление дублирования + +- Если парсинг прошел успешно, оригинальные поля удаляются +- Если парсинг не удался, оригинальные поля остаются +- Это обеспечивает чистоту данных без потери информации + +## Конфигурация + +### config.yaml + +```yaml +collectors: + proxvms: + enabled: true + type: exec + key: proxvms + interval: "1800s" # 30 минут + timeout: "300s" # 5 минут + exec: "./collectors/proxvms" + platforms: [linux] +``` + +### Переменные окружения + +- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 30s) + +## Требования + +### Системные требования + +- Proxmox VE кластер +- Доступ к файлам конфигурации: + - `/etc/corosync/corosync.conf` (основной) + - `/etc/pve/corosync.conf` (альтернативный) + - `/var/lib/pve-cluster/corosync.conf` (альтернативный) + +### Команды + +Коллектор использует следующие команды (должны быть доступны): + +- `pvesh` - утилита командной строки Proxmox VE +- `pveversion` - версия Proxmox VE + +## Уникальные идентификаторы + +### cluster_uid +Генерируется на основе: +- `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 хеша) + +### machine_uid +Генерируется на основе: +- Для QEMU VM: UUID из `smbios1` или `machine_id` +- Для LXC контейнеров: `hostname` или `machine_id` + +Формула: `SHA256(machine_identifier)[:16]` (первые 16 символов SHA256 хеша) + +## Примеры использования + +### Проверка работы коллектора + +```bash +# Запуск коллектора напрямую +./bin/agent/collectors/proxvms + +# Запуск через агент +make run +``` + +### Фильтрация данных + +```bash +# Информация о кластере +./bin/agent/collectors/proxvms | jq '.cluster' + +# Все виртуальные машины +./bin/agent/collectors/proxvms | jq '.vms[] | select(.type == "QEMU")' + +# Все LXC контейнеры +./bin/agent/collectors/proxvms | jq '.vms[] | select(.type == "LXC")' + +# Только запущенные VM +./bin/agent/collectors/proxvms | jq '.vms[] | select(.status == "running")' + +# VM с высоким использованием памяти (>4GB) +./bin/agent/collectors/proxvms | jq '.vms[] | select(.resources.memory_mb > 4096)' + +# VM с определенным именем +./bin/agent/collectors/proxvms | jq '.vms[] | select(.name == "web-server")' + +# Сетевые конфигурации +./bin/agent/collectors/proxvms | jq '.vms[] | select(.config.network != null) | {name, network: .config.network}' + +# SCSI устройства +./bin/agent/collectors/proxvms | jq '.vms[] | select(.config.scsi != null) | {name, scsi: .config.scsi}' + +# IP адреса с масками +./bin/agent/collectors/proxvms | jq '.vms[] | select(.config.network != null) | {name, ip: .config.network.net0.ip}' + +# Парсированные описания +./bin/agent/collectors/proxvms | jq '.vms[] | select(.config.description_parsed != null) | {name, description: .config.description_parsed}' + +# LXC с точками монтирования +./bin/agent/collectors/proxvms | jq '.vms[] | select(.type == "LXC" and .config.mp != null) | {name, mp: .config.mp}' + +# VM с определенным пулом хранения +./bin/agent/collectors/proxvms | jq '.vms[] | select(.config.scsi.scsi0.pool == "local-lvm")' +``` + +## Устранение неполадок + +### Частые проблемы + +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. **Пустые данные о VM/контейнерах** + - Проверьте доступность команды pvesh + - Убедитесь в правильности конфигурации кластера + - Проверьте права доступа к Proxmox API + +### Отладка + +```bash +# Проверка доступности команд +which pvesh pveversion + +# Проверка файлов конфигурации +ls -la /etc/corosync/corosync.conf /etc/pve/corosync.conf + +# Проверка статуса сервисов +systemctl status pve-cluster corosync pveproxy pvedaemon + +# Проверка VM через pvesh +pvesh get /nodes --output-format json + +# Проверка конкретной ноды +pvesh get /nodes/pve1/qemu --output-format json +pvesh get /nodes/pve1/lxc --output-format json + +# Проверка конфигурации VM +pvesh get /nodes/pve1/qemu/100/config --output-format json +``` + +## Безопасность + +- Коллектор требует права на чтение системных файлов конфигурации +- Не передает пароли или секретные ключи +- Собирает только публичную информацию о VM/контейнерах +- Не выполняет привилегированные операции + +## Производительность + +- Время выполнения: ~30-300 секунд (зависит от количества VM/контейнеров) +- Интервал сбора: рекомендуется 30 минут (1800s) +- Потребление ресурсов: минимальное +- Собирает информацию только с локальной ноды + +## Совместимость + +- **Proxmox VE**: 6.0+ +- **VM**: QEMU виртуальные машины +- **Контейнеры**: LXC контейнеры +- **Хранилища**: все поддерживаемые типы (local, nfs, ceph, lvm, zfs и др.) +- **Сети**: все типы интерфейсов (eth, ens, enp, vmbr и др.) +- **Диски**: все типы устройств (scsi, ide, virtio и др.) diff --git a/docs/collectors/sensors.md b/docs/collectors/sensors.md new file mode 100644 index 0000000..ec7840b --- /dev/null +++ b/docs/collectors/sensors.md @@ -0,0 +1,301 @@ +# Коллектор sensors + +**Автор:** Сергей Антропов +**Сайт:** https://devops.org.ru + +## Описание + +Коллектор `sensors` собирает данные с датчиков температуры, напряжения и вентиляторов через lm-sensors и IPMI. Предоставляет детальную информацию о состоянии системы и ее компонентов. + +## Поддерживаемые платформы + +- **Linux**: Полная поддержка +- **macOS/Windows**: Не поддерживается (возвращает пустой JSON) + +## Собираемые данные + +### Информация о датчиках + +```json +{ + "sensors": { + "temperature": [ // Датчики температуры + { + "name": "coretemp-isa-0000", // Имя датчика + "adapter": "ISA adapter", // Адаптер + "sensors": [ + { + "label": "Core 0", // Метка датчика + "value": 45.0, // Значение в градусах Цельсия + "unit": "°C", // Единица измерения + "status": "ok" // Статус датчика + }, + { + "label": "Core 1", + "value": 47.0, + "unit": "°C", + "status": "ok" + } + ] + }, + { + "name": "nvidia-pci-0100", + "adapter": "PCI adapter", + "sensors": [ + { + "label": "GPU Core", + "value": 65.0, + "unit": "°C", + "status": "ok" + } + ] + } + ], + "voltage": [ // Датчики напряжения + { + "name": "coretemp-isa-0000", + "adapter": "ISA adapter", + "sensors": [ + { + "label": "Vcore", + "value": 1.2, + "unit": "V", + "status": "ok" + } + ] + } + ], + "fan": [ // Датчики вентиляторов + { + "name": "nct6775-isa-0290", + "adapter": "ISA adapter", + "sensors": [ + { + "label": "fan1", + "value": 1200, + "unit": "RPM", + "status": "ok" + }, + { + "label": "fan2", + "value": 800, + "unit": "RPM", + "status": "ok" + } + ] + } + ] + } +} +``` + +### IPMI информация + +```json +{ + "ipmi": { + "available": true, // Доступен ли IPMI + "temperature": [ // IPMI датчики температуры + { + "name": "CPU Temp", + "value": 45.0, + "unit": "°C", + "status": "ok" + }, + { + "name": "System Temp", + "value": 35.0, + "unit": "°C", + "status": "ok" + } + ], + "voltage": [ // IPMI датчики напряжения + { + "name": "12V", + "value": 12.1, + "unit": "V", + "status": "ok" + }, + { + "name": "5V", + "value": 5.0, + "unit": "V", + "status": "ok" + } + ], + "fan": [ // IPMI датчики вентиляторов + { + "name": "FAN1", + "value": 1200, + "unit": "RPM", + "status": "ok" + } + ] + } +} +``` + +### Статистика + +```json +{ + "stats": { + "temperature_sensors": 8, // Количество датчиков температуры + "voltage_sensors": 4, // Количество датчиков напряжения + "fan_sensors": 3, // Количество датчиков вентиляторов + "ipmi_available": true, // Доступен ли IPMI + "ipmi_temperature_sensors": 2, // Количество IPMI датчиков температуры + "max_temperature": 65.0, // Максимальная температура + "min_temperature": 25.0, // Минимальная температура + "avg_temperature": 42.5, // Средняя температура + "max_fan_speed": 1200, // Максимальная скорость вентилятора + "min_fan_speed": 800, // Минимальная скорость вентилятора + "avg_fan_speed": 1000 // Средняя скорость вентилятора + } +} +``` + +## Конфигурация + +### config.yaml + +```yaml +collectors: + sensors: + enabled: true + type: exec + key: sensors + interval: "60s" # 1 минута + timeout: "8s" + exec: "./collectors/sensors" + platforms: [linux] +``` + +### Переменные окружения + +- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 8s) + +## Требования + +### Системные требования + +- Linux система с датчиками +- Установленный lm-sensors +- Опционально: IPMI tools для серверного оборудования +- Права на чтение информации о датчиках + +### Команды + +Коллектор использует следующие команды (должны быть доступны): + +- `sensors` - утилита lm-sensors +- `ipmitool` - утилита IPMI (опционально) +- `sensors-detect` - обнаружение датчиков + +## Примеры использования + +### Проверка работы коллектора + +```bash +# Запуск коллектора напрямую +./bin/agent/collectors/sensors + +# Запуск через агент +make run +``` + +### Фильтрация данных + +```bash +# Все датчики +./bin/agent/collectors/sensors | jq '.sensors' + +# Только температура +./bin/agent/collectors/sensors | jq '.sensors.temperature' + +# Только напряжение +./bin/agent/collectors/sensors | jq '.sensors.voltage' + +# Только вентиляторы +./bin/agent/collectors/sensors | jq '.sensors.fan' + +# IPMI информация +./bin/agent/collectors/sensors | jq '.ipmi' + +# Статистика +./bin/agent/collectors/sensors | jq '.stats' + +# Максимальная температура +./bin/agent/collectors/sensors | jq '.stats.max_temperature' + +# Средняя температура +./bin/agent/collectors/sensors | jq '.stats.avg_temperature' + +# Датчики с высокой температурой (>60°C) +./bin/agent/collectors/sensors | jq '.sensors.temperature[].sensors[] | select(.value > 60)' + +# Медленные вентиляторы (<1000 RPM) +./bin/agent/collectors/sensors | jq '.sensors.fan[].sensors[] | select(.value < 1000)' +``` + +## Устранение неполадок + +### Частые проблемы + +1. **"No sensors found"** + - Убедитесь, что lm-sensors установлен + - Запустите `sensors-detect` для обнаружения датчиков + - Проверьте права доступа к датчикам + +2. **"Permission denied"** + - Запустите с правами `sudo` + - Или добавьте пользователя в группу `sensors` + +3. **"IPMI not available"** + - Установите ipmitool + - Проверьте доступность IPMI интерфейса + - Убедитесь в правильности конфигурации IPMI + +### Отладка + +```bash +# Проверка установки lm-sensors +sensors --version + +# Проверка доступности датчиков +sensors + +# Обнаружение датчиков +sudo sensors-detect + +# Проверка IPMI +ipmitool sensor list + +# Проверка прав доступа +ls -la /sys/class/hwmon/ + +# Проверка модулей ядра +lsmod | grep -i sensor +``` + +## Безопасность + +- Коллектор требует права на чтение информации о датчиках +- Не передает пароли или секретные ключи +- Собирает только публичную информацию о датчиках +- Не выполняет привилегированные операции + +## Производительность + +- Время выполнения: ~2-8 секунд +- Интервал сбора: рекомендуется 1 минута (60s) +- Потребление ресурсов: минимальное +- Собирает только локальную информацию о датчиках + +## Совместимость + +- **Датчики**: CPU, GPU, материнская плата, диски +- **Типы**: температура, напряжение, вентиляторы, ток +- **Интерфейсы**: lm-sensors, IPMI +- **Linux**: все дистрибутивы +- **Оборудование**: серверы, рабочие станции, ноутбуки diff --git a/docs/collectors/system.md b/docs/collectors/system.md new file mode 100644 index 0000000..6f1c6c0 --- /dev/null +++ b/docs/collectors/system.md @@ -0,0 +1,357 @@ +# Коллектор system + +**Автор:** Сергей Антропов +**Сайт:** https://devops.org.ru + +## Описание + +Коллектор `system` собирает базовые системные метрики Linux системы, включая информацию о CPU, памяти, сетевых интерфейсах, дисках, синхронизации времени и доступных обновлениях. Предоставляет комплексный обзор состояния системы. + +## Поддерживаемые платформы + +- **Linux**: Полная поддержка +- **macOS/Windows**: Не поддерживается (возвращает пустой JSON) + +## Собираемые данные + +### Информация о CPU + +```json +{ + "cpu": { + "usage_percent": 25.3, // Использование CPU в процентах + "load_avg": { // Средняя нагрузка системы + "1min": 0.52, // Загрузка за 1 минуту + "5min": 0.61, // Загрузка за 5 минут + "15min": 0.72 // Загрузка за 15 минут + }, + "cores": 8, // Количество ядер CPU + "model": "Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz" // Модель процессора + } +} +``` + +### Информация о памяти (RAM) + +```json +{ + "ram": { + "total_mb": 16384, // Общая память в МБ + "used_mb": 8192, // Использованная память в МБ + "free_mb": 8192, // Свободная память в МБ + "available_mb": 10240, // Доступная память в МБ + "cached_mb": 2048, // Кэшированная память в МБ + "buffers_mb": 512, // Буферы в МБ + "usage_percent": 50.0 // Использование памяти в процентах + } +} +``` + +### Информация о swap + +```json +{ + "swap": { + "total_mb": 2048, // Общий размер swap в МБ + "used_mb": 256, // Использованный swap в МБ + "free_mb": 1792, // Свободный swap в МБ + "usage_percent": 12.5 // Использование swap в процентах + } +} +``` + +### Сетевые интерфейсы + +```json +{ + "network": [ + { + "interface": "eth0", // Имя интерфейса + "rx_bytes": 1234567890, // Принято байт + "tx_bytes": 9876543210, // Передано байт + "rx_packets": 1234567, // Принято пакетов + "tx_packets": 9876543, // Передано пакетов + "rx_errors": 0, // Ошибки приема + "tx_errors": 0, // Ошибки передачи + "rx_dropped": 0, // Отброшено при приеме + "tx_dropped": 0, // Отброшено при передаче + "speed_mbps": 1000, // Скорость в Мбит/с + "duplex": "full", // Дуплекс (full/half) + "status": "up" // Статус интерфейса + }, + { + "interface": "lo", + "rx_bytes": 123456, + "tx_bytes": 123456, + "rx_packets": 1234, + "tx_packets": 1234, + "rx_errors": 0, + "tx_errors": 0, + "rx_dropped": 0, + "tx_dropped": 0, + "speed_mbps": 0, + "duplex": "unknown", + "status": "up" + } + ] +} +``` + +### Информация о дисках + +```json +{ + "disks": [ + { + "device": "/dev/sda", // Устройство + "mountpoint": "/", // Точка монтирования + "filesystem": "ext4", // Тип файловой системы + "total_gb": 100.0, // Общий размер в ГБ + "used_gb": 50.0, // Использовано в ГБ + "free_gb": 45.0, // Свободно в ГБ + "usage_percent": 52.6, // Использование в процентах + "inodes_total": 6553600, // Общее количество inode + "inodes_used": 3276800, // Использовано inode + "inodes_free": 3276800, // Свободно inode + "inodes_usage_percent": 50.0 // Использование inode в процентах + }, + { + "device": "/dev/sdb", + "mountpoint": "/home", + "filesystem": "ext4", + "total_gb": 500.0, + "used_gb": 200.0, + "free_gb": 275.0, + "usage_percent": 42.1, + "inodes_total": 32768000, + "inodes_used": 16384000, + "inodes_free": 16384000, + "inodes_usage_percent": 50.0 + } + ] +} +``` + +### Синхронизация времени + +```json +{ + "time_sync": { + "ntp_synchronized": true, // Синхронизирован ли NTP + "ntp_service": "systemd-timesyncd", // Сервис NTP + "ntp_status": "active", // Статус сервиса NTP + "timezone": "Europe/Moscow", // Часовой пояс + "drift_seconds": 0.001 // Дрейф времени в секундах + } +} +``` + +### Доступные обновления + +```json +{ + "updates": { + "package_manager": "apt", // Менеджер пакетов + "updates_available": 15, // Количество доступных обновлений + "security_updates": 3, // Количество обновлений безопасности + "upgradeable_packages": [ // Список пакетов для обновления + { + "name": "linux-image-generic", + "current_version": "5.4.0-74.83", + "available_version": "5.4.0-74.84", + "is_security": true + }, + { + "name": "openssl", + "current_version": "1.1.1f-1ubuntu2.13", + "available_version": "1.1.1f-1ubuntu2.14", + "is_security": true + } + ] + } +} +``` + +## Конфигурация + +### config.yaml + +```yaml +collectors: + system: + enabled: true + type: exec + key: system + interval: "30s" # 30 секунд + timeout: "8s" + exec: "./collectors/system" + platforms: [linux] +``` + +### Переменные окружения + +- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 8s) + +## Требования + +### Системные требования + +- Linux система +- Доступ к файлам `/proc/*` +- Права на чтение системной информации + +### Команды + +Коллектор использует следующие команды (должны быть доступны): + +- `df` - информация о дисках +- `free` - информация о памяти +- `uptime` - время работы системы +- `systemctl` - управление сервисами (для NTP) +- `timedatectl` - управление временем +- `apt list --upgradable` - список обновлений (Ubuntu/Debian) +- `yum check-update` - список обновлений (RHEL/CentOS) +- `dnf check-update` - список обновлений (Fedora) + +## Примеры использования + +### Проверка работы коллектора + +```bash +# Запуск коллектора напрямую +./bin/agent/collectors/system + +# Запуск через агент +make run +``` + +### Фильтрация данных + +```bash +# Информация о CPU +./bin/agent/collectors/system | jq '.cpu' + +# Использование CPU +./bin/agent/collectors/system | jq '.cpu.usage_percent' + +# Средняя нагрузка +./bin/agent/collectors/system | jq '.cpu.load_avg' + +# Информация о памяти +./bin/agent/collectors/system | jq '.ram' + +# Использование памяти +./bin/agent/collectors/system | jq '.ram.usage_percent' + +# Информация о swap +./bin/agent/collectors/system | jq '.swap' + +# Сетевые интерфейсы +./bin/agent/collectors/system | jq '.network' + +# Трафик по интерфейсам +./bin/agent/collectors/system | jq '.network[] | {interface, rx_bytes, tx_bytes}' + +# Информация о дисках +./bin/agent/collectors/system | jq '.disks' + +# Диски с высокой утилизацией (>80%) +./bin/agent/collectors/system | jq '.disks[] | select(.usage_percent > 80)' + +# Синхронизация времени +./bin/agent/collectors/system | jq '.time_sync' + +# Доступные обновления +./bin/agent/collectors/system | jq '.updates' + +# Количество обновлений +./bin/agent/collectors/system | jq '.updates.updates_available' + +# Обновления безопасности +./bin/agent/collectors/system | jq '.updates.security_updates' + +# Список пакетов для обновления +./bin/agent/collectors/system | jq '.updates.upgradeable_packages' +``` + +## Устранение неполадок + +### Частые проблемы + +1. **"no data"** + - Проверьте доступность файлов `/proc/*` + - Убедитесь в правильности прав доступа + - Проверьте доступность системных команд + +2. **Пустые данные о CPU** + - Проверьте доступность `/proc/stat` + - Убедитесь в корректности формата файла + +3. **Пустые данные о памяти** + - Проверьте доступность `/proc/meminfo` + - Убедитесь в корректности формата файла + +4. **Пустые данные о сети** + - Проверьте доступность `/proc/net/dev` + - Убедитесь в корректности формата файла + +5. **Пустые данные о дисках** + - Проверьте доступность команды `df` + - Убедитесь в правильности прав доступа + +6. **Пустые данные об обновлениях** + - Проверьте доступность менеджера пакетов + - Убедитесь в правильности прав доступа + +### Отладка + +```bash +# Проверка доступности файлов +ls -la /proc/stat /proc/meminfo /proc/net/dev /proc/loadavg + +# Проверка доступности команд +which df free uptime systemctl timedatectl + +# Проверка информации о CPU +cat /proc/stat | head -1 + +# Проверка информации о памяти +cat /proc/meminfo | head -10 + +# Проверка сетевых интерфейсов +cat /proc/net/dev + +# Проверка дисков +df -h + +# Проверка времени +timedatectl status + +# Проверка обновлений (Ubuntu/Debian) +apt list --upgradable + +# Проверка обновлений (RHEL/CentOS) +yum check-update +``` + +## Безопасность + +- Коллектор требует права на чтение системных файлов +- Не передает пароли или секретные ключи +- Собирает только публичную информацию о системе +- Не выполняет привилегированные операции + +## Производительность + +- Время выполнения: ~2-8 секунд +- Интервал сбора: рекомендуется 30 секунд +- Потребление ресурсов: минимальное +- Собирает только локальную информацию о системе + +## Совместимость + +- **Linux**: все дистрибутивы +- **Файловые системы**: ext4, xfs, btrfs, zfs и др. +- **Менеджеры пакетов**: apt, yum, dnf, pacman и др. +- **Сетевые интерфейсы**: eth, ens, enp, wlan и др. +- **CPU**: все архитектуры (x86_64, ARM, etc.) diff --git a/docs/collectors/uptime.md b/docs/collectors/uptime.md new file mode 100644 index 0000000..9aaf0fb --- /dev/null +++ b/docs/collectors/uptime.md @@ -0,0 +1,166 @@ +# Коллектор uptime + +**Автор:** Сергей Антропов +**Сайт:** https://devops.org.ru + +## Описание + +Коллектор `uptime` собирает информацию о времени работы системы. Предоставляет время работы в секундах и в человекочитаемом формате. + +## Поддерживаемые платформы + +- **Linux**: Полная поддержка +- **macOS**: Полная поддержка +- **Windows**: Не поддерживается (возвращает пустой JSON) + +## Собираемые данные + +### Информация о времени работы + +```json +{ + "collector_name": "uptime", // Имя коллектора + "seconds": 86400, // Время работы в секундах + "human": "1d 0h 0m 0s", // Время работы в человекочитаемом формате + "execution_time_ms": 5, // Время выполнения коллектора в миллисекундах + "execution_time_seconds": 0.005 // Время выполнения коллектора в секундах +} +``` + +### Формат человекочитаемого времени + +Время работы отображается в формате: +- `d` - дни +- `h` - часы +- `m` - минуты +- `s` - секунды + +Примеры: +- `0d 0h 5m 30s` - 5 минут 30 секунд +- `0d 2h 15m 45s` - 2 часа 15 минут 45 секунд +- `1d 3h 20m 10s` - 1 день 3 часа 20 минут 10 секунд +- `7d 12h 0m 0s` - 7 дней 12 часов + +## Конфигурация + +### config.yaml + +```yaml +collectors: + uptime: + enabled: true + type: exec + key: uptime + interval: "60s" # 1 минута + timeout: "5s" + exec: "./collectors/uptime" + platforms: [linux, darwin] +``` + +### Переменные окружения + +- `COLLECTOR_TIMEOUT`: Таймаут выполнения коллектора (по умолчанию 5s) + +## Требования + +### Системные требования + +- Linux или macOS система +- Доступ к системным файлам времени работы +- Права на чтение системной информации + +### Команды + +Коллектор использует следующие команды (должны быть доступны): + +- **Linux**: чтение `/proc/uptime` +- **macOS**: команда `uptime` или чтение системных файлов + +## Примеры использования + +### Проверка работы коллектора + +```bash +# Запуск коллектора напрямую +./bin/agent/collectors/uptime + +# Запуск через агент +make run +``` + +### Фильтрация данных + +```bash +# Время работы в секундах +./bin/agent/collectors/uptime | jq '.seconds' + +# Время работы в человекочитаемом формате +./bin/agent/collectors/uptime | jq '.human' + +# Полная информация +./bin/agent/collectors/uptime | jq '.' + +# Время выполнения коллектора +./bin/agent/collectors/uptime | jq '.execution_time_ms' +``` + +## Устранение неполадок + +### Частые проблемы + +1. **"No data collected"** + - Убедитесь, что система Linux или macOS + - Проверьте доступность системных файлов + - Убедитесь в правильности прав доступа + +2. **"Permission denied"** + - Проверьте права доступа к системным файлам + - Убедитесь, что файлы `/proc/uptime` доступны для чтения + +3. **"Invalid uptime data"** + - Проверьте корректность системных файлов + - Убедитесь в правильности формата данных + +### Отладка + +```bash +# Проверка времени работы (Linux) +cat /proc/uptime + +# Проверка времени работы (macOS) +uptime + +# Проверка прав доступа (Linux) +ls -la /proc/uptime + +# Проверка системной информации +uname -a +``` + +## Безопасность + +- Коллектор требует права на чтение системных файлов +- Не передает пароли или секретные ключи +- Собирает только публичную информацию о времени работы +- Не выполняет привилегированные операции + +## Производительность + +- Время выполнения: ~1-5 миллисекунд +- Интервал сбора: рекомендуется 1 минута (60s) +- Потребление ресурсов: минимальное +- Собирает только локальную информацию о времени работы + +## Совместимость + +- **Linux**: все дистрибутивы +- **macOS**: все версии +- **Архитектуры**: x86_64, ARM64 +- **Системы**: серверы, рабочие станции, ноутбуки + +## Особенности + +- **Точность**: время работы измеряется с точностью до секунды +- **Формат**: поддерживает как числовой, так и человекочитаемый формат +- **Производительность**: один из самых быстрых коллекторов +- **Надежность**: минимальная вероятность ошибок diff --git a/src/collectors/proxvms/main.go b/src/collectors/proxvms/main.go new file mode 100644 index 0000000..a06fd3c --- /dev/null +++ b/src/collectors/proxvms/main.go @@ -0,0 +1,54 @@ +// +build linux + +package main + +// Автор: Сергей Антропов, сайт: https://devops.org.ru +// Коллектор proxvms - собирает информацию о виртуальных машинах и контейнерах Proxmox + +import ( + "context" + "encoding/json" + "fmt" + "os" + "strings" + "time" +) + +func main() { + // Засекаем время начала выполнения + startTime := time.Now() + + // Таймаут можно переопределить окружением COLLECTOR_TIMEOUT + timeout := parseDurationOr("COLLECTOR_TIMEOUT", 30*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + data, err := collectProxVMs(ctx) + if err != nil || data == nil { + fmt.Println("{}") + return + } + + // Вычисляем время выполнения + executionTime := time.Since(startTime) + + // Добавляем время выполнения в результат + data["execution_time_ms"] = executionTime.Milliseconds() + data["execution_time_seconds"] = executionTime.Seconds() + + 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 +} diff --git a/src/collectors/proxvms/proxvms_linux.go b/src/collectors/proxvms/proxvms_linux.go new file mode 100644 index 0000000..973918b --- /dev/null +++ b/src/collectors/proxvms/proxvms_linux.go @@ -0,0 +1,989 @@ +//go:build linux + +package main + +// Автор: Сергей Антропов, сайт: https://devops.org.ru +// Коллектор proxvms для Linux - собирает информацию о виртуальных машинах и контейнерах Proxmox + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "os" + "os/exec" + "strconv" + "strings" + "sync" +) + +// Структуры для работы с API Proxmox +type ClusterInfo struct { + ID string `json:"id"` + Name string `json:"name"` + Nodes int `json:"nodes"` + Quorate int `json:"quorate"` + Type string `json:"type"` + Version int `json:"version"` +} + +type ClusterStatus struct { + ID string `json:"id"` + IP string `json:"ip"` + Level string `json:"level"` + Local int `json:"local"` + Name string `json:"name"` + NodeID int `json:"nodeid"` + Online int `json:"online"` + Type string `json:"type"` +} + +type VM struct { + Vmid interface{} `json:"vmid"` // Может быть int или string + Name string `json:"name"` + Status string `json:"status"` + Mem int64 `json:"mem"` + MaxMem int64 `json:"maxmem"` + Cores int `json:"cpus"` + MaxDisk int64 `json:"maxdisk"` + Type string `json:"type"` +} + +// collectProxVMs собирает информацию о виртуальных машинах и контейнерах +func collectProxVMs(ctx context.Context) (map[string]interface{}, error) { + // Получаем имя локального сервера + hostname := runSimple("hostname") + debugLog("Local hostname: %s", hostname) + + // Получаем статус кластера для получения информации о кластере + clusterStatRaw, err := runPvesh("/cluster/status") + if err != nil { + debugLog("Failed to get cluster status: %v", err) + // Возвращаем базовую структуру при ошибке + return map[string]interface{}{ + "collector_name": "proxvms", + "cluster": map[string]interface{}{ + "cluster_name": "unknown", + "cluster_uid": "unknown", + "cluster_uuid": "unknown", + }, + "vms": []map[string]any{}, + }, nil + } + + var clusterStatusData []map[string]interface{} + if err := json.Unmarshal(clusterStatRaw, &clusterStatusData); err != nil { + debugLog("Failed to parse cluster status: %v", err) + return nil, err + } + + // Извлекаем информацию о кластере (первый элемент) + var clusterInfo ClusterInfo + if len(clusterStatusData) > 0 && clusterStatusData[0]["type"] == "cluster" { + clusterInfo.ID = getString(clusterStatusData[0], "id") + clusterInfo.Name = getString(clusterStatusData[0], "name") + clusterInfo.Nodes = getInt(clusterStatusData[0], "nodes") + clusterInfo.Quorate = getInt(clusterStatusData[0], "quorate") + clusterInfo.Type = getString(clusterStatusData[0], "type") + clusterInfo.Version = getInt(clusterStatusData[0], "version") + } + + // Извлекаем информацию о всех нодах и находим локальную + var clusterStat []ClusterStatus + var localNode ClusterStatus + for i := 1; i < len(clusterStatusData); i++ { + if clusterStatusData[i]["type"] == "node" { + node := ClusterStatus{ + ID: getString(clusterStatusData[i], "id"), + IP: getString(clusterStatusData[i], "ip"), + Level: getString(clusterStatusData[i], "level"), + Local: getInt(clusterStatusData[i], "local"), + Name: getString(clusterStatusData[i], "name"), + NodeID: getInt(clusterStatusData[i], "nodeid"), + Online: getInt(clusterStatusData[i], "online"), + Type: getString(clusterStatusData[i], "type"), + } + clusterStat = append(clusterStat, node) + + // Находим локальную ноду + if node.Local == 1 { + localNode = node + } + } + } + + debugLog("Cluster info: %+v", clusterInfo) + debugLog("Local node: %+v", localNode) + + // Получаем cluster_uuid из corosync + clusterUUID := runSimple("grep", "cluster_name", "/etc/pve/corosync.conf") + if clusterUUID == "unknown" || clusterUUID == "" { + clusterUUID = clusterInfo.Name // fallback на имя из API + } else { + // Извлекаем только значение после двоеточия + parts := strings.SplitN(clusterUUID, ":", 2) + if len(parts) > 1 { + clusterUUID = strings.TrimSpace(parts[1]) + } + } + + // Генерируем cluster_uid через SHA + clusterID := generateClusterID(clusterUUID) + + // Генерируем node_uid через SHA + nodeUID := generateNodeUID(clusterInfo.ID, strconv.Itoa(localNode.NodeID)) + + // Получаем VM и контейнеры + var vms []map[string]any + if localNode.Name != "" { + debugLog("Processing VMs and containers for node: %s", localNode.Name) + vms = collectVMsAndContainers(localNode.Name, clusterID, nodeUID) + } + + // Возвращаем структуру + resultMap := map[string]interface{}{ + "collector_name": "proxvms", + "cluster": map[string]interface{}{ + "cluster_name": clusterInfo.Name, + "cluster_uid": clusterID, + "cluster_uuid": clusterUUID, + }, + "vms": vms, + } + + debugLog("Final result: %+v", resultMap) + return resultMap, nil +} + +// collectVMsAndContainers собирает информацию о ВМ и контейнерах +func collectVMsAndContainers(nodeName, clusterUID, nodeUID string) []map[string]any { + var allVMs []map[string]any + var wg sync.WaitGroup + var mu sync.Mutex + + // Получаем QEMU виртуальные машины + wg.Add(1) + go func() { + defer wg.Done() + qemuVMs := collectQEMUVMs(nodeName, clusterUID, nodeUID) + mu.Lock() + allVMs = append(allVMs, qemuVMs...) + mu.Unlock() + }() + + // Получаем LXC контейнеры + wg.Add(1) + go func() { + defer wg.Done() + lxcContainers := collectLXCContainers(nodeName, clusterUID, nodeUID) + mu.Lock() + allVMs = append(allVMs, lxcContainers...) + mu.Unlock() + }() + + wg.Wait() + return allVMs +} + +// collectQEMUVMs собирает информацию о QEMU виртуальных машинах +func collectQEMUVMs(nodeName, clusterUID, nodeUID string) []map[string]any { + var qemuVMs []map[string]any + + // Получаем список QEMU VM + vmRaw, err := runPvesh("/nodes/" + nodeName + "/qemu") + if err != nil { + debugLog("Failed to get QEMU VMs for %s: %v", nodeName, err) + return qemuVMs + } + + var vms []VM + if err := json.Unmarshal(vmRaw, &vms); err != nil { + debugLog("Failed to parse QEMU VMs for %s: %v", nodeName, err) + return qemuVMs + } + + debugLog("Found %d QEMU VMs on node %s", len(vms), nodeName) + + // Обрабатываем каждую VM + for _, vm := range vms { + vmData := processQEMUVM(vm, nodeName, clusterUID, nodeUID) + if vmData != nil { + qemuVMs = append(qemuVMs, vmData) + } + } + + return qemuVMs +} + +// collectLXCContainers собирает информацию о LXC контейнерах +func collectLXCContainers(nodeName, clusterUID, nodeUID string) []map[string]any { + var lxcContainers []map[string]any + + // Получаем список LXC контейнеров + ctRaw, err := runPvesh("/nodes/" + nodeName + "/lxc") + if err != nil { + debugLog("Failed to get LXC containers for %s: %v", nodeName, err) + return lxcContainers + } + + var cts []VM + if err := json.Unmarshal(ctRaw, &cts); err != nil { + debugLog("Failed to parse LXC containers for %s: %v", nodeName, err) + return lxcContainers + } + + debugLog("Found %d LXC containers on node %s", len(cts), nodeName) + + // Обрабатываем каждый контейнер + for _, ct := range cts { + ctData := processLXCContainer(ct, nodeName, clusterUID, nodeUID) + if ctData != nil { + lxcContainers = append(lxcContainers, ctData) + } + } + + return lxcContainers +} + +// processQEMUVM обрабатывает информацию о QEMU виртуальной машине +func processQEMUVM(vm VM, nodeName, clusterUID, nodeUID string) map[string]any { + // Преобразуем vmid в строку + var vmidStr string + switch v := vm.Vmid.(type) { + case int: + vmidStr = strconv.Itoa(v) + case string: + vmidStr = v + case float64: + vmidStr = strconv.Itoa(int(v)) + default: + debugLog("Unknown vmid type for QEMU VM: %T", vm.Vmid) + return nil + } + + // Получаем полную конфигурацию VM + configRaw, err := runPvesh("/nodes/" + nodeName + "/qemu/" + vmidStr + "/config") + var config map[string]interface{} + if err == nil { + if err := json.Unmarshal(configRaw, &config); err != nil { + debugLog("Failed to parse QEMU VM config for %s: %v", vmidStr, err) + } + } else { + debugLog("Failed to get QEMU VM config for %s: %v", vmidStr, err) + } + + // Получаем machine_id из конфигурации + machineID := getString(config, "machine") + if machineID == "" { + machineID = "unknown" + } + + // Для QEMU VM пытаемся получить UUID из smbios1 + var machineUID string + if smbiosUUID := getString(config, "smbios1"); smbiosUUID != "" { + // Извлекаем UUID из строки типа "uuid=5325693e-271b-47ed-95c2-3a2cf42f4886" + if strings.Contains(smbiosUUID, "uuid=") { + parts := strings.Split(smbiosUUID, "uuid=") + if len(parts) > 1 { + uuid := strings.TrimSpace(parts[1]) + machineUID = generateMachineUID(uuid) + } else { + machineUID = generateMachineUID(machineID) + } + } else { + machineUID = generateMachineUID(machineID) + } + } else { + machineUID = generateMachineUID(machineID) + } + + // Создаем структуру VM + vmData := map[string]any{ + "vmid": vm.Vmid, + "name": vm.Name, + "status": vm.Status, + "type": "QEMU", + "node_name": nodeName, + "cluster_uid": clusterUID, + "node_uid": nodeUID, + "machine_id": machineID, + "machine_uid": machineUID, + "resources": map[string]any{ + "memory_mb": vm.Mem / 1024 / 1024, + "max_memory_mb": vm.MaxMem / 1024 / 1024, + "cpu_cores": vm.Cores, + "max_disk_gb": vm.MaxDisk / 1024 / 1024 / 1024, + }, + "config": config, + } + + // Добавляем дополнительную информацию из конфигурации + if config != nil { + // Проверяем, является ли VM template + isTemplate := false + if template, ok := config["template"]; ok { + if templateInt, ok := template.(float64); ok { + isTemplate = templateInt == 1 + } else if templateInt, ok := template.(int); ok { + isTemplate = templateInt == 1 + } + } + vmData["is_template"] = isTemplate + + // Добавляем информацию о CPU типе + cpuType := getString(config, "cpu") + if cpuType == "" { + cpuType = "kvm64" // по умолчанию + } + vmData["cpu_type"] = cpuType + + // Добавляем информацию о загрузочном диске + if bootdisk, ok := config["bootdisk"]; ok { + vmData["boot_disk"] = bootdisk + } + + // Парсим и добавляем все в config + enrichConfigWithParsedData(config) + + // Парсим JSON из поля description + if description, ok := config["description"].(string); ok { + if parsedDesc := parseDescriptionJSON(description); parsedDesc != nil { + config["description_parsed"] = parsedDesc + // Удаляем оригинальное поле description, если парсинг прошел успешно + delete(config, "description") + } + } + } + + return vmData +} + +// processLXCContainer обрабатывает информацию о LXC контейнере +func processLXCContainer(ct VM, nodeName, clusterUID, nodeUID string) map[string]any { + // Преобразуем vmid в строку + var vmidStr string + switch v := ct.Vmid.(type) { + case int: + vmidStr = strconv.Itoa(v) + case string: + vmidStr = v + case float64: + vmidStr = strconv.Itoa(int(v)) + default: + debugLog("Unknown vmid type for LXC container: %T", ct.Vmid) + return nil + } + + // Получаем полную конфигурацию контейнера + configRaw, err := runPvesh("/nodes/" + nodeName + "/lxc/" + vmidStr + "/config") + var config map[string]interface{} + if err == nil { + if err := json.Unmarshal(configRaw, &config); err != nil { + debugLog("Failed to parse LXC container config for %s: %v", vmidStr, err) + } + } else { + debugLog("Failed to get LXC container config for %s: %v", vmidStr, err) + } + + // Получаем machine_id из конфигурации (для LXC это может быть hostname или другое поле) + machineID := getString(config, "hostname") + if machineID == "" { + machineID = getString(config, "machine") + } + if machineID == "" { + machineID = "unknown" + } + + // Генерируем machine_uid + machineUID := generateMachineUID(machineID) + + // Создаем структуру контейнера + ctData := map[string]any{ + "vmid": ct.Vmid, + "name": ct.Name, + "status": ct.Status, + "type": "LXC", + "node_name": nodeName, + "cluster_uid": clusterUID, + "node_uid": nodeUID, + "machine_id": machineID, + "machine_uid": machineUID, + "resources": map[string]any{ + "memory_mb": ct.Mem / 1024 / 1024, + "max_memory_mb": ct.MaxMem / 1024 / 1024, + "cpu_cores": ct.Cores, + "max_disk_gb": ct.MaxDisk / 1024 / 1024 / 1024, + }, + "config": config, + } + + // Добавляем дополнительную информацию из конфигурации + if config != nil { + // Проверяем, является ли контейнер template + isTemplate := false + if template, ok := config["template"]; ok { + if templateInt, ok := template.(float64); ok { + isTemplate = templateInt == 1 + } else if templateInt, ok := template.(int); ok { + isTemplate = templateInt == 1 + } + } + ctData["is_template"] = isTemplate + + // Добавляем информацию о дистрибутиве + if ostemplate, ok := config["ostemplate"]; ok { + ctData["os_template"] = ostemplate + } + + // Парсим и добавляем все в config + enrichConfigWithParsedData(config) + + // Парсим JSON из поля description + if description, ok := config["description"].(string); ok { + if parsedDesc := parseDescriptionJSON(description); parsedDesc != nil { + config["description_parsed"] = parsedDesc + // Удаляем оригинальное поле description, если парсинг прошел успешно + delete(config, "description") + } + } + } + + return ctData +} + +// enrichConfigWithParsedData обогащает конфигурацию парсированными данными +func enrichConfigWithParsedData(config map[string]interface{}) { + // Парсим сетевые интерфейсы и добавляем в config + network := parseNetworkInterfaces(config) + if len(network) > 0 { + config["network"] = network + // Удаляем оригинальные netX поля, если они были распарсены + removeParsedFields(config, "net") + } + + // Парсим IP конфигурации и добавляем в config + ipconfig := parseIPConfig(config) + if len(ipconfig) > 0 { + config["ipconfig"] = ipconfig + // Удаляем оригинальные ipconfigX поля, если они были распарсены + removeParsedFields(config, "ipconfig") + } + + // Парсим SCSI устройства и добавляем в config + scsi := parseSCSIDevices(config) + if len(scsi) > 0 { + config["scsi"] = scsi + // Удаляем оригинальные scsiX поля, если они были распарсены + removeParsedFields(config, "scsi") + } + + // Парсим IDE устройства и добавляем в config + ide := parseIDEDevices(config) + if len(ide) > 0 { + config["ide"] = ide + // Удаляем оригинальные ideX поля, если они были распарсены + removeParsedFields(config, "ide") + } + + // Парсим rootfs и mpX устройства для LXC + rootfs := parseRootFS(config) + if len(rootfs) > 0 { + config["rootfs"] = rootfs + // Удаляем оригинальное rootfs поле, если оно было распарсено + // (parseRootFS уже удалил его, но на всякий случай) + } + + // Парсим mpX устройства для LXC + mp := parseMPDevices(config) + if len(mp) > 0 { + config["mp"] = mp + // Удаляем оригинальные mpX поля, если они были распарсены + removeParsedFields(config, "mp") + } +} + +// removeParsedFields удаляет оригинальные поля, которые были успешно распарсены +func removeParsedFields(config map[string]interface{}, prefix string) { + keysToRemove := make([]string, 0) + + for key := range config { + if strings.HasPrefix(key, prefix) { + // Проверяем, что это числовой суффикс (net0, scsi1, etc.) + suffix := key[len(prefix):] + if _, err := strconv.Atoi(suffix); err == nil { + keysToRemove = append(keysToRemove, key) + } + } + } + + // Удаляем найденные ключи + for _, key := range keysToRemove { + delete(config, key) + } +} + +// runPvesh запускает pvesh get и возвращает JSON +func runPvesh(path string) ([]byte, error) { + cmd := exec.Command("pvesh", "get", path, "--output-format", "json") + return cmd.Output() +} + +// runSimple выполняет простую команду и возвращает результат +func runSimple(cmd string, args ...string) string { + out, err := exec.Command(cmd, args...).Output() + if err != nil { + debugLog("Failed to run command %s %v: %v", cmd, args, err) + return "unknown" + } + return strings.TrimSpace(string(out)) +} + +// generateClusterID создает уникальный ID кластера на основе UUID +func generateClusterID(clusterUUID string) string { + if clusterUUID == "" { + clusterUUID = "default-cluster-uuid" + } + hash := sha256.Sum256([]byte(clusterUUID)) + return hex.EncodeToString(hash[:])[:16] // первые 16 символов +} + +// generateNodeUID создает уникальный ID ноды +func generateNodeUID(clusterUUID, nodeID string) string { + base := clusterUUID + ":" + nodeID + hash := sha256.Sum256([]byte(base)) + return hex.EncodeToString(hash[:])[:16] +} + +// generateMachineUID создает уникальный ID машины на основе machine_id +func generateMachineUID(machineID string) string { + if machineID == "" { + machineID = "unknown-machine-id" + } + hash := sha256.Sum256([]byte(machineID)) + return hex.EncodeToString(hash[:])[:16] +} + +// getString извлекает строку из map[string]interface{} +func getString(data map[string]interface{}, key string) string { + if val, ok := data[key]; ok { + if str, ok := val.(string); ok { + return str + } + } + return "" +} + +// getInt извлекает int из map[string]interface{} +func getInt(data map[string]interface{}, key string) int { + if val, ok := data[key]; ok { + switch v := val.(type) { + case int: + return v + case float64: + return int(v) + case string: + if i, err := strconv.Atoi(v); err == nil { + return i + } + } + } + return 0 +} + +// parseDescriptionJSON парсит JSON из поля description и переводит ключи на английский +func parseDescriptionJSON(description string) map[string]interface{} { + if description == "" { + return nil + } + + // Пытаемся найти JSON в строке description + // JSON может быть в начале строки или в середине + start := strings.Index(description, "{") + if start == -1 { + return nil + } + + // Находим закрывающую скобку + bracketCount := 0 + end := -1 + for i := start; i < len(description); i++ { + if description[i] == '{' { + bracketCount++ + } else if description[i] == '}' { + bracketCount-- + if bracketCount == 0 { + end = i + break + } + } + } + + if end == -1 { + return nil + } + + // Извлекаем JSON строку + jsonStr := description[start : end+1] + + // Парсим JSON + var result map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &result); err != nil { + debugLog("Failed to parse description JSON: %v", err) + return nil + } + + // Переводим ключи на английский + translated := translateKeysToEnglish(result) + + return translated +} + +// translateKeysToEnglish переводит русские ключи на английский +func translateKeysToEnglish(data map[string]interface{}) map[string]interface{} { + translationMap := map[string]string{ + "Название ВМ": "vm_name", + "Описание": "description", + "Задача jira": "jira_task", + "Ответственные": "responsible", + "Дата создания ВМ": "creation_date", + "Дата предположительного удаления": "deletion_date", + } + + translated := make(map[string]interface{}) + + for key, value := range data { + // Переводим ключ, если есть перевод + englishKey := translationMap[key] + if englishKey == "" { + // Если перевода нет, оставляем оригинальный ключ + englishKey = key + } + + translated[englishKey] = value + } + + return translated +} + +// parseNetworkInterfaces парсит сетевые интерфейсы (net0, net1, netX) +func parseNetworkInterfaces(config map[string]interface{}) map[string]interface{} { + network := make(map[string]interface{}) + + for key, value := range config { + if strings.HasPrefix(key, "net") { + // Проверяем, что это числовой суффикс (net0, net1, net2, etc.) + suffix := key[3:] // убираем "net" + if _, err := strconv.Atoi(suffix); err == nil { + // Парсим строку конфигурации в ключ-значение + parsed := parseKeyValueString(value) + if len(parsed) > 0 { + network[key] = parsed + } else { + network[key] = value + } + } + } + } + + return network +} + +// parseIPConfig парсит IP конфигурации (ipconfig0, ipconfig1, ipconfigX) +func parseIPConfig(config map[string]interface{}) map[string]interface{} { + ipconfig := make(map[string]interface{}) + + for key, value := range config { + if strings.HasPrefix(key, "ipconfig") { + // Проверяем, что это числовой суффикс (ipconfig0, ipconfig1, ipconfig2, etc.) + suffix := key[8:] // убираем "ipconfig" + if _, err := strconv.Atoi(suffix); err == nil { + // Парсим строку конфигурации в ключ-значение + parsed := parseKeyValueString(value) + if len(parsed) > 0 { + ipconfig[key] = parsed + } else { + ipconfig[key] = value + } + } + } + } + + return ipconfig +} + +// parseSCSIDevices парсит SCSI устройства (scsi0, scsi1, scsiX) +func parseSCSIDevices(config map[string]interface{}) map[string]interface{} { + scsi := make(map[string]interface{}) + + for key, value := range config { + if strings.HasPrefix(key, "scsi") { + // Проверяем, что это числовой суффикс (scsi0, scsi1, scsi2, etc.) + suffix := key[4:] // убираем "scsi" + if _, err := strconv.Atoi(suffix); err == nil { + // Парсим строку конфигурации в ключ-значение + parsed := parseSCSIConfig(value) + if len(parsed) > 0 { + scsi[key] = parsed + } else { + scsi[key] = value + } + } + } + } + + return scsi +} + +// parseSCSIConfig парсит конфигурацию SCSI устройства с особым вниманием к пулам +func parseSCSIConfig(value interface{}) map[string]interface{} { + result := make(map[string]interface{}) + + // Преобразуем значение в строку + var str string + switch v := value.(type) { + case string: + str = v + default: + return result + } + + if str == "" { + return result + } + + // Разбиваем по запятым + parts := strings.Split(str, ",") + + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "" { + continue + } + + // Ищем знак равенства + equalIndex := strings.Index(part, "=") + if equalIndex == -1 { + // Если нет знака равенства, это может быть пул:диск + if strings.Contains(part, ":") { + poolParts := strings.Split(part, ":") + if len(poolParts) >= 2 { + result["pool"] = poolParts[0] + result["pool_disk"] = poolParts[1] + result["enable"] = true + } else { + result[part] = true + } + } else { + result[part] = true + } + continue + } + + key := strings.TrimSpace(part[:equalIndex]) + val := strings.TrimSpace(part[equalIndex+1:]) + + if key != "" { + // Переименовываем size в pool_disk_size для SCSI устройств + if key == "size" { + result["pool_disk_size"] = val + } else { + result[key] = val + } + } + } + + return result +} + +// parseIDEDevices парсит IDE устройства (ide0, ide1, ide2, ideX) +func parseIDEDevices(config map[string]interface{}) map[string]interface{} { + ide := make(map[string]interface{}) + + for key, value := range config { + if strings.HasPrefix(key, "ide") { + // Проверяем, что это числовой суффикс (ide0, ide1, ide2, etc.) + suffix := key[3:] // убираем "ide" + if _, err := strconv.Atoi(suffix); err == nil { + // Парсим строку конфигурации в ключ-значение + parsed := parseKeyValueString(value) + if len(parsed) > 0 { + ide[key] = parsed + } else { + ide[key] = value + } + } + } + } + + return ide +} + +// parseKeyValueString парсит строку в формате "имя=значение,имя=значение" +func parseKeyValueString(value interface{}) map[string]interface{} { + result := make(map[string]interface{}) + + // Преобразуем значение в строку + var str string + switch v := value.(type) { + case string: + str = v + default: + return result + } + + if str == "" { + return result + } + + // Разбиваем по запятым + parts := strings.Split(str, ",") + + // Сначала собираем все ключи и значения + tempResult := make(map[string]interface{}) + + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "" { + continue + } + + // Ищем знак равенства + equalIndex := strings.Index(part, "=") + if equalIndex == -1 { + // Если нет знака равенства, это может быть пул:диск + if strings.Contains(part, ":") { + poolParts := strings.Split(part, ":") + if len(poolParts) >= 2 { + tempResult["pool"] = poolParts[0] + tempResult["pool_disk"] = poolParts[1] + tempResult["enable"] = true + } else { + tempResult[part] = true + } + } else { + tempResult[part] = true + } + continue + } + + key := strings.TrimSpace(part[:equalIndex]) + val := strings.TrimSpace(part[equalIndex+1:]) + + if key != "" { + tempResult[key] = val + } + } + + // Теперь обрабатываем специальные случаи + for key, val := range tempResult { + if key == "ip" { + ipData := parseIPAddress(val.(string)) + // Добавляем gw в секцию ip, если он есть + if gw, exists := tempResult["gw"]; exists { + ipData["gw"] = gw + } + result[key] = ipData + } else if key != "gw" { // gw уже добавлен в ip, не добавляем отдельно + result[key] = val + } + } + + return result +} + +// parseIPAddress парсит IP адрес с маской подсети +func parseIPAddress(ipStr string) map[string]interface{} { + result := make(map[string]interface{}) + + // Проверяем, есть ли маска в формате /24 + if strings.Contains(ipStr, "/") { + parts := strings.Split(ipStr, "/") + if len(parts) == 2 { + ip := parts[0] + mask := parts[1] + + result["ip"] = ip + result["mask_cidr"] = "/" + mask + result["mask"] = cidrToSubnetMask(mask) + } else { + result["ip"] = ipStr + } + } else { + result["ip"] = ipStr + } + + return result +} + +// cidrToSubnetMask конвертирует CIDR маску в формат 255.255.255.0 +func cidrToSubnetMask(cidr string) string { + mask, err := strconv.Atoi(cidr) + if err != nil { + return "" + } + + if mask < 0 || mask > 32 { + return "" + } + + // Создаем маску подсети + var maskBytes [4]byte + for i := 0; i < 4; i++ { + if mask >= 8 { + maskBytes[i] = 255 + mask -= 8 + } else if mask > 0 { + maskBytes[i] = 255 << (8 - mask) + mask = 0 + } else { + maskBytes[i] = 0 + } + } + + return fmt.Sprintf("%d.%d.%d.%d", maskBytes[0], maskBytes[1], maskBytes[2], maskBytes[3]) +} + +// parseRootFS парсит rootfs устройство для LXC контейнеров +func parseRootFS(config map[string]interface{}) map[string]interface{} { + if rootfs, ok := config["rootfs"]; ok { + // Парсим строку конфигурации в ключ-значение + parsed := parseSCSIConfig(rootfs) // используем ту же логику, что и для SCSI + if len(parsed) > 0 { + // Удаляем оригинальное поле rootfs, если парсинг прошел успешно + delete(config, "rootfs") + return parsed + } + } + return nil +} + +// parseMPDevices парсит mpX устройства (mp0, mp1, mpX) для LXC контейнеров +func parseMPDevices(config map[string]interface{}) map[string]interface{} { + mp := make(map[string]interface{}) + + for key, value := range config { + if strings.HasPrefix(key, "mp") { + // Проверяем, что это числовой суффикс (mp0, mp1, mp2, etc.) + suffix := key[2:] // убираем "mp" + if _, err := strconv.Atoi(suffix); err == nil { + // Парсим строку конфигурации в ключ-значение + parsed := parseSCSIConfig(value) // используем ту же логику, что и для SCSI + if len(parsed) > 0 { + mp[key] = parsed + } else { + mp[key] = value + } + } + } + } + + return mp +} + +// debugLog выводит отладочную информацию (только если установлена переменная окружения DEBUG=1) +func debugLog(format string, args ...interface{}) { + if os.Getenv("DEBUG") == "1" { + fmt.Fprintf(os.Stderr, "[DEBUG] "+format+"\n", args...) + } +} diff --git a/src/collectors/proxvms/proxvms_unsupported.go b/src/collectors/proxvms/proxvms_unsupported.go new file mode 100644 index 0000000..6b94dc1 --- /dev/null +++ b/src/collectors/proxvms/proxvms_unsupported.go @@ -0,0 +1,26 @@ +//go:build !linux + +package main + +// Автор: Сергей Антропов, сайт: https://devops.org.ru +// Коллектор proxvms для неподдерживаемых платформ + +import ( + "context" + "encoding/json" + "fmt" + "os" +) + +func collectProxVMs(ctx context.Context) (map[string]interface{}, error) { + // Возвращаем пустую структуру для неподдерживаемых платформ + return map[string]interface{}{ + "collector_name": "proxvms", + "cluster": map[string]interface{}{ + "cluster_name": "unsupported", + "cluster_uid": "unsupported", + "cluster_uuid": "unsupported", + }, + "vms": []map[string]any{}, + }, nil +}