Mon CV

Sauvegarder et restaurer ses applications sur Debian

30 mai 2014

Je suis tombé il y a quelques jours sur un billet intéressant récapitulant les méthodes pour backuper et restaurer facilement les applications installées sur Linux.

Du coup, je me suis dit que ça valait le coup d’écrire un petit outil pour automatiser cela, dans mon cas sur Debian.

Voici l’outil en question :

#! /bin/bash

#——————————————#
# ListApp #
#——————————————#
# #
# Backup list of applications installed #
# on Debian (and restore, of course!) #
# #
# Yvan Godard #
# godardyvan@gmail.com #
# #
# Version 0.1 — may, 30 2014 #
# Under Licence #
# Creative Commons 4.0 BY NC SA #
# #
# http://goo.gl/A8vPSE #
# #
#——————————————#

# Variables initialisation
VERSION=”ListApp v0.1 – 2014, Yvan Godard [godardyvan@gmail.com]”
help=”no”
SCRIPT_DIR=$(dirname $0)
SCRIPT_NAME=$(basename $0)
BACKUP_LIST_FOLDER=”/var/ListApp”
EMAIL_REPORT=”nomail”
EMAIL_LEVEL=0
LOG=”/var/log/ListApp.log”
LOG_ACTIVE=0
LOG_TEMP=$(mktemp /tmp/ListApp.XXXXX)
HOWMANYDAILY_DEFAULT=14
HOWMANYDAILY=$(echo ${HOWMANYDAILY_DEFAULT})
HOWMANYWEEKLY_DEFAULT=8
HOWMANYWEEKLY=$(echo ${HOWMANYWEEKLY_DEFAULT})
DATANAME=”backup-$(date +%d.%m.%y@%Hh%M).apps.list”
INPUT_FILE=${BACKUP_LIST_FOLDER}/last.apps.list
EMAIL_ADDRESS=””

help () {
echo -e “$VERSION\n”
echo -e “This tool is designed to backup and restore your programs on Debian.”
echo -e “\nDisclamer:”
echo -e “This tool is provide without any support and guarantee.”
echo -e “\nSynopsis:”
echo -e “./$SCRIPT_NAME [-h] | -m
echo -e ” [-l ] [-j ]”
echo -e ” [-d ] [-w ]”
echo -e ” [-i ]”
echo -e ” [-e ] [-E ]”
echo -e “\n\t-h: prints this help then exit”
echo -e “\nMandatory options:”
echo -e “\t-m : the mode to use, must be ‘backup’ or ‘restore'”
echo -e “\nOptional options:”
echo -e “\t-l : path to write backup files (i.e.: ‘/home/backups/apps’, default: ‘${BACKUP_LIST_FOLDER}’)”
echo -e “\t-j : enables logging instead of standard output. Specify an argument for the full path to the log file”
echo -e “\t (i.e.: ‘${LOG}’) or use ‘default’ (${LOG})”
echo -e “\t-d : number of daily backup lists of applications to keep (default: ‘${HOWMANYDAILY}’),”
echo -e “\t this parameter is only to use with ‘-m backup’.”
echo -e “\t-w : number of weekly backup lists of applications to keep (default: ‘${HOWMANYWEEKLY}’),”
echo -e “\t this parameter is only to use with ‘-m backup’.”
echo -e “\t-i : full path of list of applications you want to restore (default: ‘${INPUT_FILE}’),”
echo -e “\t this parameter is only to use with ‘-m restore’.”
echo -e “\t-e : settings for sending a report by email, must be ‘onerror’, ‘forcemail’ or ‘nomail’ (default: ‘${EMAIL_REPORT}’)”
echo -e “\t-E : email address to send the report (must be filled if ‘-e forcemail’ or ‘-e onerror’ options is used)”
exit 0
}

error () {
echo -e “\n*** Error ***”
echo -e ${1}
echo -e “\n”${VERSION}
alldone 1
}

alldone () {
# Redirect standard outpout
exec 1>&6 6>&-
# Logging if needed
[ ${LOG_ACTIVE} -eq 1 ] && cat ${LOG_TEMP} >> ${LOG}
# Print current log to standard outpout
[ ${LOG_ACTIVE} -ne 1 ] && cat ${LOG_TEMP}
[ ${EMAIL_LEVEL} -ne 0 ] && [ ${1} -ne 0 ] && cat ${LOG_TEMP} | mail -s “[ERROR : ${SCRIPT_NAME}] on $(hostname)” ${EMAIL_ADDRESS}
[ ${EMAIL_LEVEL} -eq 2 ] && [ ${1} -eq 0 ] && cat ${LOG_TEMP} | mail -s “[OK : ${SCRIPT_NAME}] on $(hostname)” ${EMAIL_ADDRESS}
rm ${LOG_TEMP}
exit ${1}
}

optsCount=0

