Il y a 389 articles et 19 utilisateurs inscrits (ce bandeau est défini dans MediaWiki:Sitenotice)

Script rsync avec copie sur période définies et rapports JSON

De AJLSM
Aller à la navigation Aller à la recherche
  • Transfert rsync avec authentification SSH par clé
  • Fenêtres horaires :
  • Rsync : vendredi 18h → lundi 08h
  • Validation hash : lundi 08h01 → vendredi 17h59
  • Reprise automatique des fichiers en erreur
  • Rapports enrichis JSON + tableau lisible
  • Notifications email à plusieurs destinataires
  • Compatible Systemd Timer pour planification automatique

Exact ✅. Tout se passe depuis le serveur de destination (B) :

  1. Transfert Rsync
  1. *Script transfert_rsync.sh exécuté sur B.

Se connecte via SSH sur le serveur source (A) pour récupérer les fichiers.

Copie les fichiers dans $DST sur B.

Validation Hash

Script validation_hash.sh exécuté sur B.

Compare les fichiers copiés sur B avec ceux du serveur source A via SSH (hash SHA256).

Liste les erreurs/fichiers manquants pour reprise.

Gestion des erreurs et rapports

Tous les logs, fichiers d’erreurs, rapports JSON et tableaux lisibles sont générés localement sur B.

Emails de notification envoyés depuis B.

Donc, le serveur source (A) n’exécute aucun script, il fournit uniquement l’accès SSH pour lire les fichiers.

Arborescence suggérée

/opt/rsync_sync/
├── config.sh
├── transfert_rsync.sh
├── validation_hash.sh
├── logs/
└── reports/

1️⃣ Fichier de configuration : config.sh

#!/bin/bash
# =========================
# Configuration globale
# =========================

# --- Authentification SSH ---
RSYNC_USER="user"
RSYNC_HOST="serveurA"
RSYNC_SSH_OPTS="-i ~/.ssh/rsync_key -p 22"

# --- Répertoires ---
DIRS_TO_COPY=("/var/data" "/var/data2")      # Répertoires sources sur A
DST="/data/replication"                      # Répertoire unique sur B

# --- Options Rsync ---
RSYNC_OPTS="-avz --partial --progress --delete --human-readable --stats --bwlimit=50000"

# --- Fichiers & Dossiers internes ---
LOG_DIR="/opt/rsync_sync/logs"
REPORT_DIR="/opt/rsync_sync/reports"
mkdir -p "$LOG_DIR" "$REPORT_DIR"
ERROR_FILE="$LOG_DIR/errors.txt"
HASH_FILE="$LOG_DIR/rsync_hashes_$(date +%F).txt"

# --- Notifications ---
EMAIL_TO=("admin1@example.com" "admin2@example.com")
EMAIL_SUBJECT_PREFIX="[SYNC SERVEUR A → B]"
MAIL_CMD="mail"  # ou sendmail, selon l’environnement

# --- Fenêtres horaires (documentation pour les scripts) ---
RSYNC_START="Fri 18:00"
RSYNC_END="Mon 08:00"
VALIDATION_START="Mon 08:01"
VALIDATION_END="Fri 17:59"

2️⃣ Script transfert rsync : transfert_rsync.sh

#!/bin/bash
# ===============================================
# TRANSFERT RSYNC SERVEUR A → SERVEUR B
# Objectif :
# - Transférer les fichiers sources depuis A vers B
# - Gérer la reprise automatique des erreurs
# - Générer des rapports JSON + tableau clair
# - Notifier par e-mail les résultats
# ===============================================

source /opt/rsync_sync/config.sh

DATE_TAG=$(date +%F_%H-%M)
LOG_FILE="$LOG_DIR/rsync_transfer_$DATE_TAG.log"
JSON_REPORT="$REPORT_DIR/rsync_report_$DATE_TAG.json"
TABLE_REPORT="$REPORT_DIR/rsync_summary_$DATE_TAG.txt"

echo "==== DÉBUT TRANSFERT $(date) ====" >> "$LOG_FILE"

# --------------------------
# Initialisation des compteurs
# --------------------------
declare -A STATS=(["sources"]=0 ["transferred"]=0 ["errors"]=0 ["retried"]=0)
ERROR_DETAILS="$LOG_DIR/rsync_errors_$DATE_TAG.txt"
> "$ERROR_DETAILS"

