Files
serv_benchmark/script_test.sh
2025-12-08 05:42:52 +01:00

969 lines
35 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Linux BenchTools - Script de Test Complet
# Version: 1.0.0
#
# Ce script collecte les informations hardware et exécute les benchmarks
# Génère un fichier result.json dans le dossier courant
#
set -e
# Couleurs pour l'affichage
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Variables globales
SCRIPT_VERSION="1.0.0"
OUTPUT_FILE="result.json"
TOTAL_STEPS=8
CURRENT_STEP=0
# Forcer locale en anglais pour parsing
export LC_ALL=C
# Ajouter /usr/sbin au PATH pour accéder à dmidecode, smartctl, ethtool
export PATH="/usr/sbin:/sbin:$PATH"
# Fonctions d'affichage
log_step() {
CURRENT_STEP=$((CURRENT_STEP + 1))
echo -e "${BLUE}[${CURRENT_STEP}/${TOTAL_STEPS}]${NC} ${GREEN}$1${NC}"
}
log_info() {
echo -e " ${GREEN}${NC} $1"
}
log_warn() {
echo -e " ${YELLOW}${NC} $1"
}
log_error() {
echo -e " ${RED}${NC} $1"
}
safe_bc() {
local expr="$1"
# Renvoie 0 si bc plante, au lieu de laisser une chaîne vide
local out
out=$(echo "$expr" | bc 2>/dev/null) || out="0"
echo "$out"
}
# Vérifier les permissions sudo
check_sudo() {
echo -e "${YELLOW}════════════════════════════════════════════════════════${NC}"
echo -e "${YELLOW} Linux BenchTools - Script de Test${NC}"
echo -e "${YELLOW} Version ${SCRIPT_VERSION}${NC}"
echo -e "${YELLOW}════════════════════════════════════════════════════════${NC}"
echo ""
echo -e "${BLUE}Ce script nécessite les permissions sudo pour :${NC}"
echo " - dmidecode (infos RAM, carte mère, BIOS)"
echo " - smartctl (infos disques)"
echo " - ethtool (vitesse réseau)"
echo ""
if ! sudo -v; then
log_error "Permissions sudo requises. Veuillez relancer avec sudo."
exit 1
fi
# Garder sudo actif pendant toute la durée du script
while true; do sudo -n true; sleep 50; kill -0 "$$" || exit; done 2>/dev/null &
log_info "Permissions sudo OK"
echo ""
}
# Vérifier et installer les dépendances
check_dependencies() {
local missing_essential=()
local missing_bench=()
local missing_optional=()
echo -e "${BLUE}Vérification des dépendances...${NC}"
# Outils essentiels
for tool in curl jq lscpu free lsblk ip bc; do
if ! command -v $tool &> /dev/null; then
missing_essential+=($tool)
fi
done
# Outils de benchmark
for tool in sysbench fio iperf3; do
if ! command -v $tool &> /dev/null; then
missing_bench+=($tool)
fi
done
# Outils optionnels (mais recommandés)
for tool in dmidecode smartctl ethtool lspci; do
if ! command -v $tool &> /dev/null; then
missing_optional+=($tool)
fi
done
# Installer les paquets manquants
local to_install=()
# Mapper les commandes vers les paquets Debian/Ubuntu
declare -A package_map=(
[curl]="curl"
[jq]="jq"
[lscpu]="util-linux"
[free]="procps"
[lsblk]="util-linux"
[ip]="iproute2"
[bc]="bc"
[sysbench]="sysbench"
[fio]="fio"
[iperf3]="iperf3"
[dmidecode]="dmidecode"
[smartctl]="smartmontools"
[ethtool]="ethtool"
[lspci]="pciutils"
)
# Collecter tous les paquets à installer
for tool in "${missing_essential[@]}" "${missing_bench[@]}" "${missing_optional[@]}"; do
local package="${package_map[$tool]}"
if [[ -n "$package" ]] && [[ ! " ${to_install[@]} " =~ " ${package} " ]]; then
to_install+=($package)
fi
done
# Installer si nécessaire
if [[ ${#to_install[@]} -gt 0 ]]; then
echo ""
log_warn "Paquets manquants détectés : ${to_install[*]}"
echo -e "${BLUE}Installation automatique des dépendances...${NC}"
echo ""
# Mettre à jour la liste des paquets
echo "► Mise à jour de la liste des paquets..."
if ! sudo apt-get update -qq 2>&1 | grep -v "Policy will reject signature"; then
log_warn "Avertissement lors de apt-get update (continuer quand même)"
fi
echo " Liste mise à jour"
# Installer les paquets (avec sortie pour voir les erreurs)
echo "► Installation de : ${to_install[*]}"
local install_output
install_output=$(sudo apt-get install -y "${to_install[@]}" 2>&1)
local install_code=$?
# Afficher la sortie (sans les warnings de signature)
echo "$install_output" | grep -v "Policy will reject signature" || true
if [[ $install_code -eq 0 ]]; then
log_info "Installation terminée avec succès"
# Forcer le shell à recharger le PATH pour voir les nouvelles commandes
echo "► Rechargement du PATH..."
hash -r
# Vérifier que les commandes sont maintenant disponibles
echo "► Vérification post-installation..."
for tool in dmidecode smartctl ethtool; do
if command -v $tool &> /dev/null; then
echo "$tool : $(which $tool)"
else
echo "$tool : NON TROUVÉ après installation"
fi
done
else
log_error "Erreur lors de l'installation (code: $install_code)"
echo "Veuillez installer manuellement : sudo apt-get install ${to_install[*]}"
exit 1
fi
echo ""
else
log_info "Toutes les dépendances sont déjà installées"
fi
}
#
# ÉTAPE 1 : Collecte informations système de base
#
collect_system_info() {
log_step "Collecte des informations système de base"
local hostname=$(hostname)
local os_name=$(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
local os_version=$(grep '^VERSION=' /etc/os-release | cut -d= -f2 | tr -d '"')
local kernel=$(uname -r)
local arch=$(uname -m)
SYSTEM_INFO=$(jq -n \
--arg hostname "$hostname" \
--arg os_name "$os_name" \
--arg os_version "$os_version" \
--arg kernel "$kernel" \
--arg arch "$arch" \
'{
hostname: $hostname,
os: {
name: $os_name,
version: $os_version,
kernel_version: $kernel,
architecture: $arch
}
}')
log_info "Hostname: $hostname"
log_info "OS: $os_name $os_version"
log_info "Kernel: $kernel"
}
#
# ÉTAPE 2 : Collecte informations CPU
#
collect_cpu_info() {
log_step "Collecte des informations CPU"
local vendor=$(lscpu | grep 'Vendor ID' | awk '{print $3}')
local model=$(lscpu | sed -n 's/^Model name:[ \t]*//p' | xargs)
local cores=$(lscpu | awk '/^CPU\(s\):/ {print $2}')
local threads=$(nproc)
# Fréquences
local cpu_mhz=$(lscpu | grep 'CPU MHz:' | awk '{print $3}')
local cpu_max_mhz=$(lscpu | grep 'CPU max MHz:' | awk '{print $4}')
local cpu_min_mhz=$(lscpu | grep 'CPU min MHz:' | awk '{print $4}')
# Convertir en GHz
local base_freq_ghz="null"
local max_freq_ghz="null"
if [[ -n "$cpu_mhz" ]]; then
base_freq_ghz=$(echo "scale=2; $cpu_mhz / 1000" | bc)
fi
if [[ -n "$cpu_max_mhz" ]]; then
max_freq_ghz=$(echo "scale=2; $cpu_max_mhz / 1000" | bc)
fi
# Caches
local cache_l1d=$(lscpu | grep 'L1d cache:' | awk '{print $3}' | sed 's/K//' | sed 's/M/*1024/' | bc 2>/dev/null || echo "null")
local cache_l1i=$(lscpu | grep 'L1i cache:' | awk '{print $3}' | sed 's/K//' | sed 's/M/*1024/' | bc 2>/dev/null || echo "null")
local cache_l2=$(lscpu | grep 'L2 cache:' | awk '{print $3}' | sed 's/K//' | sed 's/M/*1024/' | bc 2>/dev/null || echo "null")
local cache_l3=$(lscpu | grep 'L3 cache:' | awk '{print $3}' | sed 's/K//' | sed 's/M/*1024/' | bc 2>/dev/null || echo "null")
# Calculer L1 total
local cache_l1_kb="null"
if [[ "$cache_l1d" != "null" && "$cache_l1i" != "null" ]]; then
cache_l1_kb=$(echo "$cache_l1d + $cache_l1i" | bc)
fi
# Flags CPU (limiter aux plus importants)
local flags=$(lscpu | grep 'Flags:' | sed 's/Flags:[ \t]*//')
local important_flags="avx,avx2,sse4_1,sse4_2,aes,vt-x,vmx,svm"
local flags_array="[]"
if [[ -n "$flags" ]]; then
flags_array=$(echo "$flags" | tr ' ' '\n' | grep -E "^(avx|avx2|sse4_1|sse4_2|aes|pclmulqdq|sha|rdrand|rdseed|popcnt)$" | jq -R . | jq -s .)
fi
CPU_INFO=$(jq -n \
--arg vendor "$vendor" \
--arg model "$model" \
--argjson cores "${cores:-0}" \
--argjson threads "${threads:-0}" \
--argjson base_freq "$base_freq_ghz" \
--argjson max_freq "$max_freq_ghz" \
--argjson l1 "${cache_l1_kb:-null}" \
--argjson l2 "${cache_l2:-null}" \
--argjson l3 "${cache_l3:-null}" \
--argjson flags "$flags_array" \
'{
vendor: $vendor,
model: $model,
cores: $cores,
threads: $threads,
base_freq_ghz: $base_freq,
max_freq_ghz: $max_freq,
cache_l1_kb: $l1,
cache_l2_kb: $l2,
cache_l3_kb: $l3,
flags: $flags
}')
log_info "CPU: $model"
log_info "Cores: $cores, Threads: $threads"
log_info "Freq: ${base_freq_ghz}GHz - ${max_freq_ghz}GHz"
}
#
# ÉTAPE 3 : Collecte informations RAM
#
collect_ram_info() {
log_step "Collecte des informations RAM"
# Statistiques RAM de l'OS (total, used, free, shared)
local mem_line=$(free -m | grep '^Mem:')
local total_mb=$(echo "$mem_line" | awk '{print $2}')
local used_mb=$(echo "$mem_line" | awk '{print $3}')
local free_mb=$(echo "$mem_line" | awk '{print $4}')
local shared_mb=$(echo "$mem_line" | awk '{print $5}') # RAM partagée (inclut tmpfs, vidéo partagée, etc.)
# Infos détaillées avec dmidecode (nécessite sudo)
local slots_total="null"
local slots_used="null"
local ecc="null"
local layout="[]"
# dmidecode nécessite sudo pour fonctionner
echo " [DEBUG] Vérification dmidecode..."
if command -v dmidecode &> /dev/null; then
echo " [DEBUG] dmidecode trouvé: $(which dmidecode)"
# Nombre de slots
echo " [DEBUG] Exécution: sudo dmidecode -t 16..."
slots_total=$(sudo dmidecode -t 16 2>/dev/null | grep 'Number Of Devices' | awk '{print $4}' | head -1)
echo " [DEBUG] Slots total: $slots_total"
# ECC
if sudo dmidecode -t 16 2>/dev/null | grep 'Error Correction Type' | grep -q 'None'; then
ecc="false"
else
ecc="true"
fi
# Layout des barrettes (parsing complexe)
local dimm_data=$(sudo dmidecode -t 17 | grep -E 'Locator:|Size:|Type:|Speed:|Manufacturer:' | \
awk '
/Locator:/ && !/Bank/ { slot=$2; gsub(/_/, "", slot) }
/Size:/ && /[0-9]+ [GM]B/ {
size=$2;
if ($3 == "GB") size=size*1024;
if ($3 == "MB") size=size;
}
/Type:/ && !/Detail/ { type=$2 }
/Speed:/ && /[0-9]+ MT/ { speed=$2 }
/Manufacturer:/ {
manu=$2;
if (size > 0) {
print slot "," size "," type "," speed "," manu;
}
slot=""; size=0; type=""; speed=""; manu="";
}
')
# Convertir en JSON
if [[ -n "$dimm_data" ]]; then
layout=$(echo "$dimm_data" | while IFS=',' read -r slot size type speed manu; do
jq -n \
--arg slot "$slot" \
--argjson size "$size" \
--arg type "$type" \
--argjson speed "$speed" \
--arg manu "$manu" \
'{slot: $slot, size_mb: $size, type: $type, speed_mhz: $speed, manufacturer: $manu}'
done | jq -s .)
slots_used=$(echo "$layout" | jq 'length')
fi
else
echo " [DEBUG] dmidecode NON trouvé (command -v failed)"
log_warn "dmidecode non disponible - infos RAM limitées"
fi
echo " [DEBUG] Fin collect_ram_info"
RAM_INFO=$(jq -n \
--argjson total "$total_mb" \
--argjson used "$used_mb" \
--argjson free "$free_mb" \
--argjson shared "$shared_mb" \
--argjson slots_total "${slots_total:-null}" \
--argjson slots_used "${slots_used:-null}" \
--argjson ecc "${ecc:-null}" \
--argjson layout "$layout" \
'{
total_mb: $total,
used_mb: $used,
free_mb: $free,
shared_mb: $shared,
slots_total: $slots_total,
slots_used: $slots_used,
ecc: $ecc,
layout: $layout
}')
log_info "RAM Total: ${total_mb}MB (Utilisée: ${used_mb}MB, Libre: ${free_mb}MB)"
[[ "$shared_mb" -gt 0 ]] && log_info "RAM Partagée: ${shared_mb}MB (tmpfs/vidéo)"
[[ "$slots_used" != "null" ]] && log_info "Slots: ${slots_used}/${slots_total}"
}
#
# ÉTAPE 4 : Collecte informations GPU, Motherboard, BIOS
#
collect_hardware_info() {
log_step "Collecte GPU, Carte mère, BIOS"
# GPU
local gpu_vendor="null"
local gpu_model="null"
local gpu_vram="null"
if command -v lspci &> /dev/null; then
local gpu_info=$(lspci | grep -i 'vga\|3d' | head -1)
if [[ -n "$gpu_info" ]]; then
gpu_model=$(echo "$gpu_info" | sed 's/.*: //' | xargs)
if echo "$gpu_info" | grep -qi 'nvidia'; then
gpu_vendor="NVIDIA"
if command -v nvidia-smi &> /dev/null; then
gpu_vram=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits | head -1)
fi
elif echo "$gpu_info" | grep -qi 'intel'; then
gpu_vendor="Intel"
elif echo "$gpu_info" | grep -qi 'amd\|radeon'; then
gpu_vendor="AMD"
fi
log_info "GPU: $gpu_model"
fi
fi
GPU_INFO=$(jq -n \
--arg vendor "${gpu_vendor}" \
--arg model "${gpu_model}" \
--argjson vram "${gpu_vram:-null}" \
'{vendor: $vendor, model: $model, vram_mb: $vram}')
# Motherboard & BIOS
local mb_manufacturer="null"
local mb_model="null"
local bios_vendor="null"
local bios_version="null"
local bios_date="null"
if command -v dmidecode &> /dev/null; then
mb_manufacturer=$(sudo dmidecode -t 2 | grep 'Manufacturer:' | sed 's/.*: *//' | xargs)
mb_model=$(sudo dmidecode -t 2 | grep 'Product Name:' | sed 's/.*: *//' | xargs)
[[ -z "$mb_model" || "$mb_model" == "To be filled by O.E.M." ]] && mb_model="Unknown"
bios_vendor=$(sudo dmidecode -t 0 | grep 'Vendor:' | sed 's/.*: *//' | xargs)
bios_version=$(sudo dmidecode -t 0 | grep 'Version:' | sed 's/.*: *//' | xargs)
bios_date=$(sudo dmidecode -t 0 | grep 'Release Date:' | sed 's/.*: *//' | xargs)
log_info "Motherboard: $mb_manufacturer $mb_model"
log_info "BIOS: $bios_version ($bios_date)"
fi
MOTHERBOARD_INFO=$(jq -n \
--arg manu "${mb_manufacturer}" \
--arg model "${mb_model}" \
--arg bios_vendor "${bios_vendor}" \
--arg bios_ver "${bios_version}" \
--arg bios_date "${bios_date}" \
'{
manufacturer: $manu,
model: $model,
bios_vendor: $bios_vendor,
bios_version: $bios_ver,
bios_date: $bios_date
}')
}
#
# ÉTAPE 5 : Collecte informations Storage
#
collect_storage_info() {
log_step "Collecte des informations de stockage"
local storage_array="[]"
# Lister uniquement les disques physiques (pas loop, pas ram)
local physical_disks=$(lsblk -d -n -o NAME,TYPE | grep 'disk' | awk '{print $1}')
for disk in $physical_disks; do
# Ignorer les disques de taille 0 (lecteurs vides)
local size_bytes=$(lsblk -d -n -b -o SIZE /dev/$disk)
[[ "$size_bytes" -eq 0 ]] && continue
local size=$(lsblk -d -n -o SIZE /dev/$disk | sed 's/,/./')
local rota=$(lsblk -d -n -o ROTA /dev/$disk)
local tran=$(lsblk -d -n -o TRAN /dev/$disk)
# Type : SSD ou HDD
local disk_type="unknown"
[[ "$rota" == "0" ]] && disk_type="ssd" || disk_type="hdd"
# Interface
local interface="unknown"
[[ -n "$tran" ]] && interface="$tran"
# Modèle et données SMART via smartctl
local model="Unknown"
local serial="Unknown"
local smart_health="null"
local power_on_hours="null"
local power_cycle_count="null"
local temperature="null"
local reallocated_sectors="null"
local pending_sectors="null"
local udma_crc_errors="null"
local wear_leveling="null"
local total_lbas_written="null"
if command -v smartctl &> /dev/null; then
# Informations de base
local smart_info=$(sudo smartctl -i /dev/$disk 2>/dev/null || true)
if [[ -n "$smart_info" ]]; then
model=$(echo "$smart_info" | grep 'Device Model:' | sed 's/.*: *//' | xargs)
[[ -z "$model" ]] && model=$(echo "$smart_info" | grep 'Model Number:' | sed 's/.*: *//' | xargs)
serial=$(echo "$smart_info" | grep 'Serial Number:' | sed 's/.*: *//' | xargs)
fi
# Données SMART (santé et vieillissement)
local smart_all=$(sudo smartctl -A -H /dev/$disk 2>/dev/null || true)
if [[ -n "$smart_all" ]]; then
# État de santé global
if echo "$smart_all" | grep -q 'SMART overall-health self-assessment test result: PASSED'; then
smart_health="PASSED"
elif echo "$smart_all" | grep -q 'SMART overall-health self-assessment test result: FAILED'; then
smart_health="FAILED"
fi
# Heures de fonctionnement (ID 9)
power_on_hours=$(echo "$smart_all" | awk '/Power_On_Hours|Power On Hours/ {print $10}' | head -1)
[[ -z "$power_on_hours" ]] && power_on_hours="null"
# Nombre de cycles d'alimentation (ID 12)
power_cycle_count=$(echo "$smart_all" | awk '/Power_Cycle_Count|Start_Stop_Count/ {print $10}' | head -1)
[[ -z "$power_cycle_count" ]] && power_cycle_count="null"
# Température (ID 194)
temperature=$(echo "$smart_all" | awk '/Temperature_Celsius|Airflow_Temperature/ {print $10}' | head -1)
[[ -z "$temperature" ]] && temperature="null"
# Secteurs réalloués (ID 5) - Important pour la santé
reallocated_sectors=$(echo "$smart_all" | awk '/Reallocated_Sector_Ct/ {print $10}' | head -1)
[[ -z "$reallocated_sectors" ]] && reallocated_sectors="null"
# Secteurs en attente de réallocation (ID 197)
pending_sectors=$(echo "$smart_all" | awk '/Current_Pending_Sector/ {print $10}' | head -1)
[[ -z "$pending_sectors" ]] && pending_sectors="null"
# Erreurs CRC UDMA (ID 199) - Problèmes de câble/interface
udma_crc_errors=$(echo "$smart_all" | awk '/UDMA_CRC_Error_Count/ {print $10}' | head -1)
[[ -z "$udma_crc_errors" ]] && udma_crc_errors="null"
# Pour SSD: Wear Leveling Count (ID 177)
if [[ "$disk_type" == "ssd" ]]; then
wear_leveling=$(echo "$smart_all" | awk '/Wear_Leveling_Count/ {print $4}' | head -1)
[[ -z "$wear_leveling" ]] && wear_leveling="null"
# Total LBAs Written (indicateur d'usure SSD, ID 241)
total_lbas_written=$(echo "$smart_all" | awk '/Total_LBAs_Written/ {print $10}' | head -1)
[[ -z "$total_lbas_written" ]] && total_lbas_written="null"
fi
fi
fi
# Convertir size en GB
local size_gb=$(echo "$size" | sed 's/[^0-9.]//g')
# Créer l'objet SMART
local smart_json=$(jq -n \
--arg health "${smart_health}" \
--argjson power_hours "${power_on_hours:-null}" \
--argjson power_cycles "${power_cycle_count:-null}" \
--argjson temp "${temperature:-null}" \
--argjson realloc "${reallocated_sectors:-null}" \
--argjson pending "${pending_sectors:-null}" \
--argjson crc_errors "${udma_crc_errors:-null}" \
--argjson wear "${wear_leveling:-null}" \
--argjson lbas_written "${total_lbas_written:-null}" \
'{
health_status: $health,
power_on_hours: $power_hours,
power_cycle_count: $power_cycles,
temperature_celsius: $temp,
reallocated_sectors: $realloc,
pending_sectors: $pending,
udma_crc_errors: $crc_errors,
wear_leveling_count: $wear,
total_lbas_written: $lbas_written
}')
local disk_json=$(jq -n \
--arg device "$disk" \
--arg model "$model" \
--arg size "$size_gb" \
--arg type "$disk_type" \
--arg interface "$interface" \
--arg serial "$serial" \
--argjson smart "$smart_json" \
'{device: $device, model: $model, size_gb: $size, type: $type, interface: $interface, serial: $serial, smart: $smart}')
storage_array=$(echo "$storage_array" | jq --argjson disk "$disk_json" '. + [$disk]')
# Log avec infos de santé
local health_info=""
[[ "$smart_health" != "null" ]] && health_info=" - Santé: $smart_health"
[[ "$power_on_hours" != "null" ]] && health_info="$health_info, ${power_on_hours}h"
log_info "Disque: /dev/$disk - $model ($size, $disk_type)$health_info"
done
STORAGE_INFO="$storage_array"
}
#
# ÉTAPE 6 : Collecte informations réseau
#
collect_network_info() {
log_step "Collecte des informations réseau"
local network_array="[]"
# Interfaces actives (ignore loopback, docker, bridges)
for iface in $(ip -br link show | grep -E 'UP|UNKNOWN' | awk '{print $1}'); do
[[ "$iface" =~ ^(lo|docker|br-|veth) ]] && continue
# MAC
local mac=$(ip link show $iface | grep 'link/ether' | awk '{print $2}')
[[ -z "$mac" ]] && continue
# Type
local type="unknown"
if [[ "$iface" =~ ^(eth|eno|enp) ]]; then
type="ethernet"
elif [[ "$iface" =~ ^(wlan|wlp) ]]; then
type="wifi"
fi
# IP address
local ip_addr=$(ip -4 addr show $iface | grep 'inet ' | awk '{print $2}' | cut -d/ -f1)
# Vitesse et Wake-on-LAN (nécessite ethtool et ethernet)
local speed="null"
local wol_supported="null"
if command -v ethtool &> /dev/null && [[ "$type" == "ethernet" ]]; then
speed=$(sudo ethtool $iface 2>/dev/null | grep 'Speed:' | awk '{print $2}' | sed 's/Mb\/s//' | sed 's/Unknown!/null/')
[[ -z "$speed" || "$speed" == "Unknown" ]] && speed="null"
# Wake-on-LAN support
local wol_info=$(sudo ethtool $iface 2>/dev/null | grep 'Supports Wake-on:')
if [[ -n "$wol_info" ]]; then
# Si le support contient 'g' (magic packet), WoL est supporté
if echo "$wol_info" | grep -q 'g'; then
wol_supported="true"
else
wol_supported="false"
fi
fi
fi
local net_json=$(jq -n \
--arg name "$iface" \
--arg type "$type" \
--arg mac "$mac" \
--arg ip "${ip_addr:-null}" \
--argjson speed "${speed:-null}" \
--argjson wol "${wol_supported:-null}" \
'{name: $name, type: $type, mac: $mac, ip_address: $ip, speed_mbps: $speed, wake_on_lan: $wol}')
network_array=$(echo "$network_array" | jq --argjson net "$net_json" '. + [$net]')
log_info "Interface: $iface ($type) - IP: ${ip_addr:-N/A}"
done
NETWORK_INFO="$network_array"
}
#
# ÉTAPE 7 : Exécution des benchmarks
#
run_benchmarks() {
log_step "Exécution des benchmarks (peut prendre plusieurs minutes)"
# CPU Benchmark
local cpu_bench="null"
if command -v sysbench &> /dev/null; then
log_info "Benchmark CPU en cours..."
local cpu_result=$(sysbench cpu --cpu-max-prime=20000 --threads=$(nproc) run 2>&1)
local events_per_sec=$(echo "$cpu_result" | grep 'events per second' | awk '{print $4}')
local total_time=$(echo "$cpu_result" | grep 'total time:' | awk '{print $3}' | sed 's/s//')
local cpu_score=$(echo "scale=2; $events_per_sec / 100" | bc)
cpu_bench=$(jq -n \
--argjson eps "${events_per_sec:-0}" \
--argjson time "${total_time:-0}" \
--argjson score "${cpu_score:-0}" \
'{events_per_sec: $eps, duration_s: $time, score: $score}')
log_info "CPU: ${events_per_sec} events/sec (score: ${cpu_score})"
else
log_warn "sysbench non disponible - CPU bench ignoré"
fi
# Memory Benchmark
local mem_bench="null"
if command -v sysbench &> /dev/null; then
log_info "Benchmark Mémoire en cours..."
local mem_result=$(sysbench memory --memory-block-size=1M --memory-total-size=1G run 2>&1)
local throughput=$(echo "$mem_result" | grep 'MiB/sec' | grep -oP '\d+\.\d+' | head -1)
local mem_score=$(echo "scale=2; $throughput / 100" | bc)
mem_bench=$(jq -n \
--argjson tp "${throughput:-0}" \
--argjson score "${mem_score:-0}" \
'{throughput_mib_s: $tp, score: $score}')
log_info "Mémoire: ${throughput} MiB/s (score: ${mem_score})"
fi
# Disk Benchmark (sur le disque principal uniquement, pas /tmp)
local disk_bench="null"
if command -v fio &> /dev/null; then
log_info "Benchmark Disque en cours (cela peut prendre 2-3 minutes)..."
# Utiliser le répertoire home pour éviter /tmp (qui peut être tmpfs)
local test_dir="$HOME/fio-bench-test"
mkdir -p "$test_dir"
local fio_result=$(fio --name=bench --ioengine=libaio --rw=randrw --bs=4k \
--size=500M --numjobs=1 --direct=1 --runtime=30 --time_based \
--filename="$test_dir/testfile" --output-format=json 2>/dev/null || echo '{}')
# Nettoyer
rm -rf "$test_dir"
if [[ "$fio_result" != "{}" ]]; then
local read_bw=$(echo "$fio_result" | jq '.jobs[0].read.bw // 0')
local write_bw=$(echo "$fio_result" | jq '.jobs[0].write.bw // 0')
local read_iops=$(echo "$fio_result" | jq '.jobs[0].read.iops // 0' | cut -d. -f1)
local write_iops=$(echo "$fio_result" | jq '.jobs[0].write.iops // 0' | cut -d. -f1)
local lat_ns=$(echo "$fio_result" | jq '.jobs[0].read.clat_ns.mean // 0')
# Convertir en MB/s et ms
local read_mb=$(echo "scale=2; $read_bw / 1024" | bc)
local write_mb=$(echo "scale=2; $write_bw / 1024" | bc)
local lat_ms=$(echo "scale=3; $lat_ns / 1000000" | bc)
# Score : moyenne read/write MB/s
local disk_score=$(echo "scale=2; ($read_mb + $write_mb) / 2" | bc)
disk_bench=$(jq -n \
--argjson read "$read_mb" \
--argjson write "$write_mb" \
--argjson riops "$read_iops" \
--argjson wiops "$write_iops" \
--argjson lat "$lat_ms" \
--argjson score "$disk_score" \
'{read_mb_s: $read, write_mb_s: $write, iops_read: $riops, iops_write: $wiops, latency_ms: $lat, score: $score}')
log_info "Disque: R=${read_mb}MB/s W=${write_mb}MB/s (score: ${disk_score})"
fi
else
log_warn "fio non disponible - Disk bench ignoré"
fi
# Network Benchmark vers le serveur 10.0.1.97
local net_bench="null"
if command -v iperf3 &> /dev/null; then
log_info "Benchmark Réseau en cours (vers 10.0.1.97)..."
# Test de connectivité d'abord
if ping -c 1 -W 2 10.0.1.97 &> /dev/null; then
# Test upload (client → serveur)
local upload_result=$(iperf3 -c 10.0.1.97 -t 10 -J 2>/dev/null || echo '{}')
local upload_mbps="0"
local download_mbps="0"
local ping_ms="null"
if [[ "$upload_result" != "{}" ]]; then
# Extraire le débit d'upload en bits/sec et convertir en Mbps
local upload_bps=$(echo "$upload_result" | jq '.end.sum_sent.bits_per_second // 0')
upload_mbps=$(echo "scale=2; $upload_bps / 1000000" | bc)
# Test download (serveur → client avec -R)
local download_result=$(iperf3 -c 10.0.1.97 -t 10 -R -J 2>/dev/null || echo '{}')
if [[ "$download_result" != "{}" ]]; then
local download_bps=$(echo "$download_result" | jq '.end.sum_received.bits_per_second // 0')
download_mbps=$(echo "scale=2; $download_bps / 1000000" | bc)
fi
# Mesurer le ping
local ping_output=$(ping -c 5 10.0.1.97 2>/dev/null | grep 'avg' || echo "")
if [[ -n "$ping_output" ]]; then
ping_ms=$(echo "$ping_output" | awk -F'/' '{print $5}')
fi
# Score réseau : moyenne upload/download divisée par 10 (pour avoir un score sur 100)
local net_score=$(echo "scale=2; ($upload_mbps + $download_mbps) / 20" | bc)
net_bench=$(jq -n \
--argjson upload "$upload_mbps" \
--argjson download "$download_mbps" \
--argjson ping "${ping_ms:-null}" \
--argjson score "$net_score" \
'{upload_mbps: $upload, download_mbps: $download, ping_ms: $ping, score: $score}')
log_info "Réseau: ↑${upload_mbps}Mbps ↓${download_mbps}Mbps (ping: ${ping_ms}ms, score: ${net_score})"
else
log_warn "Serveur iperf3 sur 10.0.1.97 non accessible (assurez-vous que 'iperf3 -s' tourne)"
fi
else
log_warn "Serveur 10.0.1.97 non joignable - Network bench ignoré"
fi
else
log_warn "iperf3 non disponible - Network bench ignoré"
fi
# GPU Benchmark
local gpu_bench="null"
log_warn "GPU bench non implémenté - ignoré"
# Calculer score global (seulement CPU, RAM, Disk)
# Pondération : CPU=60%, RAM=20%, Disk=20%
local scores=""
local total_weight=0
if [[ "$cpu_bench" != "null" ]]; then
local cpu_score
cpu_score=$(echo "$cpu_bench" | jq '.score // 0')
scores="$scores + $cpu_score * 0.6"
total_weight=$(safe_bc "$total_weight + 0.6")
fi
if [[ "$mem_bench" != "null" ]]; then
local mem_score
mem_score=$(echo "$mem_bench" | jq '.score // 0')
scores="$scores + $mem_score * 0.2"
total_weight=$(safe_bc "$total_weight + 0.2")
fi
if [[ "$disk_bench" != "null" ]]; then
local disk_score
disk_score=$(echo "$disk_bench" | jq '.score // 0')
scores="$scores + $disk_score * 0.2"
total_weight=$(safe_bc "$total_weight + 0.2")
fi
# Nettoyer le préfixe " + " éventuellement
scores=$(echo "$scores" | sed -E 's/^[[:space:]]*\+ //')
local global_score=0
if [[ -n "$scores" && "$total_weight" != "0" ]]; then
global_score=$(safe_bc "scale=2; ($scores) / $total_weight")
fi
# Toujours fournir un JSON valide à jq
if [[ -z "$global_score" ]]; then
global_score=0
fi
BENCHMARK_RESULTS=$(jq -n \
--argjson cpu "$cpu_bench" \
--argjson mem "$mem_bench" \
--argjson disk "$disk_bench" \
--argjson net "$net_bench" \
--argjson gpu "$gpu_bench" \
--argjson global "$global_score" \
'{
cpu: $cpu,
memory: $mem,
disk: $disk,
network: $net,
gpu: $gpu,
global_score: $global
}')
log_info "Score global: ${global_score}/100"
}
#
# ÉTAPE 8 : Génération du fichier JSON
#
generate_json() {
log_step "Génération du fichier result.json"
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Assembler le JSON final
jq -n \
--arg version "$SCRIPT_VERSION" \
--arg timestamp "$timestamp" \
--argjson system "$SYSTEM_INFO" \
--argjson cpu "$CPU_INFO" \
--argjson ram "$RAM_INFO" \
--argjson gpu "$GPU_INFO" \
--argjson mb "$MOTHERBOARD_INFO" \
--argjson storage "$STORAGE_INFO" \
--argjson network "$NETWORK_INFO" \
--argjson benchmarks "$BENCHMARK_RESULTS" \
'{
metadata: {
script_version: $version,
timestamp: $timestamp
},
system: $system,
hardware: {
cpu: $cpu,
ram: $ram,
gpu: $gpu,
motherboard: $mb,
storage: $storage,
network: $network
},
benchmarks: $benchmarks
}' > "$OUTPUT_FILE"
log_info "Fichier généré: $OUTPUT_FILE"
# Afficher un résumé
echo ""
echo -e "${GREEN}════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN} Test terminé avec succès !${NC}"
echo -e "${GREEN}════════════════════════════════════════════════════════${NC}"
echo ""
echo "Fichier de résultat : $(pwd)/$OUTPUT_FILE"
echo "Taille du fichier : $(du -h $OUTPUT_FILE | awk '{print $1}')"
echo ""
echo "Aperçu du résultat :"
echo "-------------------"
jq '{
hostname: .system.hostname,
os: .system.os.name,
cpu: .hardware.cpu.model,
ram_mb: .hardware.ram.total_mb,
storage_count: (.hardware.storage | length),
network_count: (.hardware.network | length),
benchmark_score: .benchmarks.global_score
}' "$OUTPUT_FILE"
echo ""
}
#
# MAIN
#
main() {
# Vérifications préliminaires
check_sudo
check_dependencies
echo ""
echo -e "${BLUE}Début de la collecte et des benchmarks...${NC}"
echo ""
# Exécuter toutes les étapes
collect_system_info
collect_cpu_info
collect_ram_info
collect_hardware_info
collect_storage_info
collect_network_info
run_benchmarks
generate_json
echo -e "${GREEN}✓ Terminé !${NC}"
}
# Lancer le script
main "$@"