2.1 #2
1 changed files with 122 additions and 18 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue