SVN Stratégie Backup (Update)
Un premier article avait été rédigé SVN Stratégie Backup. Une mise à jour est réalisée dans le script svn_backup.sh
, mais comme la page initiale ayant été notée, une copie est réalisée pour ne pas avoir une note sur un nouveau script.
L'utilisation d'un serveur de source permet de suivre les modifications dans le code des projets. Mais il serait dommage de tout perdre si le serveur venait à être corrompu. Il est donc important d'effectuer régulièrement des sauvegardes des dépôts. Cet article présente la mise en place d'une telle stratégie, sous Ubuntu, permettant de réaliser:
- 1 sauvegarde incrémentale tous les matins, sauf le lundi.
- 1 sauvegarde complète le lundi matin.
- Export des sauvegardes vers un serveur "externe" via FTP.
- Conservation des trois dernières sauvegardes complètes, et des incrémentales.
La synchronisation des sauvegardes s'effectue à l'aide de l'outil de backup Duplicity. Le fait d'externaliser les sauvegardes apportent une garantie supplémentaire. En effet, si le serveur venait à être en panne, les sauvegardes de SVN resteront disponibles.
Sommaire
Votre avis
Nobody voted on this yet
|
|
Objectif
Sous Ubuntu, il existe le répertoire /var/backups
, utilisé par aptitude, dpkg, OpenLDAP ... Cependant, il ne sera pas utilisé dans le cadre de cet article, pour ne pas engendrer d'éventuels effets de bord.
Tous les scripts et données seront stockés dans un nouveau répertoire /var/opt/backups
(pour l'ensemble des stratégies) et plus particulièrement dans le répertoire /var/opt/backups/svn
pour SVN.
Concernant les logs, elles seront toutes placées dans le répertoire /var/log/backups
.
#sudo mkdir -p /var/opt/backups/svn #sudo chmod 740 /var/opt/backups/svn #sudo chown root:root /var/opt/backups/svn #sudo mkdir /var/log/backups
Les scripts mis en place présentent la sauvegarde de dépôts stockés dans le répertoire /var/opt/svn
.
Export des dépôts
Source
La première étape consiste à effectuer un export du SVN. Le script mis en place est inspiré de celui publié ici: http://www.posteet.com/view/672
Il est adapté afin d'accepter deux paramètres:
- 1er: le nom du dépôt, correspondant au répertoire sous
/var/opt/svn
- 2ème: le type d'export, incrémental ou complet.
Le script svn_dump.sh
est mis en place, avec des sécurités autorisant uniquement le compte root
à le modifier, dans le répertoire /var/opt/backups/svn
avec le code suivant:
#!/bin/bash
# Get repository name to dump from arguments
repository=$1
# Get dump mode. If full do a full dump, otherwise do incremental
typeBackup=$2
# SVN repository incremental dump script
# To run a full dump, remove version folder content
# Arguments
# SVN root path for repositories
pathRootRepo="/var/opt/svn";
# SVN repository path to dump
pathRepo=$pathRootRepo"/"$repository;
# Dump root folder
pathRootBackup="/var/opt/backups/svn";
# Dump folder
pathBackup=$pathRootBackup"/"$repository;
# Version folder path to check last revision number
pathNumVersion=$pathBackup"/version";
# Dump file name
fileName="dump_svn_"$repository;
# Date format for the dump file name
dateFileFormat="+%Y%m%d";
# Date format for the log file
dateLogFormat="+%Y-%m-%d %H:%M";
# Check
# Check repository argument
if [ "$repository" = "" ]; then
echo "Missing repository argument";
echo "[$(date "$dateLogFormat")] End dump - dump cancelled";
exit 1;
fi
# Backup log
pathLog="/var/log/backups/svn_"$repository"_dump.log";
echo "[$(date "$dateLogFormat")] Start dump" >> $pathLog;
# Check working folder exists
if [ ! -d $pathBackup ]; then
echo "Folder $pathBackup does not exist" >> $pathLog;
echo "[$(date "$dateLogFormat")] End dump - dump cancelled" >> $pathLog;
exit 1;
fi
# Create version folder if does not exists
if [ ! -d $pathNumVersion ]; then
mkdir $pathNumVersion;
chmod 540 $pathNumVersion;
chown root:root $pathNumVersion;
fi
numVersionLastBackup=$(ls $pathNumVersion);
if [[ "$numVersionLastBackup" = "" ]] || [[ "$typeBackup" = "full" ]]; then
rm -f "$pathNumVersion/*";
versionFilePath="$pathNumVersion/1";
touch "$versionFilePath";
numVersionLastBackup=1;
chmod 640 "$versionFilePath";
chown root:root "$versionFilePath";
fi
if [[ $numVersionLastBackup -gt 1 ]] && [[ "$typeBackup" != "full" ]]; then
backupIncremental=" --incremental";
typeBackup="incr";
else
typeBackup="full";
fi
# Check repository path
if ! (svnlook info $pathRepo 2>>$pathLog 1>"/dev/null") ; then
echo "[$(date "$dateLogFormat")] ERROR : Repository $pathRepo does not exist" >> $pathLog;
echo "[$(date "$dateLogFormat")] End dump - dump cancelled" >> $pathLog;
exit 1;
fi
# Get last version from the repository
youngestSvnVersion=$(svnlook youngest $pathRepo);
echo "[$(date "$dateLogFormat")] Youngest svn Version : $youngestSvnVersion" >> $pathLog;
if [[ $numVersionLastBackup -gt $youngestSvnVersion ]] && [[ "$typeBackup" = "incr" ]]; then
echo "[$(date "$dateLogFormat")] Youngest version is lower than the last dump, dump is not required" >> $pathLog;
echo "[$(date "$dateLogFormat")] End dump" >> $pathLog;
exit 0
fi
pathBackupFile="$pathBackup/$(date "$dateFileFormat")_"$fileName"_"$typeBackup;
if [ "$typeBackup" = "incr" ]; then
pathBackupFile="$pathBackupFile""_"$numVersionLastBackup"_to_"$youngestSvnVersion;
fi
pathBackupFile="$pathBackupFile.svndump.bz2";
# Launch backup
if (svnadmin dump -r$numVersionLastBackup:$youngestSvnVersion$backupIncremental $pathRepo 2>>$pathLog | bzip2 > "$pathBackupFile") ; then
echo "[$(date "$dateLogFormat")] Update last dump version number" >> $pathLog;
newVersionLastBackup=$(($youngestSvnVersion+1));
if [ $numVersionLastBackup != $newVersionLastBackup ] ; then
mv $pathNumVersion/$numVersionLastBackup $pathNumVersion/$newVersionLastBackup;
fi
else
echo "[$(date "$dateLogFormat")] Dump error" >> $pathLog;
echo "[$(date "$dateLogFormat")] End dump - dump cancelled" >> $pathLog;
exit 1;
fi
if [ "$typeBackup" = "full" ]; then
# Full backup, remove all old files.
for f in `find "$pathBackup" -name "*.bz2"`; do
if [[ "$f" != "$pathBackupFile" ]]; then
# Not the newly created file, remove it
echo "[$(date "$dateLogFormat")] Delete file $f" >> $pathLog;
rm -f "$f";
fi
done
fi
chmod 640 $pathBackupFile;
chown root:root $pathBackupFile;
echo "[$(date "$dateLogFormat")] End dump" >> $pathLog;
exit 0
Le fonctionnement de ce script est assez simple. Les exports sont stockés dans le répertoire /var/opt/backups/svn/REPO_NAME
, où REPO_NAME est le nom du dépôt pris en compte.
Dans le cas où le second argument est égale à full
, un export complet est réalisé.
Pour toute autre valeur, un export incrémental est réalisé. Pour cela, le numéro de la dernière révision sauvegardée est regardé à partir du fichier dans le répertoire /var/opt/backups/svn/REPO_NAME/version
. Si aucun fichier n'est trouvé, un export complet est réalisé. Si le fichier est trouvé, le numéro de la dernière révision est recherché dans le dépôt à l'aide de la commande svnlook youngest
. Si ce numéro est inférieur ou égal au nom du fichier, l'export est annulé car il n'y aurait rien à faire.
Les exports sont automatiquement compressés à l'aide de l'outil bzip2
, lors de l'exécution de la commande svnadmin dump
.
Dans le cas d'un export complet, tous les anciens exports sont supprimés. En effet, les exports incrémentaux deviennent obsolètes dans ce cas.
Pour des raisons de sécurités, les permissions des fichiers générés donnent un droit d'écriture uniquement sur le compte root
.
Enfin, les exécutions sont tracées dans la log /var/log/backups/svn_REPO_NAME_dump.log
.
Exemples
Dans le cas de l'export du dépôt study
, les fichiers générés seront:
- Fichier log dans
/var/log/backups/svn_study_dump.log
. - Fichier d'export dans le répertoire
/var/opt/backups/svn/study
.
Il faut donc créer les différents répertoires et leur affecter les sécurités adéquates:
#sudo mkdir /var/opt/backups/svn/study #sudo chmod 740 /var/opt/backups/svn/study #chown root:root /var/opt/backups/svn/study
L'exemple suivant permet de réaliser un export complet:
#./svn_dump.sh study full
Les exemples suivants permettent de réaliser des exports incrémentaux:
#./svn_dump.sh study incr #./svn_dump.sh study #./svn_dump.sh study EVERYTHING_EXCEPT_full
Sauvegarde des exports
Source
La seconde étape consiste à exécuter les export SVN, puis d'utiliser Duplicity afin de sauvegarder ces fichiers sur un serveur distant via FTP. Deux paramètres d'appels sont nécessaires:
- 1er: le nom du dépôt, correspondant au répertoire sous /var/opt/svn
- 2ème: le type d'export, incrémental ou complet.
Ces paramètres seront utilisés par le script et envoyé au script svn_dump.sh
.
Le script svn_backup.sh
est mis en place, avec des sécurités autorisant uniquement le compte root
à le modifier, dans le répertoire /var/opt/backups/svn
avec le code suivant:
#!/bin/bash
# Get repository name to backup from arguments
repository=$1
# Check
# Check repository argument
if [ "$repository" = "" ]; then
echo "Missing repository argument";
echo "[$(date "$dateLogFormat")] End backup - backup cancelled";
exit 1;
fi
dateLogFormat="+%Y-%m-%d %H:%M";
# Backup log
pathLog="/var/log/backups/svn_"$repository"_backup.log";
echo "[$(date "$dateLogFormat")] Start backup" >> $pathLog;
echo "[$(date "$dateLogFormat")] Start dump" >> $pathLog;
/var/opt/backups/svn/svn_dump.sh $1 $2
echo "[$(date "$dateLogFormat")] End dump" >> $pathLog;
echo "[$(date "$dateLogFormat")] Start upload with duplicity" >> $pathLog;
export PASSPHRASE="DUPLICITY PASSPHRASE"
export FTP_IP=XXX.XXX.XXX.XXX
export FTP_PATH="PATH"
export FTP_USER="USER"
export FTP_PASSWORD="USER_PASSWORD"
export ROOT_COMMAND="ftp://$FTP_USER@$FTP_IP$FTP_PATH/svn/"
if [ "$2" = "full" ]; then
duplicity remove-all-but-n-full 52 --force $ROOT_COMMAND$1 >> $pathLog;
duplicity full /var/opt/backups/svn/$1 $ROOT_COMMAND$1 >> $pathLog;
else
duplicity /var/opt/backups/svn/$1 $ROOT_COMMAND$1 >> $pathLog;
fi
unset PASSPHRASE
unset FTP_IP
unset FTP_PATH
unset FTP_USER
unset FTP_PASSWORD
unset ROOT_COMMAND
echo "[$(date "$dateLogFormat")] End upload with duplicity" >> $pathLog;
echo "[$(date "$dateLogFormat")] End backup" >> $pathLog;
Attention à l'utilisation de l'instruction export
, surtout pour la PASSPHRASE. En effet, si celle-ci contient des espaces, il est impératif de la placer entre le caractère "
.
Le script est créé avec un droit de modification et exécution uniquement pour le compte root
:
#sudo chmod 740 svn_backup.sh #sudo chown root:root svn_backup.sh
Le fonctionnement de ce script est assez simple. Le script svn_dump.sh
est exécuté avec les arguments d'appel. Puis deux variables d'environnement sont mises en place:
- PASSPHRASE: Phrase pour le cryptage des données par Duplicity.
- FTP_IP: IP ou nom du serveur ftp
- FTP_PATH: Emplacement cible pour la sauvegarde
- FTP_USER: Login utilisé pour se connecter au ftp
- FTP_PASSWORD: Le mot de passe FTP utilisé pour se connecté via Duplicity.
- ROOT_COMMAND: Chaiîne principale pour la connexion et envoi sur ftp
Lors de la première version, il y avait un mixte entre l'export complet du SVN et Duplicity. Cette nouvelle version synchronise la volonté entre les deux outils. Ainsi, lorsque le deuxième argument est full
, l'export est complêt sur le SVN, et les instructions Duplicity suivantes sont exécutées:
-
remove-all-but-n-full 3
, va conserver uniquement les trois dernières sauvegardes complètes -
full
effectue une sauvegarde complète
Dans le cas contraire, une seule commande Duplicity est exécutée, entraînant une sauvegarde incrémentale.
Le résultat de l'export est ensuite envoyé sur un serveur FTP, configuré par la value HOST
, en utilisant le login FTP_LOGIN
et le mot de passe USER_PASSWORD
placé dans la variable FTP_PASSWORD
. Les sauvegardes sont stockées à l'emplacement backup/svn/REPO_NAME
à la racine du compte après connexion sur FTP.
Enfin, les exécutions sont tracées dans la log /var/log/backups/svn_REPO_NAME_backup.log
.
Exemples
Dans le cas de la sauvegarde du dépôt study
, les fichiers générés seront:
- Fichier log dans
/var/log/backups/svn_study_dump.log
et/var/log/backups/svn_study_backup.log
. - Fichier d'export dans le répertoire
/var/opt/backups/svn/study
. - Sauvegarde dans le répertoire
backup/svn/study
à la racine du compte de connexion FTP.
L'exemple suivant permet de réaliser une sauvegarde d'un export complet:
#./svn_backup.sh study full
Les exemples suivants permettent de réaliser des sauvegardes d'un export incrémental:
#./svn_backup.sh study incr #./svn_backup.sh study #./svn_backup.sh study EVERYTHING_EXCEPT_full
Planification
Une fois que les scripts de sauvegarde sont mis en place, il est possible de les exécuter manuellement. Mais l'objectif est de les exécuter automatiquement et régulièrement sans s'en préoccuper. Dans le cadre de cette implémentation, la planification est réalisée à l'aide de l'outil Crontab disponible sur les systèmes Linux. L'outil Anacron n'a pas été utilisé car les planifications souhaitées doivent se faire à des heures et des jours particuliers.
La mise en place s'effectue en modifiant le fichier /etc/crontab
pour y ajouter deux lignes.
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
30 3 * * 0,2-6 root cd / && /var/opt/backups/svn/svn_backup.sh study
30 3 * * 1 root cd / && /var/opt/backups/svn/svn_backup.sh study full
#
Les sauvegardes incrémentales sont planifiées à 3h30 AM, tous les jours de la semaine sauf le lundi (0,2-6 pour l'argument dow
), par l'exécution de la commande cd / && /var/opt/backups/svn/svn_backup.sh study
.
La sauvegarde complète est planifiée à 3h30 AM uniquement le lundi (1 pour l'argument dow
), par l'exécution de la commande cd / && /var/opt/backups/svn/svn_backup.sh study full
.
Gestions des logs
Des fichiers de log sont créés par les deux scripts mis en place. Comme pour l'ensemble des produits, une rotation de ces logs est mise en place, à l'aide de l'outil Logrotate.
L'ensemble des logs se trouvent donc dans le répertoire /var/log/backups
avec le nom commençant par svn_
. La configuration permet une rotation hebdomadaire, en conservant 7 rotations. Les rotations sont compressées, en asynchrone, et créées avec un accès en modification au compte root.
Cette configuration est mise en place dans le fichier svn_backup
, sous le répertoire /etc/logrotate.d
/var/log/backups/svn_*.log {
weekly
missingok
rotate 7
compress
delaycompress
notifempty
create 640 root root
}