# 04 – Spécification du script client de benchmark (bench.sh) Objectif : définir précisément le comportement du script Bash exécuté sur les machines clientes pour : - collecter les informations matérielles et système, - exécuter les benchmarks, - calculer les scores, - envoyer un JSON complet au backend via HTTP. Ce fichier sert de référence pour écrire `scripts/bench.sh` dans le dépôt. --- ## 1. Usage et interface en ligne de commande Le script doit être exécutable en one-liner depuis une machine cliente, par exemple : ```bash curl -s https://gitea.maison43.duckdns.org/gilles/linux-benchtools/raw/branch/main/scripts/bench.sh \ | bash -s -- \ --server https://bench.maison43/api/benchmark \ --token "XXXXXXX" \ --device "elitedesk-800g3" \ --iperf-server 10.0.0.10 \ --short ``` ### 1.1. Arguments supportés - `--server ` (obligatoire) URL de l’endpoint backend `POST /api/benchmark`. - `--token ` (obligatoire) Token d’authentification à envoyer dans `Authorization: Bearer `. - `--device ` (optionnel) Identifiant logique de la machine (`device_identifier`). Si non fourni, utiliser `hostname` de la machine. - `--iperf-server ` (optionnel) Hôte/IP du serveur iperf3 utilisé pour les tests réseau. - `--skip-cpu`, `--skip-memory`, `--skip-disk`, `--skip-network`, `--skip-gpu` (optionnels) Permettent de désactiver certains tests. - `--short` (optionnel) Version “rapide” des tests (durées/tailles réduites). - `--help` Affiche un message d’aide et quitte. ### 1.2. Variables internes - `BENCH_SCRIPT_VERSION` (string, ex: `"1.0.0"`) Doit être mise à jour à chaque changement incompatible du script. --- ## 2. Pré-requis et compatibilité ### 2.1. OS visés (MVP) - Debian / Ubuntu / Proxmox (base Debian). Le script doit : - Lire `/etc/os-release` pour détecter l’OS. - Utiliser `apt-get` pour installer les paquets manquants. ### 2.2. Outils nécessaires Le script doit vérifier et installer si besoin : - `curl` - `jq` (construction JSON) - `sysbench` (CPU + mémoire) - `fio` (disque) - `iperf3` (réseau, si `--iperf-server` fourni) - `dmidecode` (RAM, carte mère, BIOS) - `lsblk` - `lscpu` - `smartmontools` (optionnel pour SMART disques) - `lm-sensors` (optionnel pour températures) - `glmark2` (optionnel pour GPU si dispo) --- ## 3. Structure générale du script 1. Parser les arguments. 2. Vérifier `--server` et `--token` (sinon erreur + exit 1). 3. Déterminer : - `DEVICE_IDENTIFIER` = `--device` ou `hostname`. - `BENCH_SCRIPT_VERSION`. 4. Détecter l’OS et préparer la commande d’installation de paquets. 5. Vérifier/installer les outils nécessaires. 6. Collecter les informations hardware et OS. 7. Exécuter les benchmarks (en respectant les flags `--skip-*`). 8. Calculer les scores (CPU, mémoire, disque, réseau, GPU, global). 9. Construire le JSON. 10. Envoyer le JSON au backend. 11. Afficher un récap et le statut HTTP. --- ## 4. Collecte des informations matérielles et système Toutes les infos doivent ensuite être assemblées dans le bloc `hardware` du JSON. ### 4.1. CPU Commandes possibles : - `lscpu` - `/proc/cpuinfo` Informations à extraire : - `vendor` : ligne `Vendor ID` (ou `GenuineIntel`, `AuthenticAMD`, etc.). - `model` : `Model name`. - `microarchitecture` : optionnel (peut être déterminé via une table interne si souhaité, sinon laisser vide). - `cores` : `Core(s) per socket` × `Socket(s)` ou `CPU(s)` minus hyperthreading. - `threads` : `CPU(s)` (nombre logique). - `base_freq_ghz` : depuis `lscpu` (MHz -> GHz). - `max_freq_ghz` : `CPU max MHz` si disponible. - `cache_l1_kb`, `cache_l2_kb`, `cache_l3_kb` : `L1d cache`, `L2 cache`, `L3 cache`. - `flags` : liste depuis `Flags` / `Features`. - `tdp_w` : non triviale à extraire dans un script, peut rester null. ### 4.2. RAM Commandes : - `free -m` - `dmidecode --type memory` (requiert sudo) Infos : - `total_mb` : depuis `free -m`. - `slots_total` : nombre d’entrées `Locator` dans `dmidecode` (type DIMM). - `slots_used` : slots où `Size` n’est pas `No Module Installed`. - `ecc` : champ `Total Width` vs `Data Width` ou `Error Correction Type`. - `layout` : tableau d’objets avec : - `slot` (Locator) - `size_mb` - `type` (DDR3/DDR4/DDR5/etc.) - `speed_mhz` - `vendor` - `part_number` ### 4.3. GPU Commandes : - `lspci | grep -i vga` - éventuellement `nvidia-smi` si NVIDIA. Infos : - `vendor` : Intel, NVIDIA, AMD… - `model` : texte brut de `lspci`. - `driver_version` : si récupérable (`nvidia-smi --query-gpu=driver_version`). - `memory_dedicated_mb` : via `nvidia-smi`/outils spécifiques si possible, sinon null. - `memory_shared_mb` : éventuellement via `lspci`/`/proc`, sinon null. - `api_support` : optionnel (OpenGL/Vulkan), peut être laissé vide. ### 4.4. Stockage (disques et partitions) Commandes : - `lsblk -o NAME,SIZE,TYPE,MODEL,TRAN,MOUNTPOINT,FSTYPE` - `smartctl -H /dev/sdX` (si présent) - éventuellement `nvme list` / `nvme smart-log`. Infos : - `devices` : tableau d’objets : - `name` (ex: `/dev/nvme0n1`) - `type` (HDD/SSD/NVMe, déduit de `TYPE`/`TRAN`/nom). - `interface` (SATA, PCIe 3.0 x4, USB, etc. si déductible). - `capacity_gb` : depuis `SIZE`. - `vendor` / `model` : `MODEL`. - `smart_health` : `PASSED` / `FAILED` / null. - `temperature_c` : si dispo via SMART. - `partitions` : tableau d’objets : - `name` - `mount_point` - `fs_type` - `used_gb` - `total_gb` ### 4.5. Réseau Commandes : - `ip addr` - `ip -o link` - `ethtool ` (pour vitesse si dispo). - pour Wi-Fi : `iw dev` / `iwconfig`. Infos : - `interfaces` : tableau d’objets : - `name` (ex: `eth0`, `enp3s0`, `wlan0`) - `type` (`ethernet`, `wifi`, `other`) - `mac` - `ip` (IPv4 principale si existante) - `speed_mbps` : via `ethtool`. - `driver` : éventuellement depuis `/sys/class/net//device/driver`. ### 4.6. Carte mère / BIOS Commandes : - `dmidecode --type baseboard` - `dmidecode --type bios` Infos : - `motherboard.vendor` - `motherboard.model` - `bios_version` - `bios_date` ### 4.7. OS Commandes : - `/etc/os-release` - `uname -r` - `uname -m` - `systemd-detect-virt` (si dispo). Infos : - `name` : ID ou PRETTY_NAME. - `version` : VERSION ou VERSION_CODENAME. - `kernel_version` : `uname -r`. - `architecture` : `uname -m`. - `virtualization_type` : sortie de `systemd-detect-virt` (kvm, qemu, none, etc.). ### 4.8. Capteurs (facultatif) - `sensors` (lm-sensors) - `smartctl -A` pour température disques. Infos : - `sensors.cpu_temp_c` (ou valeur moyenne). - `sensors.disk_temps_c` : map `{ "/dev/nvme0n1": 42 }`. --- ## 5. Benchmarks à exécuter Les résultats iront dans le bloc `results` du JSON. ### 5.1. CPU – sysbench Commande par défaut (mode complet) : ```bash sysbench cpu --cpu-max-prime=20000 --threads="$(nproc)" run ``` Mode `--short` : ```bash sysbench cpu --cpu-max-prime=10000 --threads="$(nproc)" run ``` Valeurs à extraire : - `events_per_sec` : ligne `events per second: X`. - `duration_s` : temps total (`total time:`). Score CPU : - Score simple : - définir une valeur de référence (par ex. 5000 events/s = 50 points). - `cpu_score = min(100, events_per_sec / ref * 50)` (ajuster plus tard). - Pour l’instant, le script peut : - soit calculer cette note, - soit juste envoyer les valeurs brutes et laisser le backend calculer. ### 5.2. Mémoire – sysbench Commande (complet) : ```bash sysbench memory --memory-total-size=2G --memory-oper=write run ``` Mode `--short` : ```bash sysbench memory --memory-total-size=512M --memory-oper=write run ``` Valeurs : - `throughput_mib_s` : ligne `transferred (XXXX MiB/sec)`. Score mémoire : - Basé sur `throughput_mib_s` et une référence. ### 5.3. Disque – fio Profil simple (séquentiel read/write 1GiB) : ```bash fio --name=bench_seq_rw \ --rw=readwrite \ --bs=1M \ --size=1G \ --numjobs=1 \ --iodepth=16 \ --filename=/tmp/fio_benchfile \ --direct=1 \ --group_reporting ``` Mode `--short` : - Taille 256M. Valeurs à extraire (via parsing ou `--output-format=json`) : - `read_mb_s` - `write_mb_s` - éventuellement `iops_read`, `iops_write`, `latency_ms`. Score disque : - Moyenne pondérée de read/write vs valeurs de référence. Après test, supprimer `/tmp/fio_benchfile`. ### 5.4. Réseau – iperf3 Uniquement si `--iperf-server` fourni. Download (client -> server, test reverse) : ```bash iperf3 -c "$IPERF_SERVER" -R -J ``` Upload : ```bash iperf3 -c "$IPERF_SERVER" -J ``` Utiliser le JSON (`-J`) + `jq` pour extraire : - `upload_mbps` - `download_mbps` - `jitter_ms` - `packet_loss_percent` (si UDP, option future). Ping (latence) : ```bash ping -c 5 "$IPERF_SERVER" ``` Extraire : - `ping_ms` = moyenne. Score réseau : - Combinaison débit (min(up, down)) et latence (ping). ### 5.5. GPU – glmark2 (optionnel) Si `glmark2` disponible : ```bash glmark2 ``` Extraire : - Score global `glmark2_score`. Score GPU : - Normalisation simple vs référence. --- ## 6. Construction du JSON Le script utilise `jq` pour construire le JSON final : Structure : ```json { "device_identifier": "...", "bench_script_version": "1.0.0", "hardware": { ... }, "results": { ... } } ``` Principes : - Utiliser `jq -n` et passer les valeurs via `--arg` / `--argjson`. - Attention aux nombres vs strings (utiliser `--argjson` pour les nombres). - Gérer proprement les valeurs nulles (par exemple si test GPU non réalisé). Exemple (simplifié) en shell : ```bash payload=$(jq -n --arg device_identifier "$DEVICE_IDENTIFIER" --arg bench_script_version "$BENCH_SCRIPT_VERSION" --argjson cpu "$CPU_JSON" --argjson ram "$RAM_JSON" --argjson results "$RESULTS_JSON" '{ device_identifier: $device_identifier, bench_script_version: $bench_script_version, hardware: { cpu: $cpu, ram: $ram }, results: $results }') ``` --- ## 7. Envoi au backend Commandes : ```bash HTTP_RESPONSE=$(curl -s -o /tmp/bench_response.txt -w "%{http_code}" \ -X POST "$SERVER_URL" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d "$payload") ``` - Si `HTTP_RESPONSE` != `200` : - Afficher un message d’erreur (console). - Optionnel : afficher `/tmp/bench_response.txt`. - Si succès : - Afficher un message confirmant l’ID du benchmark si présent dans la réponse. --- ## 8. Gestion des erreurs à prévoir - Absence de `--server` ou `--token` -> erreur et exit. - Outils manquants et impossible à installer -> avertir, sauter le test concerné, transmettre `score = null`. - Erreurs iperf3 (serveur indisponible) -> ignorer la partie réseau, `network` null. - Temps de test trop long -> proposer un mode `--short`. --- ## 9. Journalisation locale (optionnelle) - Possibilité de logger les infos dans `/var/log/linux_benchtools_client.log` ou `/tmp/linux_benchtools_client.log`. - Log recommandé : - Date/heure. - SERVER, DEVICE_IDENTIFIER. - Résumé des scores. - Code HTTP de la réponse. --- ## 10. Bonnes pratiques - Ne jamais supprimer ou modifier des fichiers système. - Nettoyer les fichiers temporaires (fio, résultats intermédiaires). - Garder le script idempotent : on peut le relancer sans casser la machine. - Prévoir un délai total raisonnable pour un run complet (ex. < 5–10 minutes en mode complet, < 2–3 minutes en mode `--short`).