frogg_freebox_check/frogg_freebox_check.sh

469 lines
16 KiB
Bash
Executable File

#!/usr/bin/env bash
# ==============================================================================
# frogg_freebox_check.sh
# Script Zabbix - Métriques Freebox via API V10
# Compatible : Zabbix 7.0 / ExternalCheck
# Auteur : frogg (généré)
# Répertoire : /usr/lib/zabbix/externalscripts/
# Usage : frogg_freebox_check.sh <APP_ID> <APP_TOKEN> <HOST> <METRIC>
# ==============================================================================
set -uo pipefail
# Note: -e retiré volontairement pour gérer les erreurs curl manuellement
# ------------------------------------------------------------------------------
# Dépendances requises : curl, jq, openssl
# ------------------------------------------------------------------------------
for cmd in curl jq openssl bc; do
if ! command -v "$cmd" &>/dev/null; then
echo "ERREUR: '$cmd' est requis mais introuvable." >&2
exit 1
fi
done
# ------------------------------------------------------------------------------
# Paramètres (fournis par Zabbix via macros du template)
# ------------------------------------------------------------------------------
APP_ID="${1:-}"
APP_TOKEN="${2:-}"
FREEBOX_HOST="${3:-mafreebox.freebox.fr}"
METRIC="${4:-}"
# Mode debug : passer DEBUG=1 en variable d'environnement pour voir les erreurs curl
DEBUG="${DEBUG:-0}"
if [[ -z "$APP_ID" || -z "$APP_TOKEN" || -z "$FREEBOX_HOST" || -z "$METRIC" ]]; then
echo "Usage: $0 <APP_ID> <APP_TOKEN> <HOST> <METRIC>" >&2
echo "Métriques disponibles:" >&2
echo " cpu_percent - Utilisation CPU (%)" >&2
echo " ram_percent - Utilisation RAM (%)" >&2
echo " ram_used - RAM utilisée (bytes)" >&2
echo " ram_total - RAM totale (bytes)" >&2
echo " hdd_percent - Utilisation HDD (%)" >&2
echo " hdd_used - HDD utilisé (bytes)" >&2
echo " hdd_total - HDD total (bytes)" >&2
echo " net_rate_down - Débit descendant actuel (bit/s)" >&2
echo " net_rate_up - Débit montant actuel (bit/s)" >&2
echo " net_bytes_down - Total octets reçus" >&2
echo " net_bytes_up - Total octets envoyés" >&2
echo " net_bw_down - Bande passante max descendante (bit/s)" >&2
echo " net_bw_up - Bande passante max montante (bit/s)" >&2
echo " temp_cpum - Température CPU mère (°C)" >&2
echo " temp_cpub - Température CPU box (°C)" >&2
echo " temp_sw - Température switch (°C)" >&2
echo " temp_hdd - Température HDD (°C)" >&2
echo " fan_rpm - Vitesse ventilateur (RPM)" >&2
echo " uptime - Uptime système (secondes)" >&2
echo " disk_status - Statut disque (ok=1 / problem=0)" >&2
exit 1
fi
BASE_URL="https://${FREEBOX_HOST}/api/v10"
SESSION_FILE="/tmp/.freebox_session_${APP_ID}.cache"
SESSION_MAX_AGE=1800 # 30 min en secondes
# ------------------------------------------------------------------------------
# Options curl communes
# --insecure : La Freebox utilise un certificat Free (CA non reconnu par défaut)
# Si tu veux valider le certificat, télécharge le CA Free :
# curl -O https://raw.githubusercontent.com/freebox/ssl/main/freebox_root_ca.pem
# puis remplace --insecure par --cacert /etc/ssl/freebox_root_ca.pem
# ------------------------------------------------------------------------------
CURL_OPTS=(
--insecure # Certificat SSL Free (CA non standard)
--silent # Pas de barre de progression
--max-time 15 # Timeout global
--connect-timeout 5 # Timeout connexion
--retry 2 # 2 tentatives en cas d'échec réseau
--retry-delay 1
)
# En mode debug, on affiche les erreurs curl sur stderr
if [[ "$DEBUG" == "1" ]]; then
CURL_OPTS+=(--show-error)
fi
# ------------------------------------------------------------------------------
# Fonctions utilitaires
# ------------------------------------------------------------------------------
log_error() {
echo "ERREUR: $*" >&2
}
log_debug() {
if [[ "$DEBUG" == "1" ]]; then
echo "DEBUG: $*" >&2
fi
}
# Requête API Freebox (sans session, pour login)
api_request_noauth() {
local method="$1"
local endpoint="$2"
local data="${3:-}"
local response
local http_code
local tmp_body
tmp_body=$(mktemp)
if [[ "$method" == "POST" && -n "$data" ]]; then
http_code=$(curl "${CURL_OPTS[@]}" \
-o "$tmp_body" \
-w "%{http_code}" \
-X POST \
-H "Content-Type: application/json" \
-d "$data" \
"${BASE_URL}${endpoint}" 2>&1)
else
http_code=$(curl "${CURL_OPTS[@]}" \
-o "$tmp_body" \
-w "%{http_code}" \
"${BASE_URL}${endpoint}" 2>&1)
fi
local curl_exit=$?
response=$(cat "$tmp_body")
rm -f "$tmp_body"
if [[ $curl_exit -ne 0 ]]; then
log_error "curl a échoué (exit=$curl_exit) sur ${BASE_URL}${endpoint}"
log_error "Conseil : vérifiez la connectivité et le certificat SSL (mode DEBUG=1 pour détails)"
exit 2
fi
if [[ "$http_code" != "200" && "$http_code" != "201" ]]; then
log_error "Réponse HTTP inattendue : $http_code sur ${endpoint}"
log_debug "Corps de la réponse : $response"
exit 2
fi
log_debug "Réponse ${endpoint} [HTTP $http_code] : $response"
echo "$response"
}
# Requête API Freebox avec session token
api_request() {
local method="$1"
local endpoint="$2"
local session_token="$3"
local data="${4:-}"
local response
local http_code
local tmp_body
tmp_body=$(mktemp)
if [[ "$method" == "POST" && -n "$data" ]]; then
http_code=$(curl "${CURL_OPTS[@]}" \
-o "$tmp_body" \
-w "%{http_code}" \
-X POST \
-H "Content-Type: application/json" \
-H "X-Fbx-App-Auth: ${session_token}" \
-d "$data" \
"${BASE_URL}${endpoint}" 2>&1)
else
http_code=$(curl "${CURL_OPTS[@]}" \
-o "$tmp_body" \
-w "%{http_code}" \
-H "X-Fbx-App-Auth: ${session_token}" \
"${BASE_URL}${endpoint}" 2>&1)
fi
local curl_exit=$?
response=$(cat "$tmp_body")
rm -f "$tmp_body"
if [[ $curl_exit -ne 0 ]]; then
log_error "curl a échoué (exit=$curl_exit) sur ${endpoint}"
# Session peut être expirée : supprimer le cache pour forcer un nouveau login
rm -f "$SESSION_FILE"
exit 2
fi
if [[ "$http_code" != "200" && "$http_code" != "201" ]]; then
log_error "Réponse HTTP inattendue : $http_code sur ${endpoint}"
log_debug "Corps de la réponse : $response"
# Si 403, la session est invalide, on purge le cache
if [[ "$http_code" == "403" || "$http_code" == "401" ]]; then
log_error "Session invalide, suppression du cache. Relancez la commande."
rm -f "$SESSION_FILE"
fi
exit 2
fi
log_debug "Réponse ${endpoint} [HTTP $http_code] : $response"
echo "$response"
}
# Génère le mot de passe de session via HMAC-SHA1
generate_password() {
local token="$1"
local challenge="$2"
echo -n "$challenge" | openssl dgst -sha1 -hmac "$token" | awk '{print $NF}'
}
# ------------------------------------------------------------------------------
# Gestion de la session (cache pour éviter trop de logins)
# ------------------------------------------------------------------------------
get_session_token() {
# Vérification du cache
if [[ -f "$SESSION_FILE" ]]; then
local file_age
file_age=$(( $(date +%s) - $(stat -c %Y "$SESSION_FILE" 2>/dev/null || echo 0) ))
if [[ $file_age -lt $SESSION_MAX_AGE ]]; then
cat "$SESSION_FILE"
return 0
fi
fi
# Récupération du challenge
local login_resp
login_resp=$(api_request_noauth "GET" "/login")
local success
success=$(echo "$login_resp" | jq -r '.success // false')
if [[ "$success" != "true" ]]; then
log_error "Impossible de récupérer le challenge de login"
exit 3
fi
local challenge
challenge=$(echo "$login_resp" | jq -r '.result.challenge')
if [[ -z "$challenge" || "$challenge" == "null" ]]; then
log_error "Challenge vide reçu de la Freebox"
exit 3
fi
# Génération du mot de passe
local password
password=$(generate_password "$APP_TOKEN" "$challenge")
# Ouverture de session
local session_payload
session_payload=$(jq -nc \
--arg app_id "$APP_ID" \
--arg password "$password" \
'{"app_id": $app_id, "password": $password}')
local session_resp
session_resp=$(api_request_noauth "POST" "/login/session" "$session_payload")
local session_success
session_success=$(echo "$session_resp" | jq -r '.success // false')
if [[ "$session_success" != "true" ]]; then
local err_msg
err_msg=$(echo "$session_resp" | jq -r '.msg // "Erreur inconnue"')
log_error "Échec d'ouverture de session : $err_msg"
exit 3
fi
local session_token
session_token=$(echo "$session_resp" | jq -r '.result.session_token')
if [[ -z "$session_token" || "$session_token" == "null" ]]; then
log_error "Session token vide"
exit 3
fi
# Mise en cache
echo "$session_token" > "$SESSION_FILE"
chmod 600 "$SESSION_FILE"
echo "$session_token"
}
# ------------------------------------------------------------------------------
# Récupération des métriques système (CPU, RAM, Temp, Fan)
# ------------------------------------------------------------------------------
get_system_metrics() {
local session_token="$1"
api_request "GET" "/system/" "$session_token"
}
# ------------------------------------------------------------------------------
# Récupération des métriques réseau (WAN stats)
# ------------------------------------------------------------------------------
get_connection_metrics() {
local session_token="$1"
api_request "GET" "/connection/" "$session_token"
}
# ------------------------------------------------------------------------------
# Récupération des métriques stockage
# ------------------------------------------------------------------------------
get_storage_metrics() {
local session_token="$1"
api_request "GET" "/storage/disk/" "$session_token"
}
# ------------------------------------------------------------------------------
# Calcul du pourcentage HDD
# Parcourt tous les disques et agrège used/total
# ------------------------------------------------------------------------------
compute_hdd_stats() {
local storage_json="$1"
local metric="$2"
local total used percent
total=$(echo "$storage_json" | jq '[.result[]? | .partitions[]? | .total_bytes // 0] | add // 0')
used=$(echo "$storage_json" | jq '[.result[]? | .partitions[]? | .used_bytes // 0] | add // 0')
if [[ "$total" -gt 0 ]]; then
percent=$(echo "scale=2; ($used * 100) / $total" | bc)
else
percent=0
fi
case "$metric" in
hdd_percent) echo "$percent" ;;
hdd_used) echo "$used" ;;
hdd_total) echo "$total" ;;
esac
}
# ------------------------------------------------------------------------------
# MAIN - Sélection de la métrique
# ------------------------------------------------------------------------------
SESSION_TOKEN=$(get_session_token)
case "$METRIC" in
# ---- CPU ------------------------------------------------------------------
cpu_percent)
######## NON DISPONIBLE ATM
SYS=$(get_system_metrics "$SESSION_TOKEN")
echo "$SYS" | jq -r '.result.cpu_usage // 0'
;;
# ---- RAM ------------------------------------------------------------------
ram_percent)
######## NON DISPONIBLE ATM
SYS=$(get_system_metrics "$SESSION_TOKEN")
TOTAL=$(echo "$SYS" | jq -r '.result.total_mem // 1')
USED=$(echo "$SYS" | jq -r '.result.used_mem // 0')
if [[ "$TOTAL" -gt 0 ]]; then
echo "scale=2; ($USED * 100) / $TOTAL" | bc
else
echo "0"
fi
;;
ram_used)
######## NON DISPONIBLE ATM
SYS=$(get_system_metrics "$SESSION_TOKEN")
echo "$SYS" | jq -r '.result.used_mem // 0'
;;
ram_total)
######## NON DISPONIBLE ATM
SYS=$(get_system_metrics "$SESSION_TOKEN")
echo "$SYS" | jq -r '.result.total_mem // 0'
;;
# ---- HDD ------------------------------------------------------------------
hdd_percent|hdd_used|hdd_total)
STORAGE=$(get_storage_metrics "$SESSION_TOKEN")
compute_hdd_stats "$STORAGE" "$METRIC"
;;
# ---- RÉSEAU ---------------------------------------------------------------
net_rate_down)
CONN=$(get_connection_metrics "$SESSION_TOKEN")
echo "$CONN" | jq -r '.result.rate_down // 0'
;;
net_rate_up)
CONN=$(get_connection_metrics "$SESSION_TOKEN")
echo "$CONN" | jq -r '.result.rate_up // 0'
;;
net_bytes_down)
CONN=$(get_connection_metrics "$SESSION_TOKEN")
echo "$CONN" | jq -r '.result.bytes_down // 0'
;;
net_bytes_up)
CONN=$(get_connection_metrics "$SESSION_TOKEN")
echo "$CONN" | jq -r '.result.bytes_up // 0'
;;
net_bw_down)
CONN=$(get_connection_metrics "$SESSION_TOKEN")
echo "$CONN" | jq -r '.result.bandwidth_down // 0'
;;
net_bw_up)
CONN=$(get_connection_metrics "$SESSION_TOKEN")
echo "$CONN" | jq -r '.result.bandwidth_up // 0'
;;
# ---- TEMPÉRATURES ---------------------------------------------------------
temp_cpum)
# Note : Sur la Pop (r1), il n'y a pas de 'temp_cpum', c'est 'temp_t1' et 'temp_t2'
# Je te mets 'temp_t1' par défaut, ou adapte selon ce que tu veux remonter
SYS=$(get_system_metrics "$SESSION_TOKEN")
echo "$SYS" | jq -r '.result.sensors[]? | select(.id=="temp_t1") | .value // 0'
;;
temp_cpub)
SYS=$(get_system_metrics "$SESSION_TOKEN")
echo "$SYS" | jq -r '.result.sensors[]? | select(.id=="temp_cpub") | .value // 0'
;;
temp_sw)
# Note : Pas de 'temp_sw' (Switch) dans ton JSON Pop, on se rabat sur 'temp_t2'
SYS=$(get_system_metrics "$SESSION_TOKEN")
echo "$SYS" | jq -r '.result.sensors[]? | select(.id=="temp_t2") | .value // 0'
;;
temp_hdd)
# Ton JSON confirme 'customer_hdd_slots': 0 et internal_hdd_size: 0 (Pas de HDD)
# On laisse la sécurité à 0 au cas où tu branches un disque USB SMART plus tard
STORAGE=$(get_storage_metrics "$SESSION_TOKEN")
echo "$STORAGE" | jq -r '[.result[]? | .smart_data.temperature // 0] | first // 0'
;;
# ---- VENTILATEUR ----------------------------------------------------------
fan_rpm)
SYS=$(get_system_metrics "$SESSION_TOKEN")
# L'ID dans ton JSON est 'fan0_speed' au lieu de 'fan_rpm'
echo "$SYS" | jq -r '.result.fans[]? | select(.id=="fan0_speed") | .value // 0'
;;
# ---- UPTIME ---------------------------------------------------------------
uptime)
SYS=$(get_system_metrics "$SESSION_TOKEN")
echo "$SYS" | jq -r '.result.uptime_val // 0'
;;
# ---- STATUT DISQUE --------------------------------------------------------
disk_status)
STORAGE=$(get_storage_metrics "$SESSION_TOKEN")
# Retourne 1 si tous les disques sont ok, 0 sinon
ALL_OK=$(echo "$STORAGE" | jq '[.result[]? | select(.state != "ok" and .state != "enabled")] | length == 0')
if [[ "$ALL_OK" == "true" ]]; then
echo "1"
else
echo "0"
fi
;;
*)
log_error "Métrique inconnue : $METRIC"
exit 1
;;
esac
exit 0