# --------------------------
# Boucle sur les répertoires à transférer
# --------------------------
for src_dir in "${DIRS_TO_COPY[@]}"; do
    ((STATS["sources"]++))
    echo "[INFO] Transfert de $src_dir → $DST" >> "$LOG_FILE"

    # 1️⃣ Reprise des erreurs précédentes
    if [ -s "$ERROR_FILE" ]; then
        echo "[INFO] Reprise des erreurs précédentes listées dans $ERROR_FILE" >> "$LOG_FILE"
        rsync_output=$(rsync $RSYNC_OPTS -e "ssh $RSYNC_SSH_OPTS" --files-from="$ERROR_FILE" \
            "$RSYNC_USER@$RSYNC_HOST:$src_dir/" "$DST" 2>&1)
        echo "$rsync_output" >> "$LOG_FILE"

        retried_count=$(echo "$rsync_output" | grep -c '^>')
        STATS["retried"]=$((STATS["retried"] + retried_count))
        > "$ERROR_FILE"
    fi

    # 2️⃣ Transfert principal
    echo "[INFO] Lancement transfert principal depuis $src_dir" >> "$LOG_FILE"
    rsync_output=$(rsync $RSYNC_OPTS -e "ssh $RSYNC_SSH_OPTS" \
        "$RSYNC_USER@$RSYNC_HOST:$src_dir/" "$DST" 2>&1)
    echo "$rsync_output" >> "$LOG_FILE"

    transferred_count=$(echo "$rsync_output" | grep -c '^>')
    error_count=$(echo "$rsync_output" | grep -c 'rsync error')

    STATS["transferred"]=$((STATS["transferred"] + transferred_count))
    STATS["errors"]=$((STATS["errors"] + error_count))

    # 3️⃣ Liste des fichiers transférés pour la validation future
    ssh $RSYNC_SSH_OPTS "$RSYNC_USER@$RSYNC_HOST" "find $src_dir -type f" >> "$HASH_FILE"

    # 4️⃣ Log et rapport des erreurs
    if [ "$error_count" -gt 0 ]; then
        echo "[ERREUR] $error_count erreurs détectées sur $src_dir" >> "$ERROR_DETAILS"
    fi
done

echo "==== FIN TRANSFERT $(date) ====" >> "$LOG_FILE"

# --------------------------
# Génération du rapport JSON
# --------------------------
cat > "$JSON_REPORT" <<EOF
{
  "date": "$(date)",
  "sources": "${DIRS_TO_COPY[*]}",
  "destination": "$DST",
  "stats": {
    "sources_count": ${STATS["sources"]},
    "files_transferred": ${STATS["transferred"]},
    "files_retried": ${STATS["retried"]},
    "errors": ${STATS["errors"]}
  },
  "log_file": "$LOG_FILE",
  "error_details": "$ERROR_DETAILS"
}
EOF

# --------------------------
# Génération du tableau lisible
# --------------------------
cat > "$TABLE_REPORT" <<EOF
===========================
   RAPPORT DE TRANSFERT RSYNC
===========================
Date : $(date)
Sources : ${DIRS_TO_COPY[*]}
Destination : $DST
--------------------------------
Répertoires traités     : ${STATS["sources"]}
Fichiers transférés     : ${STATS["transferred"]}
Reprises d'erreurs       : ${STATS["retried"]}
Erreurs détectées        : ${STATS["errors"]}
--------------------------------
Logs détaillés           : $LOG_FILE
Rapport JSON             : $JSON_REPORT
--------------------------------
EOF

# --------------------------
# Rapport résumé clair dans les logs
# --------------------------
{
  echo "RÉSUMÉ DU TRANSFERT"
  echo "---------------------"
  echo "Répertoires traités : ${STATS["sources"]}"
  echo "Fichiers transférés : ${STATS["transferred"]}"
  echo "Reprises effectuées : ${STATS["retried"]}"
  echo "Erreurs détectées   : ${STATS["errors"]}"
  echo "---------------------"
} >> "$LOG_FILE"

# --------------------------
# Notifications email
# --------------------------
if [ "${#EMAIL_TO[@]}" -gt 0 ]; then
  for mail in "${EMAIL_TO[@]}"; do
    {
      echo -e "Sujet : $EMAIL_SUBJECT_PREFIX Transfert Rsync - $(date)"
      echo
      cat "$TABLE_REPORT"
      if [ "${STATS["errors"]}" -gt 0 ]; then
        echo
        echo "⚠️  Des erreurs Rsync ont été détectées. Voir :"
        echo "   $ERROR_DETAILS"
      fi
    } | $MAIL_CMD -s "$EMAIL_SUBJECT_PREFIX Transfert Rsync - $(date)" "$mail"
  done
fi

exit 0

3️⃣ Script validation hash : validation_hash.sh

#!/bin/bash
# ===============================================
# VALIDATION HASH SERVEUR A → SERVEUR B
# Objectif :
# - Vérifier l’intégrité des fichiers transférés
# - Identifier les erreurs de hash ou fichiers manquants
# - Générer un rapport JSON + tableau clair
# - Envoyer notifications email multi-destinataires
# ===============================================

