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

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