#!/bin/bash
# --------------------------------------------------------------------------------------
# Didier
# Script de sauvegarde avec BorgBackup 
# la commande de creation du dépot est : borg init --encryption=repokey /mnt/backup-nas1/BorgRepo
# la conf de borg est dans /root/.config/borg
# Le repository peut etre distant: BORG_REPO='ssh://user@host:port/path/to/repo'
# la clé ssh devra être copiée sur le site distant et l' init se fera sous la forme
# borg init --encryption=repokey ssh://user@host:port/path/to/repo
# la clé est modifiable avec la commande borg key change-passphrase
# toutes les variables sont dans la config générale de KAZ
# scripts PRE et Post 
# les script pre et post doivent s' appelle pre_xxxxx.sh ou post_xxxx.sh
# La variable BORGSCRIPTS est le chemin du repertoire des scripts dans la config générale de Kaz
##################################################### 
KAZ_ROOT=$(cd "$(dirname $0)"/..; pwd)
. $KAZ_ROOT/bin/.commonFunctions.sh
setKazVars
. $DOCKERS_ENV
. ${KAZ_KEY_DIR}/env-borg
# Si la variable SCRIPTBORG est renseignée avec un fichier on le source 
if [ ! -z ${SCRIPTBORG} ]
then
	[ -f ${SCRIPTBORG} ] && . ${SCRIPTBORG}
fi
VERSION="V-07-08-2025"
PRG=$(basename $0)
RACINE=$(echo $PRG | awk '{print $1}')
#IFS=' '
#####################################################
# Variables générales
#####################################################
# le volume monté ou sera le repo
# impérativement laisser vide dans le cas d' un repo distant
VOLUME_SAUVEGARDES=${borg_VOLUME_SAUVEGARDES}
# le repo Borg
export BORG_REPO=${borg_BORG_REPO}
# Le mot de passe du repo
export BORG_PASSPHRASE=${borg_BORG_PASSPHRASE}
# les personnes qui recevront le rapport de sauvegarde
MAIL_RAPPORT=${borg_MAIL_RAPPORT}
# Recevoir un mail quand la sauvegarde est OK ?
MAILOK=${borg_MAILOK}
MAILWARNING=${borg_MAILWARNING}
MAILDETAIL=${borg_MAILDETAIL}
# repertoire de montage des sauvegardes pour les restaurations
BORGMOUNT=${borg_BORGMOUNT}
# - la liste des repertoires à sauver séparés par un espace
LISTREPSAUV=${borg_LISTREPSAUV}
# - Les sauvegardes à garder jour, semaines, mois
# - ou si renseigné c' est la variable borg_BACKUPS_KEEP qui prend le dessus
BACKUPS_KEEP=${borg_BACKUPS_KEEP}
NB_BACKUPS_JOUR=${borg_NB_BACKUPS_JOUR}
NB_BACKUPS_SEM=${borg_NB_BACKUPS_SEM}
NB_BACKUPS_MOIS=${borg_NB_BACKUPS_MOIS}
# Le Repertoire ou sont les pré traitement
BORGSCRIPTS=${borg_BORGSCRIPTS}
BORGLOG="${borg_BORGLOG}/BorgBackup-$(date +%d-%m-%Y-%H-%M-%S).log"
DEBUG=false
#Fichier des sauvegardes a supprimer
BORG_FIC_DEL=${borg_BORG_FIC_DEL}
BORG_EXCLUDE_BACKUP=${borg_BORG_EXCLUDE_BACKUP}

##################################################### 
#
FICLOG="/var/log/${PRG}.log"

##################################################### 

trap 'LogFic "script stoppé sur un SIGTERM ou SIGINT" >&2; exit 2' INT TERM

LogFic() {
        [ ! -w ${FICLOG} ] && { echo "Probleme d' ecriture dans $FICLOG" ; exit 1 ;}
        echo "$(date +%d-%m-%Y-%H-%M-%S) : $1" >> ${FICLOG}
}
#
ExpMail() {
	MAIL_DEST=$1
	MAIL_SUJET=$2
	MAIL_TEXTE=$3
	printf "Subject:${MAIL_SUJET}\n${MAIL_TEXTE}" | msmtp ${MAIL_DEST}
}

Pre_Sauvegarde() {
	if [ -d ${BORGSCRIPTS} ]
	then
		cd ${BORGSCRIPTS}
		for FicPre in $(ls )
		do
			if [ -x ${FicPre} ] && [ $(echo ${FicPre} | grep -i ^pre_) ]
			then
	        		LogFic " - Pré traitement de la sauvegarde : ${FicPre}"
				[ "$DEBUG" = true ] && echo " - Pré traitement de la sauvegarde : ${FicPre}" 
				./${FicPre}
			fi
		done
	fi
}