source /opt/rsync_sync/config.sh

DATE_TAG=$(date +%F_%H-%M)
LOG_FILE="$LOG_DIR/validation_$DATE_TAG.log"
JSON_REPORT="$REPORT_DIR/validation_report_$DATE_TAG.json"
TABLE_REPORT="$REPORT_DIR/validation_summary_$DATE_TAG.txt"

echo "==== DÉBUT VALIDATION HASH $(date) ====" >> "$LOG_FILE"

# --------------------------
# Initialisation des compteurs
# --------------------------
declare -A HASH_STATS=(["checked"]=0 ["ok"]=0 ["errors"]=0 ["missing"]=0)
ERROR_DETAILS="$LOG_DIR/validation_errors_$DATE_TAG.txt"
> "$ERROR_DETAILS"

# --------------------------
# Boucle de validation
# --------------------------
while read -r file; do
    # Calcul du hash source distant
    src_hash=$(ssh $RSYNC_SSH_OPTS "$RSYNC_USER@$RSYNC_HOST" "sha256sum '$file' 2>/dev/null" | awk '{print $1}')
    dest_file="$DST/$(basename "$file")"

    if [ -f "$dest_file" ]; then
        dest_hash=$(sha256sum "$dest_file" | awk '{print $1}')
        if [ "$src_hash" == "$dest_hash" ] && [ -n "$src_hash" ]; then
            ((HASH_STATS["ok"]++))
        else
            ((HASH_STATS["errors"]++))
            echo "$file" >> "$ERROR_FILE"
            echo "[HASH ERROR] $file" >> "$LOG_FILE"
            echo "[HASH ERROR] $file" >> "$ERROR_DETAILS"
        fi
    else
        ((HASH_STATS["missing"]++))
        echo "$file" >> "$ERROR_FILE"
        echo "[MISSING] $file" >> "$LOG_FILE"
        echo "[MISSING] $file" >> "$ERROR_DETAILS"
    fi

    ((HASH_STATS["checked"]++))
done < "$HASH_FILE"

echo "==== FIN VALIDATION HASH $(date) ====" >> "$LOG_FILE"

# --------------------------
# Génération du rapport JSON
# --------------------------
cat > "$JSON_REPORT" <<EOF
{
  "date": "$(date)",
  "stats": {
    "files_checked": ${HASH_STATS["checked"]},
    "hash_ok": ${HASH_STATS["ok"]},
    "hash_errors": ${HASH_STATS["errors"]},
    "missing_files": ${HASH_STATS["missing"]}
  },
  "log_file": "$LOG_FILE",
  "errors_file": "$ERROR_DETAILS",
  "error_list_file": "$ERROR_FILE"
}
EOF

# --------------------------
# Génération du tableau lisible
# --------------------------
cat > "$TABLE_REPORT" <<EOF
==============================
  VALIDATION HASH - SYNTHÈSE
==============================
Date : $(date)
--------------------------------
Fichiers vérifiés     : ${HASH_STATS["checked"]}
Conformes (hash OK)   : ${HASH_STATS["ok"]}
Erreurs de hash        : ${HASH_STATS["errors"]}
Fichiers manquants     : ${HASH_STATS["missing"]}
--------------------------------
Logs détaillés         : $LOG_FILE
Erreurs détaillées     : $ERROR_DETAILS
Rapport JSON           : $JSON_REPORT
--------------------------------
EOF

# --------------------------
# Rapport résumé clair dans les logs
# --------------------------
{
  echo "RÉSUMÉ VALIDATION HASH"
  echo "------------------------"
  echo "Total vérifiés : ${HASH_STATS["checked"]}"
  echo "OK : ${HASH_STATS["ok"]}"
  echo "Erreurs : ${HASH_STATS["errors"]}"
  echo "Manquants : ${HASH_STATS["missing"]}"
  echo "------------------------"
} >> "$LOG_FILE"

# --------------------------
# Notifications email
# --------------------------
if [ "${#EMAIL_TO[@]}" -gt 0 ]; then
  for mail in "${EMAIL_TO[@]}"; do
    {
      echo -e "Sujet : $EMAIL_SUBJECT_PREFIX Validation Hash - $(date)"
      echo
      cat "$TABLE_REPORT"
      if [ "${HASH_STATS["errors"]}" -gt 0 ] || [ "${HASH_STATS["missing"]}" -gt 0 ]; then
        echo
        echo "⚠️  Des erreurs ont été détectées. Voir détails dans :"
        echo "   $ERROR_DETAILS"
      fi
    } | $MAIL_CMD -s "$EMAIL_SUBJECT_PREFIX Validation Hash - $(date)" "$mail"
  done
