309 lines
7.9 KiB
Markdown
Executable File
309 lines
7.9 KiB
Markdown
Executable File
# Bug #9 : Collecte Réseau - Erreur jq Invalid JSON - 2025-12-14
|
|
|
|
## 🐛 Symptômes
|
|
|
|
Lors de l'exécution du benchmark sur **elitedesk** (Intel Core i7-6700), le script crash à l'étape 6 :
|
|
|
|
```
|
|
[6/8] Collecte des informations réseau
|
|
jq: invalid JSON text passed to --argjson
|
|
Use jq --help for help with command-line options,
|
|
or see the jq manpage, or online docs at https://jqlang.github.io/jq
|
|
```
|
|
|
|
**Machine affectée** : elitedesk (HP EliteDesk 800 G2)
|
|
**CPU** : Intel Core i7-6700
|
|
**OS** : Debian 13 (trixie) avec kernel Proxmox 6.17.2-1-pve
|
|
|
|
---
|
|
|
|
## 🔍 Analyse du Bug
|
|
|
|
### Ligne Problématique
|
|
|
|
**Fichier** : [scripts/bench.sh](scripts/bench.sh#L661-L663)
|
|
|
|
```bash
|
|
# Ancienne version (ligne 661)
|
|
network_array=$(echo "$network_array" | jq --argjson net "$net_json" '. + [$net]')
|
|
```
|
|
|
|
### Cause Racine #1 : Regex jq test()
|
|
|
|
Le problème initial venait de la **construction du JSON** pour `wake_on_lan` :
|
|
|
|
```bash
|
|
wake_on_lan: ( if $wol == "" then null else ( $wol|test("true";"i") ) end )
|
|
```
|
|
|
|
**Problème** : La fonction jq `test()` avec regex **peut échouer** si `$wol` contient caractères spéciaux.
|
|
|
|
### Cause Racine #2 : Parsing ethtool (Découvert sur elitedesk)
|
|
|
|
**Symptômes** :
|
|
- `speed="1000Mb/s"` au lieu de `"1000"` → jq `.tonumber?` échoue
|
|
- `wol="pumbg\ng"` (avec retour chariot) → pollution du JSON
|
|
|
|
**Origine** :
|
|
```bash
|
|
# Ligne 633 - Pattern AWK ne retire pas correctement "Mb/s"
|
|
spd=$(echo "$e" | awk -F: '/Speed:/ {gsub(/ Mb\/s/,"",$2); gsub(/^[ \t]+/,"",$2); print $2}')
|
|
# Retourne: "1000Mb/s" ❌ au lieu de "1000" ✅
|
|
|
|
# Ligne 636 - Wake-on-LAN contient des retours chariot
|
|
wol=$(echo "$e" | awk -F: '/Wake-on:/ {gsub(/^[ \t]+/,"",$2); print $2}')
|
|
# Retourne: "pumbg\ng" ❌ au lieu de "pumbg" ✅
|
|
```
|
|
|
|
**Impact** : `jq --argjson net "$net_json"` échoue car `net_json` contient du JSON invalide
|
|
|
|
### Reproduction du Bug
|
|
|
|
```bash
|
|
# Simulation de l'erreur
|
|
wol_supported="" # ou une valeur inattendue
|
|
jq -n --arg wol "$wol_supported" '{wake_on_lan: ( if $wol == "" then null else ( $wol|test("true";"i") ) end )}'
|
|
# Peut retourner une erreur jq selon la valeur de $wol
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ Solution Appliquée
|
|
|
|
### Approche : Conversion Bash → JSON Booléen
|
|
|
|
Au lieu d'utiliser une regex jq complexe, on **convertit la valeur en bash** avant de passer à jq :
|
|
|
|
**Fichier** : [scripts/bench.sh](scripts/bench.sh#L628-L678)
|
|
|
|
```bash
|
|
# CORRECTION #1 : Extraction propre de la vitesse (seulement le nombre)
|
|
local speed="" wol_supported=""
|
|
if [[ "$type" = "ethernet" && -x /usr/sbin/ethtool ]]; then
|
|
local e
|
|
e=$(sudo ethtool "$iface" 2>/dev/null || true)
|
|
local spd
|
|
# Extraire seulement le nombre de la vitesse (enlever "Mb/s")
|
|
spd=$(echo "$e" | awk -F: '/Speed:/ {gsub(/^[ \t]+/,"",$2); print $2}' | grep -oE '[0-9]+' | head -1)
|
|
[[ -n "$spd" ]] && speed="$spd"
|
|
local wol
|
|
# Extraire Wake-on-LAN et nettoyer (enlever retours chariot)
|
|
wol=$(echo "$e" | awk -F: '/Wake-on:/ {gsub(/^[ \t]+/,"",$2); print $2}' | tr -d '\n' | head -1)
|
|
if [[ -n "$wol" && "$wol" != "d" ]]; then
|
|
wol_supported="true"
|
|
elif [[ -n "$wol" ]]; then
|
|
wol_supported="false"
|
|
fi
|
|
fi
|
|
|
|
# CORRECTION #2 : Convertir wol_supported en booléen ou null pour jq
|
|
local wol_json="null"
|
|
if [[ "$wol_supported" == "true" ]]; then
|
|
wol_json="true"
|
|
elif [[ "$wol_supported" == "false" ]]; then
|
|
wol_json="false"
|
|
fi
|
|
|
|
# CORRECTION #3 : Génération JSON avec valeurs propres
|
|
local net_json
|
|
net_json=$(jq -n \
|
|
--arg name "$iface" \
|
|
--arg type "$type" \
|
|
--arg mac "$mac" \
|
|
--arg ip "${ip_addr:-}" \
|
|
--arg speed "$speed" \
|
|
--argjson wol "$wol_json" \ # ← Utilise --argjson au lieu de --arg
|
|
'{
|
|
name: $name,
|
|
type: $type,
|
|
mac: $mac,
|
|
ip_address: ( $ip | select(. != "") ),
|
|
speed_mbps: ( ( $speed | tonumber? ) // null ), # ← $speed contient "1000" pas "1000Mb/s"
|
|
wake_on_lan: $wol # ← Pas de test() regex ici
|
|
}' 2>/dev/null || echo '{}')
|
|
|
|
# CORRECTION #4 : Validation JSON avant ajout
|
|
if [[ "$net_json" != "{}" ]] && echo "$net_json" | jq empty 2>/dev/null; then
|
|
network_array=$(echo "$network_array" | jq --argjson net "$net_json" '. + [$net]')
|
|
else
|
|
log_warn "Interface $iface: JSON invalide, ignorée"
|
|
fi
|
|
```
|
|
|
|
### Avantages de Cette Solution
|
|
|
|
1. ✅ **Simplicité** : Conversion directe en bash (plus lisible)
|
|
2. ✅ **Robustesse** : `--argjson` avec valeur booléenne pure (true/false/null)
|
|
3. ✅ **Validation** : Vérifie que `net_json` est valide avant utilisation
|
|
4. ✅ **Fallback** : Si jq échoue, retourne `'{}'` et log un warning
|
|
5. ✅ **Compatibilité** : Fonctionne avec tous types de cartes réseau
|
|
|
|
---
|
|
|
|
## 🧪 Tests de Validation
|
|
|
|
### Test 1 : Interface Ethernet Standard
|
|
|
|
```bash
|
|
iface="eno1"
|
|
mac="18:c0:4d:b5:65:74"
|
|
ip_addr="10.0.1.109"
|
|
speed="1000"
|
|
wol_supported="true"
|
|
|
|
# Résultat attendu
|
|
{
|
|
"name": "eno1",
|
|
"type": "ethernet",
|
|
"mac": "18:c0:4d:b5:65:74",
|
|
"ip_address": "10.0.1.109",
|
|
"speed_mbps": 1000,
|
|
"wake_on_lan": true
|
|
}
|
|
```
|
|
|
|
### Test 2 : Interface sans WoL
|
|
|
|
```bash
|
|
wol_supported="" # Non détecté
|
|
|
|
# Résultat attendu
|
|
{
|
|
"wake_on_lan": null
|
|
}
|
|
```
|
|
|
|
### Test 3 : Interface WiFi
|
|
|
|
```bash
|
|
iface="wlan0"
|
|
type="wifi"
|
|
mac="aa:bb:cc:dd:ee:ff"
|
|
wol_supported="false"
|
|
|
|
# Résultat attendu
|
|
{
|
|
"name": "wlan0",
|
|
"type": "wifi",
|
|
"mac": "aa:bb:cc:dd:ee:ff",
|
|
"wake_on_lan": false
|
|
}
|
|
```
|
|
|
|
### Test 4 : Caractères Spéciaux (Edge Case)
|
|
|
|
```bash
|
|
# Même avec des valeurs bizarres, ne doit pas crash
|
|
wol_supported="g" # Valeur inattendue de ethtool
|
|
|
|
# Résultat
|
|
{
|
|
"wake_on_lan": null # Géré correctement
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Impact
|
|
|
|
### Avant Correction
|
|
|
|
- ❌ **Crash** sur certaines machines (elitedesk)
|
|
- ❌ **Benchmark incomplet** (arrêt à l'étape 6/8)
|
|
- ❌ **Pas de données réseau** collectées
|
|
|
|
### Après Correction
|
|
|
|
- ✅ **Pas de crash** sur toutes les machines testées
|
|
- ✅ **Benchmark complet** (8/8 étapes)
|
|
- ✅ **Données réseau** correctement collectées
|
|
- ✅ **Warning informatif** si JSON invalide (au lieu d'un crash)
|
|
|
|
---
|
|
|
|
## 🔧 Compatibilité
|
|
|
|
### Machines Testées
|
|
|
|
| Machine | CPU | OS | Réseau | Statut |
|
|
|---------|-----|----|---------| -------|
|
|
| **aorus** | Ryzen 9 5900X | Debian 13 | eno1 (ethernet) | ✅ OK |
|
|
| **elitedesk** | Intel i7-6700 | Debian 13 PVE | Interface ethernet | ✅ **CORRIGÉ** |
|
|
|
|
### Types d'Interfaces Supportées
|
|
|
|
- ✅ Ethernet (`eth0`, `eno1`, `enp*`)
|
|
- ✅ WiFi (`wlan0`, `wl*`)
|
|
- ✅ Interfaces virtuelles (ignorées : `lo`, `docker`, `br-`, `veth`)
|
|
|
|
---
|
|
|
|
## 🎓 Leçons Apprises
|
|
|
|
### Problème avec jq `test()` Regex
|
|
|
|
**Ne pas faire** :
|
|
```bash
|
|
# ❌ Peut crash si $var contient caractères spéciaux
|
|
jq -n --arg var "$value" '{field: ($var|test("pattern"))}'
|
|
```
|
|
|
|
**Faire plutôt** :
|
|
```bash
|
|
# ✅ Conversion en bash + passage via --argjson
|
|
local json_value="null"
|
|
[[ "$value" == "pattern" ]] && json_value="true"
|
|
jq -n --argjson field "$json_value" '{field: $field}'
|
|
```
|
|
|
|
### Toujours Valider le JSON Généré
|
|
|
|
```bash
|
|
# ✅ Validation avant utilisation
|
|
if echo "$json" | jq empty 2>/dev/null; then
|
|
# JSON valide, on peut l'utiliser
|
|
array=$(echo "$array" | jq --argjson item "$json" '. + [$item]')
|
|
else
|
|
# JSON invalide, log un warning
|
|
log_warn "JSON invalide, ignoré"
|
|
fi
|
|
```
|
|
|
|
### Fallback Robuste
|
|
|
|
```bash
|
|
# ✅ Toujours prévoir un fallback
|
|
json=$(jq -n ... 2>/dev/null || echo '{}')
|
|
```
|
|
|
|
---
|
|
|
|
## 📝 Fichiers Modifiés
|
|
|
|
### Scripts Bash
|
|
|
|
**[scripts/bench.sh](scripts/bench.sh)**
|
|
- **Lignes 644-674** : Refactoring collecte réseau
|
|
- L644-650 : Conversion `wol_supported` en JSON booléen
|
|
- L659 : Utilisation `--argjson` au lieu de regex
|
|
- L669-674 : Validation JSON avant ajout
|
|
|
|
---
|
|
|
|
## ✅ Statut Final
|
|
|
|
**Bug #9** : ✅ **CORRIGÉ**
|
|
|
|
- **Impact** : Bloquant (crash sur certaines machines)
|
|
- **Priorité** : Haute
|
|
- **Complexité** : Moyenne
|
|
- **Solution** : Conversion bash + validation JSON
|
|
- **Tests** : 2 machines (aorus + elitedesk)
|
|
|
|
---
|
|
|
|
**Document créé le** : 2025-12-14 à 10h30
|
|
**Version script** : 1.2.1 (après correction)
|
|
**Machines affectées** : elitedesk (HP EliteDesk 800 G2)
|
|
**Status** : ✅ Corrigé et testé
|