Post_Sauvegarde() {
	if [ -d ${BORGSCRIPTS} ]
	then
		cd ${BORGSCRIPTS}
                for FicPre in $(ls )
		do
			if [ -x ${FicPre} ] && [ $(echo ${FicPre} | grep -i ^post_) ]
        		then
	        		LogFic " - Post traitement de la sauvegarde : ${FicPre}"
				[ "$DEBUG" = true ] && echo " - Post traitement de la sauvegarde : ${FicPre}" 
                        	./${FicPre}
			fi
		done
        fi

}

Sauvegarde() {
   [ -f "${BORG_EXCLUDE_BACKUP}" ] && S_EXCU="--exclude-from ${BORG_EXCLUDE_BACKUP}" || S_EXCU=""
   Pre_Sauvegarde 
   BACKUP_PRE=$?
   borg create                     \
   --filter AME                    \
   --exclude-caches                \
   --stats                         \
   --show-rc                       \
   --exclude 'home/*/.cache/*'     \
   --exclude 'var/tmp/*'           \
   ${S_EXCU} \
   ::$(date +%Y-%m-%d-%H-%M-%S-%A)-{hostname}        \
   ${LISTREPSAUV} >>${BORGLOG} 2>>${BORGLOG}
   BACKUP_EXIT=$?
   Post_Sauvegarde
   BACKUP_POST=$?
}

Purge() {
if [ ! -z ${BACKUPS_KEEP} ]
then
borg prune --keep-within=${BACKUPS_KEEP}
PRUNE_EXIT=$?
else
borg prune --keep-daily ${NB_BACKUPS_JOUR} --keep-weekly ${NB_BACKUPS_SEM} --keep-monthly ${NB_BACKUPS_MOIS}
PRUNE_EXIT=$?
fi
}


Compact() {

borg compact --progress ${BORG_REPO}

}

usage() {

echo "-h : Usage"
echo "-c : Permet de compacter ${BORG_REPO}"
echo "-d : Permet de verifier les variables de sauvegarde"
echo "-delbackup : Permet la suppression de backups renseignés dans un fichier ${BORG_FIC_DEL} "
echo "-i : Mode interractif"
echo "-info"
echo "-l : Liste les sauvegardes sans monter ${BORG_REPO}"
echo "-m : Monte le REPO (${BORG_REPO} sur ${BORGMOUNT})"
echo "-p : Permet de lancer la phase de purge des backups"
echo "-s : Lance la sauvegarde"
echo "-u : Demonte le REPO (${BORG_REPO} de ${BORGMOUNT})"
echo "-v : Version"
exit
}

Borgvariables() {
	echo "-----------------------------------------------------------"
	echo "       Variables applicatives pour le site ${site}"
	echo "-----------------------------------------------------------"
	for borgvar in $(set | grep borg_ | sed -e 's/borg_//' -e 's/=.*$//' | grep ^[A-Z])
        do
                echo "$borgvar=${!borgvar}"
        done
	if grep borgfs /etc/mtab >/dev/null 2>&1
	then
		echo -e "${RED}WARNING${NC}: ${BORG_REPO} est monté sur ${BORGMOUNT}"
	fi
}


BorgDelBackups() {

	[ -z ${BORG_FIC_DEL} ] && { echo "Le fichier n'est pas renseigné" ; exit 1; }
	[ ! -r ${BORG_FIC_DEL} ] && { echo "Le fichier ${BORG_FIC_DEL} est inexistant" ; exit 1 ; }
	for Backups in $(cat ${BORG_FIC_DEL})
	do
        	echo "suppression de la sauvegarde ${Backups}"
        	borg delete ${BORG_REPO}::${Backups}
	done
}

Borgmount() {
	LogFic "Montage du repo ${BORG_REPO} sur ${BORGMOUNT} .. " 
	echo -en "Montage du repo ${BORG_REPO} sur ${BORGMOUNT} .. " 
	borg mount ${BORG_REPO} ${BORGMOUNT} >/dev/null 2>&1
	if [ $? = 0 ]
	then
		LogFic "Ok"
		echo -e "${GREEN}Ok${NC}"
	else
		LogFic "Error"
		echo -e "${RED}Error $?${NC}"
	fi
	exit
}

Borgumount() {
	LogFic "Demontage du repo ${BORG_REPO} sur ${BORGMOUNT} .. " 
	echo -en "Demontage du repo ${BORG_REPO} sur ${BORGMOUNT} .. " 
	borg umount ${BORGMOUNT} >/dev/null 2>&1
	if [ $? = 0 ]
	then
		LogFic "Ok"
		echo -e "${GREEN}Ok${NC}"
	else
		LogFic "Error"
		echo -e "${RED}Error $?${NC}"
	fi
	exit
}