fi

exit 0

4️⃣ Workflow visuel avec fenêtres horaires

Vendredi 18h                  Lundi 08h01                 Vendredi 17h59
+-----------------------------+---------------------------+
|                             |                           |
|     TRANSFERT RSYNC         |   VALIDATION HASH         |
|  (reprise erreurs + copie)  |   (fichiers copiés)      |
|                             |                           |
+-----------------------------+---------------------------+

Cycle :
- Les fichiers en erreur sont ajoutés à errors.txt
- Week-end suivant, rsync reprend les erreurs en priorité
- Transfert incrémental pour nouveaux fichiers
- Validation hash continue en semaine

Ordonnancement

5️⃣ Systemd Services et Timers

1️⃣ Rsync Transfer Service

Service rsync : /etc/systemd/system/rsync_sync.service

[Unit]
Description=Transfert Rsync serveur A → B
After=network.target

[Service]
Type=oneshot
ExecStart=/opt/rsync_sync/transfert_rsync.sh
User=root

Timer rsync : /etc/systemd/system/rsync_sync.timer

[Unit]
Description=Planification Transfert Rsync (Ven 18h → Lun 08h)

[Timer]
# Début vendredi 18h
OnCalendar=Fri 18:00
# Persistant pour lancer le transfert même si l'heure est passée
Persistent=true

[Install]
WantedBy=timers.target

2️⃣ Validation Hash Service

Service validation hash : /etc/systemd/system/validation_hash.service

[Unit]
Description=Validation Hash serveur A → B
After=network.target

[Service]
Type=oneshot
ExecStart=/opt/rsync_sync/validation_hash.sh
User=root

Timer validation hash : /etc/systemd/system/validation_hash.timer

[Unit]
Description=Planification Validation Hash (Lun 08h01 → Ven 17h59)

[Timer]
# Début lundi 08h01
OnCalendar=Mon 08:01
Persistent=true

[Install]
WantedBy=timers.target

e) Activer les timers

sudo systemctl daemon-reload

# Activer et démarrer Rsync timer
sudo systemctl enable --now rsync_sync.timer

# Activer et démarrer Validation Hash timer
sudo systemctl enable --now validation_hash.timer

# Vérification des timers actifs
systemctl list-timers | grep rsync_sync
systemctl list-timers | grep validation_hash

Notes importantes

  • User=root : à adapter pour exécuter les scripts avec un utilisateur non privilégié.
  • Les timers ne définissent que l’heure de départ. Les scripts eux-mêmes gèrent le traitement complet (reprise, logs, hash).
  • Persistent=true permet de lancer le job si le serveur était éteint au moment prévu.
  • Les logs et rapports se trouvent dans /opt/rsync_sync/logs et /opt/rsync_sync/reports.

Crontab

1️⃣ Planification rsync via cron (vendredi 18h → lundi 08h)

  1. Ouvrir le crontab pour l’utilisateur qui exécute le script :
    crontab -e
    
  2. Ajouter la ligne suivante pour lancer le transfert vendredi 18h :
    0 18 * * 5 /opt/rsync_sync/transfert_rsync.sh
    
    0 18 * * 5 → vendredi à 18h00
  3. Ajouter une ligne optionnelle pour assurer le démarrage lundi 08h (au cas où le transfert serait interrompu ou pour reprise) :
    0 8 * * 1 /opt/rsync_sync/transfert_rsync.sh
    
    0 8 * * 1 → lundi 08h00

Les scripts incluent déjà un contrôle de fin de fenêtre (RSYNC_END) pour arrêter le transfert lundi 08h00.

2️⃣ Planification validation hash via cron (lundi 08h01 → vendredi 17h59)

  1. Toujours dans le crontab :
    1 8 * * 1 /opt/rsync_sync/validation_hash.sh
    
    Lancement lundi 08h01
  2. Optionnel : relancer la validation toutes les heures pendant la semaine, pour traiter les fichiers par lots si nécessaire :
    0 9-17 * * 1-5 /opt/rsync_sync/validation_hash.sh
    
    De 9h à 17h du lundi au vendredi, toutes les heures. Le script s’arrête automatiquement si la fenêtre VALIDATION_END (vendredi 17h59) est dépassée

3️⃣ Avantages de cette version cron

Compatible tous serveurs Linux/Unix

  • Même logique que Systemd :
  • Reprise automatique des erreurs
  • Fenêtres horaires respectées
  • Rapports JSON + tableau lisible
  • Notifications email

Facile à tester sans redémarrer le daemon systemd