while getopts “hm:l:j:d:w:i:e:E:” OPTION
do
case “$OPTION” in
h) help=”yes”
;;
m) MODE=${OPTARG}
let optsCount=$optsCount+1
;;
l) BACKUP_LIST_FOLDER=”${OPTARG%/}”
;;
e) EMAIL_REPORT=${OPTARG}
;;
E) EMAIL_ADDRESS=${OPTARG}
;;
j) [ ${OPTARG} != “default” ] && LOG=${OPTARG}
LOG_ACTIVE=1
;;
i) INPUT_FILE=${OPTARG}
;;
w) HOWMANYWEEKLY=${OPTARG}
;;
d) HOWMANYDAILY=${OPTARG}
;;
esac
done

if [[ ${optsCount} != “1” ]] then
help
alldone 1
fi

[[ ${help} = “yes” ]] && help

# Redirect standard outpout to temp file
exec 6>&1
exec >> ${LOG_TEMP}

# Start temp log file
echo -e “\n****************************** `date` ******************************\n”
echo -e “$0 started on $(hostname)\n”

# Test of sending email parameter and check the consistency of the parameter email address
if [[ ${EMAIL_REPORT} = “forcemail” ]] then
EMAIL_LEVEL=2
if [[ -z $EMAIL_ADDRESS ]] then
echo -e “You use option ‘-e ${EMAIL_REPORT}’ but you have not entered any email info.\n\t-> We continue the process without sending email.”
EMAIL_LEVEL=0
else
echo “${EMAIL_ADDRESS}” | grep ‘^[a-zA-Z0-9._-]*@[a-zA-Z0-9._-]*\.[a-zA-Z0-9._-]*$’ > /dev/null 2>&1
if [ $? -ne 0 ] then
echo -e “This address ‘${EMAIL_ADDRESS}’ does not seem valid.\n\t-> We continue the process without sending email.”
EMAIL_LEVEL=0
fi
fi
elif [[ ${EMAIL_REPORT} = “onerror” ]] then
EMAIL_LEVEL=1
if [[ -z $EMAIL_ADDRESS ]] then
echo -e “You use option ‘-e ${EMAIL_REPORT}’ but you have not entered any email info.\n\t-> We continue the process without sending email.”
EMAIL_LEVEL=0
else
echo “${EMAIL_ADDRESS}” | grep ‘^[a-zA-Z0-9._-]*@[a-zA-Z0-9._-]*\.[a-zA-Z0-9._-]*$’ > /dev/null 2>&1
if [ $? -ne 0 ] then
echo -e “This address ‘${EMAIL_ADDRESS}’ does not seem valid.\n\t-> We continue the process without sending email.”
EMAIL_LEVEL=0
fi
fi
elif [[ ${EMAIL_REPORT} != “nomail” ]] then
echo -e “\nOption ‘-e ${EMAIL_REPORT}’ is not valid (must be: ‘onerror’, ‘forcemail’ or ‘nomail’).\n\t-> We continue the process without sending email.”
EMAIL_LEVEL=0
elif [[ ${EMAIL_REPORT} = “nomail” ]] then
EMAIL_LEVEL=0
fi

# Test log file
if [[ ${LOG_ACTIVE} == “1” ]] then
if [[ ! -f ${LOG} ]] then
touch ${LOG}
[ $? -ne 0 ] && error “Error when trying to create log file ‘${LOG}'”
fi
fi

# Test option -m (mode)
[[ ${MODE} != “backup” ]] && [[ ${MODE} != “restore” ]] && error “Parameter ‘-m ${MODE}’ is not correct.\n-m must be ‘backup’ or ‘restore'”

# Test options HOWMANYDAILY & HOWMANYWEEKLY
if [[ ! -z “`echo ${HOWMANYDAILY} | sed s/[0-9]*//`” ]] then
echo -e “Option ‘-d ${HOWMANYDAILY}’ is not valid, should be an integer.\n\t-> We continue the process without standard option ‘-d ${HOWMANYDAILY_DEFAULT}’.”
HOWMANYDAILY=$(echo ${HOWMANYDAILY_DEFAULT})
fi
if [[ ! -z “`echo ${HOWMANYWEEKLY} | sed s/[0-9]*//`” ]] then
echo -e “Option ‘-w ${HOWMANYWEEKLY}’ is not valid, should be an integer.\n\t-> We continue the process without standard option ‘-d ${HOWMANYWEEKLY_DEFAULT}’.”
HOWMANYWEEKLY=$(echo ${HOWMANYWEEKLY_DEFAULT})
fi

# Test on location
if [[ ${MODE} = “backup” ]] then
if [[ ! -d ${BACKUP_LIST_FOLDER} ]] then
echo -e “Creating backup path ‘${BACKUP_LIST_FOLDER}’…”
mkdir -p ${BACKUP_LIST_FOLDER}
if [ $? -ne 0 ] then
error “Impossible to create folder ‘${BACKUP_LIST_FOLDER}’.\nPlease create it or verify this path and re-launch this tool.”
else
echo -e “\t-> Path ${BACKUP_LIST_FOLDER} successfully created.”
fi
fi
elif [[ ${MODE} = “restore” ]] then
[[ ! -f ${INPUT_FILE} ]] && error “Impossible to read ${INPUT_FILE} as source.\nPlease verify this path and re-launch this tool.”
fi