Borglist() {
	BORG_LIST_BACKUPS=/tmp/borglistbackups.txt
	LogFic "Borg list demandé"
	borg list --short ${BORG_REPO} >${BORG_LIST_BACKUPS}
	cat ${BORG_LIST_BACKUPS}
	echo " --- Nombre de backups"
	cat ${BORG_LIST_BACKUPS} | wc -l
	rm ${BORG_LIST_BACKUPS}
	exit
}

Borginfo() {
	LogFic "Borg info demandé"
	borg info ${BORG_REPO}
	exit
}

#################################################################################################################################
# on teste tout le temps le message si le repo est monté
#################################################################################################################################
# Test si le REPO est monté
if grep borgfs /etc/mtab >/dev/null 2>&1
then
         REPO_MOUNT_ACTIVE=true
else
         REPO_MOUNT_ACTIVE=false
fi
 
# on affiche tout le temps le message si le repo est monté
if [ "${REPO_MOUNT_ACTIVE}" = "true" ]
then
         echo "*****************************************************************************************"
         echo -e "${RED} WARNING : ${NC} Le repo ${BORG_REPO} est monté"
         echo "*****************************************************************************************"
fi
#################################################################################################################################

main() {
# ****************************************************** Main *******************************************************************
# Création du fichier de log
touch ${FICLOG}
#
LogFic "#########################################################################################################################"
LogFic "                         ***************  ${PRG} Version ${VERSION}  ***************"
LogFic "#########################################################################################################################"
# test si les variables importantes sont renseignées et sortie si tel n' est pas le cas
if [ -z "${VOLUME_SAUVEGARDES}" ] && [ -z "${BORG_REPO}" ] || [ -z "${BORG_REPO}" ] || [ -z "${BORG_PASSPHRASE}" ] || [ -z "${MAIL_RAPPORT}" ]
then
	echo "Les variables VOLUME_SAUVEGARDES, BORG_REPO,  BORG_PASSPHRASE, MAIL_RAPPORT sont à verifier"
	LogFic "Les variables VOLUME_SAUVEGARDES, BORG_REPO,  BORG_PASSPHRASE, MAIL_RAPPORT sont à verifier"
	LogFic "Sortie du script"
	exit 1
fi
# test si le volume de sauvegarde est ok
if [ ! -z ${VOLUME_SAUVEGARDES} ]
then
	[ !$(grep "${VOLUME_SAUVEGARDES}" /etc/mtab >/dev/null 2>&1) ] || { echo "le volume de sauvegarde ${VOLUME_SAUVEGARDES} n' est pas monté"; LogFic "Erreur de montage du volume ${VOLUME_SAUVEGARDES} de sauvegarde" ;  exit 1;}
else
	[ ! $(echo ${BORG_REPO} | grep -i ssh 2>/dev/null) ] && { echo "Problème avec le repo distant ";exit 1;}
fi

#Test si le REPO est monté : on sort
if [ "${REPO_MOUNT_ACTIVE}" = "true" ]
then
        echo "le REPO : ${BORG_REPO} est monté , je sors"
        LogFic "le REPO : ${BORG_REPO} est monté , je sors"
	ExpMail ${MAIL_RAPPORT} "${site} : Sauvegarde en erreur" "le REPO : ${BORG_REPO} est monté, sauvegarde impossible"
        exit 1
fi


#  Tout se passe bien on continue
LogFic " - Repertoire a sauver : ${LISTREPSAUV}"
LogFic " - Volume Nfs monté : ${VOLUME_SAUVEGARDES}"
LogFic " - Repertoire des sauvegardes : ${BORG_REPO}"
[ ! -d ${BORGSCRIPTS} ] && LogFic "Pas de repertoire de PRE et POST" || LogFic " - Repertoire des scripts Post/Pré : ${BORGSCRIPTS}" 
[ -e ${BORG_EXCLUDE_BACKUP} ] && LogFic " - Fichier des exclusions : ${BORG_EXCLUDE_BACKUP}" 
[ "${DEBUG}" = true ] && [ -d ${BORGSCRIPTS} ] && echo "Rep des scripts PRE/POST :${BORGSCRIPTS}"
LogFic " - Rapport par Mail : ${MAIL_RAPPORT}"
if [ ! -z ${BACKUPS_KEEP} ]
then
	LogFic " - Backups à garder : ${BACKUPS_KEEP}"
else
	LogFic " - Backups jour : ${NB_BACKUPS_JOUR} , Backups semaines : ${NB_BACKUPS_SEM} , Backups mois : ${NB_BACKUPS_MOIS}"
fi
[ "${DEBUG}" = true ] && echo "${LISTREPSAUV} sauvé dans ${BORG_REPO}, Rapport vers : ${MAIL_RAPPORT}"
LogFic "#########################################################################################################################"
LogFic " - Démarrage de la sauvegarde"
[ "$DEBUG" = true ] && echo "Demarrage de la sauvegarde : "
LogFic " - Log dans ${BORGLOG}"
Sauvegarde
[ "$DEBUG" = true ] && echo "code de retour de backup : ${BACKUP_EXIT}"
LogFic " - Code de retour de la commande sauvegarde : ${BACKUP_EXIT}"
LogFic " - Démarrage du nettoyage des sauvegardes"
[ "$DEBUG" = true ] && echo "Nettoyage des sauvegardes: "
Purge
LogFic " - Code retour du Nettoyage des sauvegardes (0=OK; 1=WARNING, 2=ERROR)  : ${PRUNE_EXIT}"
[ "$DEBUG" = true ] && echo "code de retour prune : ${PRUNE_EXIT}"
#
########################################################################################
# si la variable MAILDETAIL est true alors on affecte le contenu du log sinon LOGDATA est VIDE 
LOGDATA=""
[ "$MAILDETAIL" = true ] && LOGDATA=$(cat ${BORGLOG})
[ "$DEBUG" = true ] && [ "$MAILDETAIL" = true ] && echo "Envoi du mail à ${MAIL_RAPPORT}"
# On teste le code retour de la sauvegarde, on log et on envoie des mails
case "${BACKUP_EXIT}" in
	'0' )
		IFS=''
		MESS_SAUVE_OK="
