feat(beszel): Installation Beszel monitoring infrastructure
- Ajout Hub Beszel pour Synology NAS (192.168.1.25) - docker-compose-hub.yml - Ajout Agent FolzoCorp avec GPU AMD RX 7800 XT - docker-compose-agent-folzocorp.yml (amd_sysfs) - Ajout Agent EffiServer (CPU only, SKIP_GPU) - docker-compose-agent-effiserver.yml - Documentation: docs/BESZEL-INSTALLATION.md - Script client Python: scripts/beszel_client.py - Permet à Effi d'interroger l'API Beszel
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
# Beszel Agent - EffiServer (192.168.1.27)
|
||||||
|
# Agent pour monitoring EffiServer (Intel J5040)
|
||||||
|
|
||||||
|
services:
|
||||||
|
beszel-agent:
|
||||||
|
image: henrygd/beszel-agent:latest
|
||||||
|
container_name: beszel-agent
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
volumes:
|
||||||
|
- ./beszel_agent_data:/var/lib/beszel-agent
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
environment:
|
||||||
|
HUB_URL: http://192.168.1.25:8090
|
||||||
|
# Pas de GPU sur effi-server (Intel J5040)
|
||||||
|
SKIP_GPU: "true"
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Beszel Agent - FolzoCorp (192.168.1.11)
|
||||||
|
# Agent pour monitoring FolzoCorp avec GPU AMD RX 7800 XT
|
||||||
|
|
||||||
|
services:
|
||||||
|
beszel-agent:
|
||||||
|
image: henrygd/beszel-agent:latest
|
||||||
|
container_name: beszel-agent
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
volumes:
|
||||||
|
- ./beszel_agent_data:/var/lib/beszel-agent
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- /dev/kfd:/dev/kfd
|
||||||
|
- /dev/dri:/dev/dri
|
||||||
|
environment:
|
||||||
|
HUB_URL: http://192.168.1.25:8090
|
||||||
|
# GPU AMD - utilise amd_sysfs ou rocm-smi automatiquement
|
||||||
|
GPU_COLLECTOR: amd_sysfs
|
||||||
|
#amd_sysfs pour AMD RX 7800 XT (Navi 32)
|
||||||
|
devices:
|
||||||
|
- /dev/kfd:/dev/kfd
|
||||||
|
- /dev/dri:/dev/dri
|
||||||
|
group_add:
|
||||||
|
- video
|
||||||
|
- render
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Beszel Hub - Synology NAS
|
||||||
|
# Monitoring central pour FolzoCorp et EffiServer
|
||||||
|
|
||||||
|
services:
|
||||||
|
beszel:
|
||||||
|
image: henrygd/beszel:latest
|
||||||
|
container_name: beszel
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
APP_URL: http://192.168.1.25:8090
|
||||||
|
TZ: Europe/Paris
|
||||||
|
ports:
|
||||||
|
- "8090:8090"
|
||||||
|
volumes:
|
||||||
|
- ./beszel_data:/beszel_data
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
networks:
|
||||||
|
- beszel_network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
beszel_network:
|
||||||
|
name: beszel_network
|
||||||
|
driver: bridge
|
||||||
@@ -0,0 +1,320 @@
|
|||||||
|
# Installation Beszel - Monitoring Infrastructure
|
||||||
|
|
||||||
|
## Vue d'ensemble
|
||||||
|
|
||||||
|
Beszel est un système de monitoring léger pour serveurs avec historique, stats Docker et alertes.
|
||||||
|
|
||||||
|
### Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ NAS Synology (192.168.1.25) │
|
||||||
|
│ Beszel Hub │
|
||||||
|
│ Port: 8090 │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
┌─────────────────────────────┐ ┌─────────────────────────────┐
|
||||||
|
│ FolzoCorp (192.168.1.11) │ │ EffiServer (192.168.1.27) │
|
||||||
|
│ Agent Beszel │ │ Agent Beszel │
|
||||||
|
│ GPU: AMD RX 7800 XT │ │ CPU: Intel J5040 │
|
||||||
|
│ RAM: 32GB │ │ RAM: 8GB │
|
||||||
|
└─────────────────────────────┘ └─────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Installation Hub - NAS Synology (192.168.1.25)
|
||||||
|
|
||||||
|
### Étape 1: Copier les fichiers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Sur le NAS Synology (via SSH)
|
||||||
|
mkdir -p ~/beszel && cd ~/beszel
|
||||||
|
|
||||||
|
# Copier le fichier docker-compose depuis FolzoCorp
|
||||||
|
scp folzo@192.168.1.11:~/Documents/OpenCode/Projets/Effi/beszel/docker-compose-hub.yml ./
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 2: Démarrer le Hub
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/beszel
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 3: Créer le compte admin
|
||||||
|
|
||||||
|
1. Ouvrir http://192.168.1.25:8090
|
||||||
|
2. Créer un compte admin
|
||||||
|
3. Noter les identifiants
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Installation Agent - FolzoCorp (192.168.1.11)
|
||||||
|
|
||||||
|
### Étape 1: Préparer le répertoire
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/beszel-agent && cd ~/beszel-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 2: Copier la configuration
|
||||||
|
|
||||||
|
Le fichier `docker-compose-agent-folzocorp.yml` est dans le projet Effi:
|
||||||
|
```bash
|
||||||
|
cp ~/Documents/OpenCode/Projets/Effi/beszel/docker-compose-agent-folzocorp.yml ./
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 3: Démarrer l'agent
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 4: Ajouter le système dans Beszel UI
|
||||||
|
|
||||||
|
1. Ouvrir http://192.168.1.25:8090
|
||||||
|
2. Cliquer **Add System**
|
||||||
|
3. Choisir **Socket** comme type
|
||||||
|
4. Utiliser le chemin: `/var/run/beszel-agent/beszel.sock`
|
||||||
|
5. Récupérer le TOKEN et KEY affichés
|
||||||
|
|
||||||
|
### Étape 5: Configurer TOKEN et KEY
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Arrêter l'agent
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
# Éditer docker-compose.yml et ajouter TOKEN et KEY
|
||||||
|
nano docker-compose.yml
|
||||||
|
|
||||||
|
# Redémarrer
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vérification GPU
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Vérifier que le monitoring GPU fonctionne
|
||||||
|
docker exec beszel-agent beszel-agent status
|
||||||
|
|
||||||
|
# Ou vérifier les logs
|
||||||
|
docker logs beszel-agent | grep -i gpu
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Installation Agent - EffiServer (192.168.1.27)
|
||||||
|
|
||||||
|
### Étape 1: Se connecter en SSH
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh effi@192.168.1.27
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 2: Préparer le répertoire
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/beszel-agent && cd ~/beszel-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 3: Copier la configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp folzo@192.168.1.11:~/Documents/OpenCode/Projets/Effi/beszel/docker-compose-agent-effiserver.yml ./
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 4: Démarrer l'agent
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Étape 5: Ajouter dans Beszel UI
|
||||||
|
|
||||||
|
Même procédure que FolzoCorp, mais utiliser `/var/run/beszel-agent/beszel.sock`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Endpoints API Beszel
|
||||||
|
|
||||||
|
Beszel expose une API REST pour qu'Effi puisse récupérer les métriques.
|
||||||
|
|
||||||
|
### Authentification
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Login pour obtenir un token
|
||||||
|
curl -X POST http://192.168.1.25:8090/api/auth/login \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"identity": "admin", "password": "votre_password"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Récupérer les stats d'un système
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Lister les systèmes
|
||||||
|
curl http://192.168.1.25:8090/api/systems \
|
||||||
|
-H "Authorization: Bearer <token>"
|
||||||
|
|
||||||
|
# Stats détaillées d'un système
|
||||||
|
curl http://192.168.1.25:8090/api/systems/<system_id>/stats \
|
||||||
|
-H "Authorization: Bearer <token>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exemple de réponse stats
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"cpu": 12.5,
|
||||||
|
"memory": 45.2,
|
||||||
|
"swap": 8.1,
|
||||||
|
"disk": 67.3,
|
||||||
|
"load": [1.2, 0.8, 0.5],
|
||||||
|
"temperature": {},
|
||||||
|
"gpu": {
|
||||||
|
"AMD RX 7800 XT": {
|
||||||
|
"memory_used": 1788194816,
|
||||||
|
"memory_total": 17163091968,
|
||||||
|
"utilization_gpu": 3,
|
||||||
|
"power_draw": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"id": "abc123",
|
||||||
|
"name": "comfyui",
|
||||||
|
"cpu_percent": 0.5,
|
||||||
|
"memory_percent": 48.69
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Scripts Effi pour interroger Beszel
|
||||||
|
|
||||||
|
### Script Python pour récupérer les stats
|
||||||
|
|
||||||
|
```python
|
||||||
|
import requests
|
||||||
|
import os
|
||||||
|
|
||||||
|
BESZEL_URL = "http://192.168.1.25:8090"
|
||||||
|
USERNAME = os.getenv("BESZEL_USER", "admin")
|
||||||
|
PASSWORD = os.getenv("BESZEL_PASSWORD", "")
|
||||||
|
|
||||||
|
def get_beszel_token():
|
||||||
|
response = requests.post(f"{BESZEL_URL}/api/auth/login", json={
|
||||||
|
"identity": USERNAME,
|
||||||
|
"password": PASSWORD
|
||||||
|
})
|
||||||
|
return response.json().get("token")
|
||||||
|
|
||||||
|
def get_system_stats(system_id, token):
|
||||||
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
|
response = requests.get(f"{BESZEL_URL}/api/systems/{system_id}/stats", headers=headers)
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def check_resource_usage():
|
||||||
|
token = get_beszel_token()
|
||||||
|
|
||||||
|
# FolzoCorp
|
||||||
|
folzo_stats = get_system_stats("folzocorp", token)
|
||||||
|
if folzo_stats["memory"]["used_percent"] > 90:
|
||||||
|
print("⚠️ FolzoCorp RAM > 90%")
|
||||||
|
|
||||||
|
# EffiServer
|
||||||
|
effi_stats = get_system_stats("effiserver", token)
|
||||||
|
if effi_stats["cpu"] > 80:
|
||||||
|
print("⚠️ EffiServer CPU > 80%")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Alertes
|
||||||
|
|
||||||
|
### Configurer des alertes dans Beszel UI
|
||||||
|
|
||||||
|
1. Ouvrir http://192.168.1.25:8090
|
||||||
|
2. Cliquer sur un système → **Edit**
|
||||||
|
3. Aller dans **Alerts** tab
|
||||||
|
4. Configurer les alertes souhaitées:
|
||||||
|
|
||||||
|
| Métrique | Seuil Warning | Seuil Critical |
|
||||||
|
|----------|---------------|----------------|
|
||||||
|
| CPU | 70% | 90% |
|
||||||
|
| RAM | 80% | 95% |
|
||||||
|
| VRAM | 80% | 95% |
|
||||||
|
| Disk | 80% | 90% |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Dépannage
|
||||||
|
|
||||||
|
### Agent ne démarre pas
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Vérifier les logs
|
||||||
|
docker logs beszel-agent
|
||||||
|
|
||||||
|
# Vérifier la connectivité au Hub
|
||||||
|
curl http://192.168.1.25:8090/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### GPU non détecté sur FolzoCorp
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Vérifier les permissions GPU
|
||||||
|
ls -la /dev/kfd
|
||||||
|
ls -la /dev/dri/
|
||||||
|
|
||||||
|
# Tester rocm-smi manuellement
|
||||||
|
rocm-smi --showmeminfo vram
|
||||||
|
```
|
||||||
|
|
||||||
|
### Socket non accessible
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Vérifier que le socket existe
|
||||||
|
ls -la /var/run/beszel-agent/
|
||||||
|
|
||||||
|
# Redémarrer l'agent
|
||||||
|
docker restart beszel-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fichiers de configuration
|
||||||
|
|
||||||
|
| Fichier | Emplacement | Description |
|
||||||
|
|---------|-------------|-------------|
|
||||||
|
| `docker-compose-hub.yml` | Synology NAS | Configuration Hub |
|
||||||
|
| `docker-compose-agent-folzocorp.yml` | FolzoCorp | Agent FolzoCorp avec GPU AMD |
|
||||||
|
| `docker-compose-agent-effiserver.yml` | EffiServer | Agent EffiServer (CPU only) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Monitoring GPU
|
||||||
|
|
||||||
|
### FolzoCorp (AMD RX 7800 XT)
|
||||||
|
|
||||||
|
- Utilise `amd_sysfs` collector (recommandé)
|
||||||
|
- Métriques: VRAM, utilisation GPU, power draw
|
||||||
|
- Pas besoin de `rocm-smi` (amd_sysfs plus efficace)
|
||||||
|
|
||||||
|
### EffiServer (Intel J5040)
|
||||||
|
|
||||||
|
- GPU monitoring désactivé (`SKIP_GPU=true`)
|
||||||
|
- J5040 n'a pas de GPU dédié
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Liens utiles
|
||||||
|
|
||||||
|
- [Beszel GitHub](https://github.com/henrygd/beszel)
|
||||||
|
- [Documentation Beszel](https://beszel.dev)
|
||||||
|
- [GPU Monitoring](https://beszel.dev/guide/gpu)
|
||||||
|
- [REST API](https://beszel.dev/guide/rest-api)
|
||||||
Executable
+218
@@ -0,0 +1,218 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Beszel API Client - Pour qu'Effi interroge les métriques Beszel
|
||||||
|
# Usage: python3 beszel_client.py [--system SYSTEM_ID] [--check CHECK_TYPE]
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
BESZEL_URL = os.getenv("BESZEL_URL", "http://192.168.1.25:8090")
|
||||||
|
|
||||||
|
class BeszelClient:
|
||||||
|
def __init__(self, username=None, password=None):
|
||||||
|
self.url = BESZEL_URL
|
||||||
|
self.token = None
|
||||||
|
self.username = username or os.getenv("BESZEL_USER", "admin")
|
||||||
|
self.password = password or os.getenv("BESZEL_PASSWORD", "")
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
try:
|
||||||
|
response = requests.post(f"{self.url}/api/auth/login", json={
|
||||||
|
"identity": self.username,
|
||||||
|
"password": self.password
|
||||||
|
}, timeout=10)
|
||||||
|
if response.status_code == 200:
|
||||||
|
self.token = response.json().get("token")
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur login: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_systems(self):
|
||||||
|
if not self.token:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
headers = {"Authorization": f"Bearer {self.token}"}
|
||||||
|
response = requests.get(f"{self.url}/api/systems", headers=headers, timeout=10)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur get_systems: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_system_stats(self, system_id):
|
||||||
|
if not self.token:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
headers = {"Authorization": f"Bearer {self.token}"}
|
||||||
|
response = requests.get(f"{self.url}/api/systems/{system_id}/stats",
|
||||||
|
headers=headers, timeout=10)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur get_stats: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_system_info(self, system_id):
|
||||||
|
if not self.token:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
headers = {"Authorization": f"Bearer {self.token}"}
|
||||||
|
response = requests.get(f"{self.url}/api/systems/{system_id}",
|
||||||
|
headers=headers, timeout=10)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur get_info: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def format_stats_text(self, stats, system_name="System"):
|
||||||
|
lines = []
|
||||||
|
lines.append(f"=== {system_name} ===")
|
||||||
|
lines.append(f"CPU: {stats.get('cpu', 0):.1f}%")
|
||||||
|
lines.append(f"Mémoire: {stats.get('memory', 0):.1f}%")
|
||||||
|
|
||||||
|
if 'swap' in stats:
|
||||||
|
lines.append(f"Swap: {stats.get('swap', 0):.1f}%")
|
||||||
|
|
||||||
|
if 'disk' in stats:
|
||||||
|
for disk, info in stats['disk'].items():
|
||||||
|
lines.append(f"Disque {disk}: {info.get('used_percent', 0):.1f}%")
|
||||||
|
|
||||||
|
if 'load' in stats:
|
||||||
|
load = stats['load']
|
||||||
|
lines.append(f"Load: {load[0]:.2f} {load[1]:.2f} {load[2]:.2f}")
|
||||||
|
|
||||||
|
if 'gpu' in stats and stats['gpu']:
|
||||||
|
lines.append("")
|
||||||
|
lines.append("GPU:")
|
||||||
|
for gpu_name, gpu_data in stats['gpu'].items():
|
||||||
|
vram_used = gpu_data.get('memory_used', 0) / (1024**3)
|
||||||
|
vram_total = gpu_data.get('memory_total', 0) / (1024**3)
|
||||||
|
vram_pct = (gpu_data.get('memory_used', 0) / gpu_data.get('memory_total', 1)) * 100
|
||||||
|
lines.append(f" {gpu_name}:")
|
||||||
|
lines.append(f" VRAM: {vram_used:.2f}GB / {vram_total:.2f}GB ({vram_pct:.1f}%)")
|
||||||
|
lines.append(f" Utilisation GPU: {gpu_data.get('utilization_gpu', 0)}%")
|
||||||
|
if 'temperature' in gpu_data:
|
||||||
|
lines.append(f" Température: {gpu_data.get('temperature', 0)}°C")
|
||||||
|
if 'power_draw' in gpu_data:
|
||||||
|
lines.append(f" Consommation: {gpu_data.get('power_draw', 0)}W")
|
||||||
|
|
||||||
|
if 'containers' in stats and stats['containers']:
|
||||||
|
lines.append("")
|
||||||
|
lines.append("Containers Docker:")
|
||||||
|
for container in stats['containers']:
|
||||||
|
name = container.get('name', 'unknown')
|
||||||
|
cpu = container.get('cpu_percent', 0)
|
||||||
|
mem = container.get('memory_percent', 0)
|
||||||
|
lines.append(f" {name}: CPU {cpu:.1f}% MEM {mem:.1f}%")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def check_thresholds(self, stats, thresholds=None):
|
||||||
|
if thresholds is None:
|
||||||
|
thresholds = {
|
||||||
|
'cpu': 80,
|
||||||
|
'memory': 90,
|
||||||
|
'vram': 90
|
||||||
|
}
|
||||||
|
|
||||||
|
alerts = []
|
||||||
|
|
||||||
|
cpu = stats.get('cpu', 0)
|
||||||
|
if cpu > thresholds['cpu']:
|
||||||
|
alerts.append(f"⚠️ CPU elevated: {cpu:.1f}%")
|
||||||
|
|
||||||
|
memory = stats.get('memory', 0)
|
||||||
|
if memory > thresholds['memory']:
|
||||||
|
alerts.append(f"⚠️ Memory elevated: {memory:.1f}%")
|
||||||
|
|
||||||
|
if 'gpu' in stats and stats['gpu']:
|
||||||
|
for gpu_name, gpu_data in stats['gpu'].items():
|
||||||
|
vram_pct = (gpu_data.get('memory_used', 0) / gpu_data.get('memory_total', 1)) * 100
|
||||||
|
if vram_pct > thresholds['vram']:
|
||||||
|
alerts.append(f"⚠️ VRAM {gpu_name} elevated: {vram_pct:.1f}%")
|
||||||
|
|
||||||
|
util = gpu_data.get('utilization_gpu', 0)
|
||||||
|
if util > thresholds['vram']:
|
||||||
|
alerts.append(f"⚠️ GPU {gpu_name} utilization elevated: {util}%")
|
||||||
|
|
||||||
|
return alerts
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Beszel API Client")
|
||||||
|
parser.add_argument("--system", "-s", help="System ID to query")
|
||||||
|
parser.add_argument("--list-systems", "-l", action="store_true", help="List all systems")
|
||||||
|
parser.add_argument("--check", "-c", choices=["stats", "alerts", "full"],
|
||||||
|
default="stats", help="Type of check")
|
||||||
|
parser.add_argument("--json", "-j", action="store_true", help="Output JSON")
|
||||||
|
parser.add_argument("--user", "-u", help="Beszel username")
|
||||||
|
parser.add_argument("--password", "-p", help="Beszel password")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
client = BeszelClient(username=args.user, password=args.password)
|
||||||
|
|
||||||
|
if not client.login():
|
||||||
|
print("❌ Échec de connexion à Beszel")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if args.list_systems:
|
||||||
|
systems = client.get_systems()
|
||||||
|
if systems:
|
||||||
|
print("=== Systèmes surveillés ===")
|
||||||
|
for sys in systems.get('items', []):
|
||||||
|
print(f" - {sys.get('name')} (ID: {sys.get('id')})")
|
||||||
|
return
|
||||||
|
|
||||||
|
if args.system:
|
||||||
|
if args.check == "stats":
|
||||||
|
stats = client.get_system_stats(args.system)
|
||||||
|
if stats:
|
||||||
|
if args.json:
|
||||||
|
print(json.dumps(stats, indent=2))
|
||||||
|
else:
|
||||||
|
info = client.get_system_info(args.system)
|
||||||
|
name = info.get('name', args.system) if info else args.system
|
||||||
|
print(client.format_stats_text(stats, name))
|
||||||
|
|
||||||
|
elif args.check == "alerts":
|
||||||
|
stats = client.get_system_stats(args.system)
|
||||||
|
if stats:
|
||||||
|
alerts = client.check_thresholds(stats)
|
||||||
|
if alerts:
|
||||||
|
print("\n".join(alerts))
|
||||||
|
else:
|
||||||
|
print("✅ Tout est normal")
|
||||||
|
|
||||||
|
elif args.check == "full":
|
||||||
|
stats = client.get_system_stats(args.system)
|
||||||
|
info = client.get_system_info(args.system)
|
||||||
|
if stats and info:
|
||||||
|
if args.json:
|
||||||
|
print(json.dumps({'info': info, 'stats': stats}, indent=2, default=str))
|
||||||
|
else:
|
||||||
|
name = info.get('name', args.system)
|
||||||
|
print(f"=== {name} ===")
|
||||||
|
print(client.format_stats_text(stats, name))
|
||||||
|
alerts = client.check_thresholds(stats)
|
||||||
|
if alerts:
|
||||||
|
print("\n" + "\n".join(alerts))
|
||||||
|
else:
|
||||||
|
systems = client.get_systems()
|
||||||
|
if systems:
|
||||||
|
print("Systèmes disponibles (utiliser --system ID):")
|
||||||
|
for sys in systems.get('items', []):
|
||||||
|
print(f" - {sys.get('name')} (ID: {sys.get('id')})")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user