Corrections et améliorations v2.1.0

Corrections critiques :
- Bug triple_health_check : fait maintenant 3 vraies tentatives au lieu de s'arrêter au 1er échec
- Optimisation get_pool_disk_uuids : ls au lieu de find (gain performance)
- Nettoyage logging verbeux dans handle_health_failure

Nouveau système de notifications Proxmox :
- Mode INFO : toutes les notifications (succès, échecs, migrations)
- Mode ERROR : erreurs uniquement (disques, pools dégradés)
- Intégration pvesh pour Proxmox VE 8+/9.x
- Notifications sur : réplication réussie/échouée, migrations LXC, disques manquants, pools dégradés, espace disque critique

Configuration :
- NOTIFICATION_ENABLED=true
- NOTIFICATION_MODE="INFO" ou "ERROR"
- Nécessite configuration notification target dans Proxmox GUI
This commit is contained in:
Tellsanguis 2025-12-29 11:28:33 +01:00
parent c61661523c
commit f758beeee2

View file

@ -52,6 +52,11 @@ LOG_RETENTION_DAYS=14
HEALTH_CHECK_MIN_FREE_SPACE=5 # Pourcentage minimum d'espace libre HEALTH_CHECK_MIN_FREE_SPACE=5 # Pourcentage minimum d'espace libre
HEALTH_CHECK_ERROR_COOLDOWN=3600 # Anti-ping-pong: 1 heure en secondes HEALTH_CHECK_ERROR_COOLDOWN=3600 # Anti-ping-pong: 1 heure en secondes
# Configuration des notifications Proxmox
NOTIFICATION_ENABLED=true # Activer/désactiver les notifications
NOTIFICATION_MODE="INFO" # "INFO" (toutes les notifs) ou "ERROR" (erreurs uniquement)
# Note: Configurer les notification targets dans Proxmox GUI: Datacenter > Notifications
# Initialiser le répertoire de logs # Initialiser le répertoire de logs
init_logging() { init_logging() {
mkdir -p "$LOG_DIR" mkdir -p "$LOG_DIR"
@ -95,6 +100,54 @@ log() {
fi fi
} }
# Fonction d'envoi de notifications Proxmox
send_notification() {
local severity="$1" # "info" ou "error"
local title="$2"
local message="$3"
# Vérifier si les notifications sont activées
if [[ "${NOTIFICATION_ENABLED}" != "true" ]]; then
return 0
fi
# Filtrer selon le mode de notification
if [[ "${NOTIFICATION_MODE}" == "ERROR" ]] && [[ "$severity" != "error" ]]; then
# Mode ERROR: ignorer les notifications info
return 0
fi
# Préparer le corps du message
local hostname
hostname=$(hostname)
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local full_message="[${hostname}] [${timestamp}]
${message}
Script: zfs-nfs-replica v${SCRIPT_VERSION}
Nœud: ${hostname}"
# Tenter d'envoyer via le système de notifications Proxmox
# Pour Proxmox VE 8+/9.x, utiliser pvesh avec le système de notifications
if command -v pvesh >/dev/null 2>&1; then
# Essayer d'envoyer via l'API Proxmox
# Note: Nécessite configuration d'un notification target dans Proxmox GUI
pvesh create /cluster/notifications/targets/sendmail/notify \
--severity "$severity" \
--title "ZFS NFS HA: ${title}" \
--body "$full_message" \
>/dev/null 2>&1 || {
# Si pvesh échoue (pas de target configuré), logger en warning
log "warning" "Notification non envoyée (configurer notification target dans Proxmox GUI)"
}
else
# Fallback si pvesh n'existe pas (ne devrait pas arriver sur Proxmox)
log "warning" "pvesh non disponible - notifications désactivées"
fi
}
# Fonction d'auto-update # Fonction d'auto-update
auto_update() { auto_update() {
# Vérifier si l'auto-update est activé # Vérifier si l'auto-update est activé
@ -348,28 +401,32 @@ get_pool_disk_uuids() {
return 0 return 0
fi fi
# Pour chaque device, résoudre vers /dev/disk/by-id/ # Pour chaque device, résoudre vers /dev/disk/by-id/ (méthode optimisée)
local uuids=() local uuids=()
while read -r device; do while read -r device; do
if [[ -z "$device" ]]; then if [[ -z "$device" ]]; then
continue continue
fi fi
# Résoudre le device vers ses liens dans /dev/disk/by-id/ # Résoudre le device réel
local device_id local device_real
device_id=$(find /dev/disk/by-id/ -type l -exec readlink -f {} \; 2>/dev/null | \ device_real=$(readlink -f "$device" 2>/dev/null)
grep -F "$(readlink -f "$device" 2>/dev/null)" | \
head -1)
if [[ -n "$device_id" ]]; then if [[ -z "$device_real" ]]; then
# Extraire juste le nom du fichier (wwn-*, ata-*, etc.) continue
local uuid_name fi
uuid_name=$(basename "$device_id")
# Filtrer pour ne garder que les identifiants persistants # Chercher les liens dans /dev/disk/by-id/ pointant vers ce device
if [[ "$uuid_name" =~ ^(wwn-|ata-|scsi-|nvme-) ]]; then # Méthode optimisée: ls -l au lieu de find
local found_uuids
found_uuids=$(ls -l /dev/disk/by-id/ 2>/dev/null | \
awk -v target="$(basename "$device_real")" '$NF == target {print $(NF-2)}' | \
grep -E '^(wwn-|ata-|scsi-|nvme-)' || true)
if [[ -n "$found_uuids" ]]; then
while read -r uuid_name; do
uuids+=("$uuid_name") uuids+=("$uuid_name")
fi done <<< "$found_uuids"
fi fi
done <<< "$devices" done <<< "$devices"
@ -483,6 +540,11 @@ verify_disk_presence() {
if [[ $missing_disks -gt 0 ]]; then if [[ $missing_disks -gt 0 ]]; then
log "error" "${missing_disks} disque(s) manquant(s) pour ${pool}" log "error" "${missing_disks} disque(s) manquant(s) pour ${pool}"
send_notification "error" "Disque(s) manquant(s) - ${pool}" \
"${missing_disks} disque(s) manquant(s) détecté(s) pour le pool ${pool}.
Vérifier les connexions USB/SATA et l'état des disques.
Une migration automatique du LXC peut être déclenchée."
return 1 return 1
else else
log "info" "✓ Tous les disques présents pour ${pool}" log "info" "✓ Tous les disques présents pour ${pool}"
@ -506,6 +568,11 @@ check_pool_health_status() {
if [[ "$pool_health" != "ONLINE" ]]; then if [[ "$pool_health" != "ONLINE" ]]; then
log "error" "Pool ${pool} en état dégradé: ${pool_health}" log "error" "Pool ${pool} en état dégradé: ${pool_health}"
send_notification "error" "Pool ZFS ${pool_health} - ${pool}" \
"Le pool ZFS ${pool} est en état ${pool_health}.
Vérifier l'état des disques avec: zpool status ${pool}
Une migration automatique du LXC peut être déclenchée."
health_issues=$((health_issues + 1)) health_issues=$((health_issues + 1))
else else
log "info" "✓ Pool ${pool} status: ONLINE" log "info" "✓ Pool ${pool} status: ONLINE"
@ -520,6 +587,13 @@ check_pool_health_status() {
if [[ $capacity -ge $min_capacity ]]; then if [[ $capacity -ge $min_capacity ]]; then
log "error" "Espace disque critique pour ${pool}: ${capacity}% utilisé (seuil: ${min_capacity}%)" log "error" "Espace disque critique pour ${pool}: ${capacity}% utilisé (seuil: ${min_capacity}%)"
send_notification "error" "Espace disque critique - ${pool}" \
"Le pool ${pool} est presque plein: ${capacity}% utilisé.
Seuil critique: ${min_capacity}%
Espace libre restant: $((100 - capacity))%
ACTION REQUISE: Libérer de l'espace ou agrandir le pool."
health_issues=$((health_issues + 1)) health_issues=$((health_issues + 1))
else else
local free_percent=$((100 - capacity)) local free_percent=$((100 - capacity))
@ -732,8 +806,6 @@ triple_health_check() {
log "info" "Vérification santé #${i}/3 réussie pour ${pool}" log "info" "Vérification santé #${i}/3 réussie pour ${pool}"
else else
log "error" "Vérification santé #${i}/3 échouée pour ${pool}" log "error" "Vérification santé #${i}/3 échouée pour ${pool}"
# Ne pas continuer si une vérification échoue
return 1
fi fi
# Délai entre les vérifications (sauf après la dernière) # Délai entre les vérifications (sauf après la dernière)
@ -832,8 +904,16 @@ handle_health_failure() {
log "error" "Action: ARRÊT du LXC ${CTID} pour éviter ping-pong" log "error" "Action: ARRÊT du LXC ${CTID} pour éviter ping-pong"
# Arrêter le LXC # Arrêter le LXC
if pct stop "$CTID" 2>&1 | while read -r line; do log "info" "$line"; done; then if pct stop "$CTID" >/dev/null 2>&1; then
log "error" "✓ LXC ${CTID} arrêté avec succès" log "error" "✓ LXC ${CTID} arrêté avec succès"
send_notification "error" "Arrêt LXC (anti-ping-pong)" \
"Le LXC ${CTID} a été arrêté pour éviter un ping-pong.
Pool: ${pool}
Raison: ${failure_reason}
Erreur précédente: ${last_error_time}
ACTION REQUISE: Vérifier l'état des disques et pools sur les deux nœuds avant de redémarrer le LXC."
record_critical_error "$pool" "$failure_reason" "lxc_stopped" record_critical_error "$pool" "$failure_reason" "lxc_stopped"
return 0 return 0
else else
@ -847,8 +927,17 @@ handle_health_failure() {
log "warning" "Action: MIGRATION du LXC ${CTID} vers ${REMOTE_NODE_NAME}" log "warning" "Action: MIGRATION du LXC ${CTID} vers ${REMOTE_NODE_NAME}"
# Tenter la migration via HA # Tenter la migration via HA
if ha-manager migrate "ct:${CTID}" "$REMOTE_NODE_NAME" 2>&1 | while read -r line; do log "info" "$line"; done; then if ha-manager migrate "ct:${CTID}" "$REMOTE_NODE_NAME" >/dev/null 2>&1; then
log "warning" "✓ Migration HA initiée vers ${REMOTE_NODE_NAME}" log "warning" "✓ Migration HA initiée vers ${REMOTE_NODE_NAME}"
send_notification "error" "Migration LXC vers ${REMOTE_NODE_NAME}" \
"Le LXC ${CTID} a été migré vers ${REMOTE_NODE_NAME} suite à un problème de santé.
Pool: ${pool}
Raison: ${failure_reason}
Nœud source: $(hostname)
Nœud destination: ${REMOTE_NODE_NAME}
Le service NFS devrait continuer à fonctionner sur le nœud distant."
record_critical_error "$pool" "$failure_reason" "lxc_migrated" record_critical_error "$pool" "$failure_reason" "lxc_migrated"
return 0 return 0
else else
@ -856,7 +945,7 @@ handle_health_failure() {
log "error" "Tentative d'arrêt du LXC en dernier recours" log "error" "Tentative d'arrêt du LXC en dernier recours"
# Fallback: arrêter le LXC si la migration échoue # Fallback: arrêter le LXC si la migration échoue
if pct stop "$CTID" 2>&1 | while read -r line; do log "info" "$line"; done; then if pct stop "$CTID" >/dev/null 2>&1; then
log "error" "✓ LXC ${CTID} arrêté en dernier recours" log "error" "✓ LXC ${CTID} arrêté en dernier recours"
record_critical_error "$pool" "$failure_reason" "lxc_stopped_failsafe" record_critical_error "$pool" "$failure_reason" "lxc_stopped_failsafe"
return 0 return 0
@ -1149,8 +1238,23 @@ log "info" "=========================================="
if [[ $POOLS_FAILED -eq 0 ]]; then if [[ $POOLS_FAILED -eq 0 ]]; then
log "info" "✓ Toutes les réplications ont réussi" log "info" "✓ Toutes les réplications ont réussi"
send_notification "info" "Réplication ZFS réussie" \
"Toutes les réplications ZFS ont réussi.
Pools répliqués: ${POOLS_TOTAL}
Succès: ${POOLS_SUCCESS}
Nœud actif: $(hostname)
Nœud distant: ${REMOTE_NODE_NAME}"
exit 0 exit 0
else else
log "error" "${POOLS_FAILED} pool(s) ont échoué" log "error" "${POOLS_FAILED} pool(s) ont échoué"
send_notification "error" "Échec réplication ZFS" \
"${POOLS_FAILED} pool(s) ont échoué lors de la réplication.
Total: ${POOLS_TOTAL}
Succès: ${POOLS_SUCCESS}
Échecs: ${POOLS_FAILED}
Vérifier les logs: /var/log/zfs-nfs-replica/"
exit 1 exit 1
fi fi