Salut

La sauvegarde est ok, ce message peut être enlevé avec la variable MAILOK=false
Que la force soit avec toi

BorgBackup

"
		LogFic " - la sauvegarde est OK"
		[ "$MAILOK" = true ] && ExpMail ${MAIL_RAPPORT} "${site} : Sauvegarde Ok" ${MESS_SAUVE_OK}${LOGDATA}
		IFS=' '
		;;
	'1' )
		IFS=''
		MESS_SAUVE_ERR="
Salut

La sauvegarde est en warning
Code de retour de la commande sauvegarde : ${BACKUP_EXIT}
Le log contenant les infos est ${BORGLOG}

BorgBackup

"
		LogFic " - Sauvegarde en Warning: ${BACKUP_EXIT}"
		[ "$MAILWARNING" = true ] && ExpMail ${MAIL_RAPPORT} "${site} : Sauvegarde en Warning: ${BACKUP_EXIT}" ${MESS_SAUVE_ERR}${LOGDATA}
		IFS=' '
		;;
	* )
		IFS=''
		MESS_SAUVE_ERR="
Salut

La sauvegarde est en Erreur 
Code de retour de la commande sauvegarde : ${BACKUP_EXIT}
Le log à consulter est ${BORGLOG}

BorgBackup

"
		LogFic " - !!!!! Sauvegarde en Erreur !!!!! : ${BACKUP_EXIT}"
		ExpMail ${MAIL_RAPPORT} "${site} : Sauvegarde en Erreur !!!! : ${BACKUP_EXIT}" ${MESS_SAUVE_ERR}${LOGDATA}
		IFS=' '
		;;
esac
LogFic " - Fin de la sauvegarde"
exit
}

[ ! "$#" -eq "0" ] || usage 
# On teste les arguments pour le script 
for ARG in $@; do
    case "${ARG}" in
        '-h' | '-help' )
            usage
            ;;
        '-m' )
            shift
	    Borgmount
            ;;
        '-u' )
            shift
	    Borgumount
            ;;
        '-l' )
            shift
	    Borglist
            ;;
        '-i' )
            shift
	    DEBUG=true
            ;;
        '-v' )
            shift
	    echo "Version : ${VERSION}"
	    exit
            ;;
	'-d' )
	    shift
	    Borgvariables
	    exit
	    ;;
	'-c' )
	    shift
	    Compact
	    exit
	    ;;
	'-s' )
	    main
	    ;;
	'-p' )
            shift
	    if [ ! -z ${BACKUPS_KEEP} ]
            then 
                PURGE_MESS="Ok pour lancer la purge en fonction de ces valeurs : BACKUPS_KEEP=${BACKUPS_KEEP} ? O/N :"
            else
                PURGE_MESS="Ok pour lancer la purge en fonction de ces valeurs :jour=${NB_BACKUPS_JOUR},semaine=${NB_BACKUPS_SEM},mois=${NB_BACKUPS_MOIS} ? O/N :"
            fi
            read -p "${PURGE_MESS}" READPURGE
            [[ ${READPURGE} =~ ^[oO]$ ]] && Purge || echo "pas de purge"
            exit
            ;;
	'-info' )
	    shift
	    Borginfo
	    exit
	    ;;
	'-delbackup' )
	    shift
	    BorgDelBackups
	    exit
	    ;;
	* | ' ' )
	   usage
	   ;;
    esac
done
