Files
serv_benchmark/BUG_9_COLLECTE_RESEAU.md
2025-12-14 10:40:54 +01:00

7.9 KiB

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

# 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 :

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 :

# 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

# 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

# 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

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

wol_supported=""  # Non détecté

# Résultat attendu
{
  "wake_on_lan": null
}

Test 3 : Interface WiFi

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)

# 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 :

# ❌ Peut crash si $var contient caractères spéciaux
jq -n --arg var "$value" '{field: ($var|test("pattern"))}'

Faire plutôt :

# ✅ 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é

# ✅ 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

# ✅ Toujours prévoir un fallback
json=$(jq -n ... 2>/dev/null || echo '{}')

📝 Fichiers Modifiés

Scripts Bash

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é