# Backup loop
if [[ ${MODE} = “backup” ]] then
if [ “$( date +%w )” == “0” ] then
[ ! -d ${BACKUP_LIST_FOLDER}/weekly ] && mkdir -p ${BACKUP_LIST_FOLDER}/weekly
DATADIR=${BACKUP_LIST_FOLDER}/weekly
KEEP_NUMBER=${HOWMANYWEEKLY}
echo “Weekly backup:”
echo -e “\t-> ${KEEP_NUMBER} days of backup list files will be stored.”
else
[ ! -d ${BACKUP_LIST_FOLDER}/daily ] && mkdir -p ${BACKUP_LIST_FOLDER}/daily
DATADIR=${BACKUP_LIST_FOLDER}/daily
KEEP_NUMBER=${HOWMANYDAILY}
echo “Daily backup:”
echo -e “\t-> ${KEEP_NUMBER} days of backup list files will be stored.”
fi
# Creating application list
echo “Creating backup ${DATADIR}/${DATANAME}…”
dpkg –get-selections > ${DATADIR}/${DATANAME}
[ $? -ne 0 ] && error “Error when trying to create backup list ‘${DATADIR}/${DATANAME}’.”
[ -f ${BACKUP_LIST_FOLDER}/last.apps.list ] && rm ${BACKUP_LIST_FOLDER}/last.apps.list
ln -s ${DATADIR}/${DATANAME} ${BACKUP_LIST_FOLDER}/last.apps.list
[ -f ${DATADIR}/last.apps.list ] && rm ${DATADIR}/last.apps.list
ln -s ${DATADIR}/${DATANAME} ${DATADIR}/last.apps.list
# Delete old backup files
echo “Deleting old backups if needed…”
find ${DATADIR} -name “*.apps.list” -mtime +${KEEP_NUMBER} -print -exec rm {} \;
[ $? -ne 0 ] && error “Error when trying to delete old backup files.”
fi

# Restore loop
if [[ ${MODE} = “restore” ]] then
[[ `whoami` != ‘root’ ]] && error “You need to run this tool as root to be able to use ‘-m restore’ option. Please use SUDO.”
echo “Restore:”
cat ${INPUT_FILE}
sudo dpkg –set-selections < ${INPUT_FILE} [ $? -ne 0 ] && error "Error when trying to use command 'sudo dpkg --set-selections < ${INPUT_FILE}'." sudo apt-get dselect-upgrade fi echo -e "\nAll the process seems to be OK!" alldone 0[/sourcecode]

 

Installer et utiliser le script

Pour l’installer, rendez-vous dans le dossier dans lequel vous souhaitez installer le script puis lancez la commande suivante pour le récupérer depuis github.com :

wget -O ListApp.sh --no-check-certificate https://raw.github.com/yvangodard/Debian-Backup-List-Applications/master/ListApp.sh
chmod 755 ListApp.sh

Une fois le script récupéré, vous pouvez afficher l’aide en lançant

./ListApp.sh -h

Les paramètres à utiliser sont les suivants

  • -m <mode> : ‘backup‘ ou ‘restore‘ en fonction de l’utilisation que vous souhaitez faire,
  • -j <fichier de log> : active l’écriture dans un fichier journal (log) à la place de la sortie standard. Mettez en argument le chemin complet du fichier de log ou ‘default’ pour utiliser le ficher standard (/var/log/ListApp.log)
  • -d : permet de choisir un nombre de backups quotidiens à conserver (par défaut 14). Ce paramètre n’est à utiliser que si -m backup est appelé.
  • -w : permet de choisir un nombre de backups hebdomadaires à conserver (par défaut 8). Ce paramètre n’est à utiliser que si -m backup est appelé.
  • -i : chemin de la liste d’application à utiliser pour une restauration. Ce paramètre n’est à utiliser que si -m restore est appelé
  • -e : permet de choisir les options d’envoi d’email, onerror, forcemail ou nomail (par défaut, -e nomail est utilisé)
  • -E : permet d’entrer l’adresse email à utiliser si -e onerror ou -e forcemail est utilisé

 

Le stockage des backups

Pour optimiser un peu le stockage des backups, je crée deux sous-dossiers :

  • weekly contiendra les backups réalisés le dimanche (backup hebdomadaire)
  • daily contiendra les backups réalisés du lundi au samedi
  • un lien symbolique dans chaque dossier vous donne accès au dernier fichier.

Par défaut, si vous lancez une restauration sans entrer de fichier en paramètre, c’est le backup /var/ListApp/last.apps.list qui sera utilisé.

 

Evidemment, c’est une version brute de décoffrage … n’hésitez pas à me proposer vos améliorations ou à faire remonter vos bugs.

Posted in Unix et LinuxTags: