the_matrix_has_you Welcome, to the real world | Bonjour à tous,
Je suis entrain de mettre en place un système de sauvegarde des données de mon NAS vers un NAS distant hébergé chez un ami et réciproquement pour ses données. Le tout est basé sur rsync, j'ai écrit un bout de script pour gérer le tout mais c'est un peu mon premier script. Etant donné qu'il s'agit quand même d'une application "sensible" pour l'intégrité des données, j'aimerai savoir si je me suis complètement planté ou non.
Désolé, ça va faire une grosse page de code balancée comme ça mais j'ai commenté un maximum pour m'y retrouver.
Le principe de base est en gros de faire des snapshots : je fais de l'incrémental pour récupérer les données modifiées entre 2 sauvegardes, le reste est constitué de lien en dur.
Code :
- #!/bin/bash
- # Version 2.2 - sauvegarde_nuit
- #
- #-------------------------------------------------------------------------------------------------------------------------------------------#
- # SYNCHRONISATION DISTANTE DES DONNES PAR RSYNC ENTRE 2 NAS
- #
- #Il créé un fichier flag, témoin de son lancement, puis démarre une sauvegarde miroir depuis une machine distante vers celle qui l'héberge
- #Lors du démarrage, il contrôle la présence du fichier flag, si celui ci est présent c'est qu'une synchro rsync est déjà en cours,
- #on la stoppe avec le signal SIGUSR1 (code retour 19 de rsync). Ceci fermera également le script qui l'a lancé
- #
- #Le script lance ensuite un "dry run" pour tester la connexion et lister le volume de données à envoyer. Les stats sont envoyées dans le
- #fichier de flag. Si tout s'est bien passé on lance la synchronisation réelle : d'abord mise à jour des dossiers puis des fichiers
- #
- #En cas d'erreur de rsync ou de sauvegarde de la veille non terminée, on envoie un mail pour alerter l'administrateur
- #En cas de bonne exécution, le fichier flag est transformé en fichier log dans le dossier de la sauvegarde
- #
- #Le script utilise une version patchée de rsync incluant l'option --detect-renamed pour ne pas retransférer des fichiers renommés ou
- #déplacés
- #-------------------------------------------------------------------------------------------------------------------------------------------#
- #VARIABLES ET CONFIGURATION
- #**********************************************************************************
- #Variables modifiables :
- DOSS_SCRIPT="/mnt/pool_sauv_distante_mickael/Scripts" #Dossier abritant ce script
- NOM_FLAG="flag_nuit" #Nom du fichier "flag" (sans extension)
- EXTENSION=".log" #Extension à ajouter aux fichiers logs générés
- DOSSIER_SOURCE="/mnt/Tank/" #Dossier source à sauvegarder
- NAS_DISTANT=192.168.0.2 #Adresse du serveur source
- PORT=22 #Port du service ssh serveur source
- USER="Toto" #Nom d'utilisateur source
- CIBLE="/mnt/pool_sauv_distante_toto/Sauvegardes" #Dossier de destination des sauvegardes (un dossier par date est créé ensuite à l'intérieur)
- USER_CIBLE="toto2" #Nom d'utilisateur serveur destination
- EXCLUS="/mnt/pool_sauv_distante_toto/Scripts/liste.txt" #Liste des fichiers et dossiers à exclure de la sauvegarde
- BP_LIMITE=100 #Bande passante maximale en ko/s. 0 = pas de limite
- #Configuration :
- MAIL_SUCCES=1 #Mettre à 0 pour ne pas recevoir le rapport de sauvegarde par mail en cas de succès. Aucune influence sur les rapports d'erreur
- #FIN DES VARIABLES ET DE LA CONFIGURATION, NE PAS MODIFIER PLUS BAS
- #*******************************************************************************************************************************************
- # La fonction envoi_mail gère l'ajout des textes explicatifs et l'envoi des mails aux utilisateurs
- #elle a peu d'interêt ici, je vous l'épargne
- # La fonction copie_liens permet de créer au début de la sauvegarde l'image précedente en faisant une copie de la
- #sauvegarde N-1 par des liens en durs, cette copie sera ensuite exploitée par rsync pour la mettre à jour.
- # L'utilisation de ce système à la place de l'option --link-dest de rsync permet d'utiliser l'option --detect-renamed de
- #rsync
- #----------------------------------------------------------------------------------------------------------------------
- function copie_liens()
- {
- cp -alL $CIBLE/courante $CIBLE/000_$date_jour 2>> $flag #copie (liens durs) de la sauvegarde courante. Sert de base et est mise à jour ensuite
- echo -e '\nCopie image courante terminée...' >> $flag
- }
- # La fonction lien_courante permet de mettre à jour le lien symbolique "courante" sur la sauvegarde distante
- # qui pointe vers la sauvegarde actuelle (c'est l'image courante)
- # La fonction reçoit un argument qui est le dossier à lier au dossier "courante"
- #----------------------------------------------------------------------------------------------------------------------
- function lien_courante()
- {
- rm -rf $CIBLE/courante 2>> $flag #Suppression du dossier de la sauvegarde courante...
- ln -s $CIBLE/$1 $CIBLE/courante 2>> $flag #... et recréation (en fait un simple lien vers la sauvegarde du jour)
- }
- # La fonction rotation_sauvegardes permet d'incrémenter le numéro des dossiers contenant les sauvegardes en conservant la date, par
- # exemple : 005_2012-12-12 est renommé en 006_2012-12-12. La sauvegarde numero 999 est supprimée.
- # Cette fonction supprime également les sauvegardes incompletes (nom de dossier se terminant par _incomplete) à partir de la 25eme sauvegarde
- function rotation_sauvegarde()
- {
- if ls $CIBLE/999_* > /dev/null 2>&1; then #suppression de la sauvegarde numéro 999 si elle existe
- echo "suppression de la sauvegarde 999" >> $flag
- rm -rf $CIBLE/999_* 2>> $flag
- fi
- for i in {999..0} #boucle de 999 à 0
- do
- ichaine=$(printf "%.3d" $i) #génère le numéro de sauvegarde sur 3 chiffres
- if [ $i -gt 25 ] && find $CIBLE/${ichaine}_*_incomplete -maxdepth 0 > /dev/null 2>&1; then #à partir de la 25eme sauvegarde (et après) on teste si c'est une incomplète
- echo "suppression de la sauvegarde incomplète ${ichaine}" >> $flag
- rm -r $CIBLE/${ichaine}_*_incomplete 2>> $flag #si c'est une incomplète, on la supprime
- fi
- if ls $CIBLE/${ichaine}_* > /dev/null 2>&1; then #test de l'existence de la sauvegarde n
- for k in $CIBLE/${ichaine}_*; do #si existe on récupère son nom complet (avec chemin et date)
- let j=$i+1 #génére le numéro n+1 sur 3 chiffres
- j=$(printf "%.3d" $j)
- k=${k#${CIBLE}/} #supprime la partie chemin du nom de sauvegarde
- mv $CIBLE/$k $CIBLE/${j}${k#$ichaine} 2>> $flag #renomme la sauvegarde n en n+1
- done
- fi
- done
- }
- # La fonction suppression sauvegarde permet de supprimer les anciennes sauvegardes en en gardant 1 seule par interval défini. Elle reçoit
- # 3 paramètres : une butée haute, une butée basse et un interval (dans cet ordre). La série entre les deux butées est divisées en intervals
- # de la longueur définie par le paramètre interval puis une seule sauvegarde est conservée dans celui ci.
- #Note : si la longueur de la série entre les butées n'est pas divisible par l'interval, le reste ne correspondant pas à un interval complet est
- #ignoré (ex : de 100 à 75 par pas de 10 : on garde une sauvegarde entre 100 et 91, une entre 90 et 81 mais rien n'est supprimé entre 80 et 75
- #-----------------------------------------------------------------------------------------------------------------------------------------------
- function suppression_sauvegardes()
- {
- let start=$1 # initialise la première boucle avec la butée haute passée en paramètre
- let stop=$start-$3+1 # initialise la première boucle avec le calcul de stop (start-pas+1)
- let fin=$2 # récupère la butée basse en paramètre n°3
- while [ $stop -ge $fin ] # Cette boucle génère les bornes entre les butées hautes, basses et avec l'interval passé en paramètre
- do
- f=0 #initialise le flag
- for ((i=$start;i>=$stop;--i)) #boucle entre les bornes start - stop
- do
- ichaine=$(printf "%.3d" $i)
- if ls $CIBLE/${ichaine}_* > /dev/null 2>&1; then #teste si on a une sauvegarde qui porte ce numéro
- if [ $f -eq 0 ]; then #si on en a une on regarde si c'est la première
- let f=1 #si oui, on positionne le flag pour dire qu'on en a une
- else
- k=$(find $CIBLE/${ichaine}_* -maxdepth 0)
- echo "suppression de la sauvegarde "${k#${CIBLE}/} >> $flag #si ce n'est pas la première, on la supprime
- rm -r $CIBLE/${k#${CIBLE}/} 2>> $flag
- fi
- fi
- done
- let start=$stop-1 #calculs prochaine bornes
- let stop=$start-$3+1
- done
- }
- #Programme principal, contrôle l'état actuel, prépare le dossier de sauvegarde, lance une analyse (dry-run rsync),
- #puis copie l'arborescence des dossiers (sans supprimer les anciens) afin de permettre le bon fonctionnement de --detect-renamed
- #en cas de fichiers déplacés ou dossiers renommés et enfin lance la sauvegarde effective des fichiers.
- #Inclus le contrôle des codes retour des fonctions principales pour s'assurer de la bonne exécution.
- #----------------------------------------------------------------------------------------------------------------------
- flag=$DOSS_SCRIPT/$NOM_FLAG$EXTENSION #définition du fichier de flag
- SOURCE=$USER@$NAS_DISTANT:$DOSSIER_SOURCE
- #Si il y a encore un fichier flag => la synchro de la veille n'est peut être pas terminée
- if [ -e $flag ]; then
- pkill -SIGUSR1 -f -u $USER_CIBLE rsync #ferme Rsync avec le signal SIGUSR1 (le signal est testé par le script de la veille et lui signal de se fermer également)
- sleep 120 #Tempo 120 secondes
- date_veille=$(head -n 1 $flag | cut -c15-) #récupère la date sauvegarde précédente (dans 1ere ligne du fichier flag)
- if [ -e $DOSS_SCRIPT/log/$date_veille-incomplete$EXTENSION ]; then #teste l'existence d'un fichier date-incomplète dans les logs correspondant à la sauvegarde ci dessus
- envoi_mail 1
- rotation_sauvegarde #effectue la rotation des sauvegardes (renommage n en n+1)
- lien_courante 001_$date_veille #met à jour le lien pour que le dossier "courante" pointe vers la sauvegarde précédente(incomplète)
- else
- envoi_mail 2 # mail sauvegarde non terminée cause arrêt NAS ou plantage script => ne pas lier courante, sauvegarde non fiable
- fi
- fi
- date_jour=$(date +%Y-%m-%d) #Enregistrement date du jour
- #Effacement et reCréation du fichier de flag :
- echo 'SAUVEGARDE DU '$date_jour > $flag #NE PAS MODIFIER CETTE LIGNE
- #Création du dossier de sauvegarde du jour : on recopie en liens l'image courante :
- copie_liens
- #on commence par un lancement de rsync en mode dry run pour lister dans le fichier de flag les fichiers à synchroniser (uniquement pour les statistiques)
- echo -e 'Début analyse du volume à '$(date +%H:%M:%S) >> $flag
- echo -e 'Rapport analyse, à synchroniser ce soir :\n----------------------------------------------' >> $flag
- $DOSS_SCRIPT/rsync -ahzn -e "ssh -p "$PORT --stats --timeout=60 --delete --exclude-from=$EXCLUS $SOURCE $CIBLE/000_$date_jour >> $flag 2>&1
- retval=$? #enregistre le code retour de rsync
- if [ $retval -ne 0 ]; then #contrôle du code retour
- #si erreur (clés ssh, connexion, serveur distant éteind, indisponible, ...)
- echo -e '\nErreur d execution. Suppression du dossier 000_'$date_jour >> $flag
- rm -r $CIBLE/000_$date_jour >> $flag 2>&1
- envoi_mail 3
- mv $flag $DOSS_SCRIPT/log/$date_jour-erreur$EXTENSION #déplacement du flag dans le dossier des log et renommage
- exit
- fi
- #Copie de l'arborescence des dossiers uniquement (ordre des includes/exclude important, pas de --delete)
- echo -e '\nDébut mise à jour arborescence à '$(date +%H:%M:%S) >> $flag
- $DOSS_SCRIPT/rsync -ahz -e "ssh -p $PORT" --timeout=60 --exclude-from=$EXCLUS --include='*/' --exclude='*' $SOURCE $CIBLE/000_$date_jour >> $flag 2>&1
- retval=$? #enregistre le code retour de rsync
- if [ $retval -ne 0 ]; then #contrôle du code retour
- #si erreur (clés ssh, connexion, serveur distant éteind, indisponible, ...)
- echo -e '\nErreur d execution. Suppression du dossier 000_'$date_jour >> $flag
- rm -r $CIBLE/000_$date_jour >> $flag 2>&1
- envoi_mail 5
- mv $flag $DOSS_SCRIPT/log/$date_jour-erreur$EXTENSION #déplacement du flag dans le dossier des log et renommage
- exit
- fi
- echo -e 'Mise à jour arborescence terminée à '$(date +%H:%M:%S) >> $flag
- #Lancement de la synchro réelle :
- echo -e '\n\nDébut de sauvegarde à '$(date +%H:%M:%S) >> $flag
- echo -e 'Rapport de sauvegarde :\n----------------------------------------------' >> $flag
- $DOSS_SCRIPT/rsync -ahz -e "ssh -p $PORT" --stats --delete --delete-excluded --detect-renamed --timeout=60 --bwlimit=$BP_LIMITE --partial --partial-dir="tempRsync" --exclude-from=$EXCLUS $SOURCE $CIBLE/000_$date_jour >> $flag 2>&1
- retval=$? #enregistrement et contrôle du code retour
- if [ $retval -eq 19 ]; then #si rsync est quitté avec le code 19 (SIGUSR1) alors copie le flag en log et quitte le script car une nouvelle occurence du script s'est lancée...
- cp $flag $DOSS_SCRIPT/log #ATTENTION : Pas de mv direct du fichier de flag dans log car l'autre instance du script en a besoin
- mv $DOSS_SCRIPT/log/$NOM_FLAG$EXTENSION $DOSS_SCRIPT/log/$date_jour-incomplete$EXTENSION #renommage du fichier flag en log
- mv $CIBLE/000_$date_jour $CIBLE/000_${date_jour}_incomplete #renommage du dossier avec ajout du suffixe "incomplete"
- exit
- elif [ $retval -eq 0 ]; then #si rsync est quitté normalement, déroulement normal...
- echo -e '\nSauvegarde terminée à '$(date +%H:%M:%S)'\nRotation des sauvegardes...' >> $flag
- rotation_sauvegarde #Effectue le renommage de toutes les sauvegardes n en n+1 (rotation)
- echo 'Rotation terminée, effacement et recréation du dossier de sauvegarde courante...' >> $flag
- lien_courante 001_$date_jour #Suppression du dossier de la sauvegarde courante et recréation (en fait un simple lien vers la sauvegarde du jour)
- suppression_sauvegardes 1000 401 200 #Suppression de quelques anciennes sauvegardes avec une répartition variable selon l'ancienneté
- suppression_sauvegardes 400 131 30
- suppression_sauvegardes 130 41 10
- envoi_mail 9
- mv $flag $DOSS_SCRIPT/log/$date_jour$EXTENSION #...déplace et renomme le fichier flag dans les logs
- elif [ $retval -ne 0 ]; then #si on a une erreur autre :
- echo -e '\nErreur d execution. Suppression du dossier 000_'$date_jour >> $flag
- rm -r $CIBLE/000_$date_jour >> $flag 2>&1
- envoi_mail 4
- mv $flag $DOSS_SCRIPT/log/$date_jour-erreur$EXTENSION #déplace le fichier de flag dans le dossier des logs et le renomme
- exit
- fi
|
Ça fait un gros pâté , pas moyen de colorer sur le forum ?
Merci à vous en tout cas !
Edit : coloration des commentaires pour essayer de gagner en lisibilité Message édité par the_matrix_has_you le 02-04-2013 à 10:49:10
|