Backup Scripts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Run this script with sudo | |
[ `whoami` = root ] || { echo "Need to run as root"; exit 1; } | |
# Update config here and run the script - example values used below | |
export PASSPHRASE="12345678901234567890" | |
# Specify full system paths from the root | |
export backupDirectory="/network/path/to/backps" | |
export restoreDirectory="/tmp/restore-data/" | |
duplicity --file-to-restore / "file://$backupDirectory" "$restoreDirectory" | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Backup Script | |
# | |
# Backs up docker directory to a remote encryped SMB share with guest permissions | |
# May add smb user permissions in the future | |
####################################### | |
# Uncomment to debug | |
# set -x | |
## Config | |
# export DEBUG="1" | |
export DEBUG="0" | |
export localDirs="/local/dir/to/backup" | |
export localDescription="Description of backup job here to be put in notification mail" | |
export localTmpMountPath="/tmp/backupmount" | |
export remoteSmbHost="smb.host.example.com" | |
export remoteSmbShare="ShareName" | |
export remoteSmbPathInShare="subdir/in/share" | |
# Used to encrypt the backups - storing this in a file allows it | |
# to only be read by root, while other users can see this script | |
export passwordFile="/opt/backups/pwfile" | |
export alertFromAddr="backups-noreply@example.com" | |
export alertFromName="Backups User" | |
## Helper Functions | |
# Send success message along with some further information about the backup run | |
function successMail() { | |
removalResult="$1" | |
runResult="$2" | |
verifyResult="$3" | |
echo "Sending backup report to recipients" | |
for m in $alertAddresses ; do | |
if [[ "$DEBUG" = "1" ]] ; then | |
echo " - sending alert message to $m" | |
fi | |
echo -e "Duplicity backup run completed sucessfully on '$HOSTNAME' with the following settings: \n\nDEST: $remoteSmbHost/$remoteSmbShare/$remoteSmbPathInShare\nLOCAL DIR: $localDirs \nBACKUP DESCRIPTION: $localDescription\n\n\n----------------------------------------------------\n\n\nOLD BACKUP REMOVAL OUTPUT: \n${removalResult}\n\n\nBACKUP RUN RESULT:\n${runResult}\n\n\nBACKUP VERIFY RESULT:\n${verifyResult}" | mail -s "[BACKUP] [SUCCESS] $HOSTNAME" -a "From: $alertFromName<$alertFromAddr>" "$m" | |
done | |
} | |
# Sends failure message on backup failure | |
function failMail() { | |
ws=" " | |
echo "Sending backup report to recipients" | |
for m in $alertAddresses ; do | |
if [[ "$DEBUG" = "1" ]] ; then | |
echo " - sending alert message to $m" | |
fi | |
# echo -e "Duplicity backup run failed on '$HOSTNAME' with the following settings: \n\n$ws Destination: $remoteSmbHost/$remoteSmbShare/$remoteSmbPathInShare\n$ws Local dir: $localDirs \n$ws Description: $localDescription" | mail -s "[BACKUP] [FAIL] $HOSTNAME" -a "From: $alertFromName<$alertFromAddr>" "$m" | |
done | |
} | |
function exitFailHandler() { | |
# echo "$@" | |
# echo "$(caller)" | |
echo >&2 ' | |
*************** | |
*** FAILURE *** | |
*************** | |
' | |
echo "An error occurred. Exiting..." >&2 | |
failMail | |
exit 1 | |
} | |
trap exitFailHandler ERR | |
set -e | |
## Error handler method | |
# Runs on every exit, and can handle failures so they are alerted | |
## Main method | |
# Steps accomplished below: | |
# 0) Read password file into variable, fail if unreadable or < 8 chars | |
# 1) Mount remote share - fail if no mount found after running mount command | |
# 2) Run duplicity 1) remove old, 2) backup, and 3) verification of backups | |
# 3) Cleanup mount and unmount | |
# 4) Alert on success | |
# Check if running as root | |
if [ $(id -u) != 0 ]; then echo "You should run this script as root."; exit 1; fi | |
# Check if $passwordfile is readable | |
if [[ -r "$passwordFile" ]] ; then | |
if [[ "$DEBUG" = "1" ]] ; then | |
echo "Password file '$passwordFile' is readable." | |
fi | |
else | |
echo "Password file '$passwordFile' is not readable. Can not continue." | |
exit 1; | |
fi | |
# Reading in password | |
# NOTE - don't change this variable name, it's a magic env var used by duplicity | |
export PASSPHRASE="$(cat $passwordFile)" | |
# Check to ensure length is > 8 | |
if [[ ${#PASSPHRASE} -lt 8 ]] ; then | |
echo "Password specified was too short or could not be read. Exiting backup." | |
exit 1 | |
fi | |
# Ensure CIFS utils are installed | |
# Will return "0" if installed, and "1" if not installed | |
dpkg -l cifs-utils &> /dev/null | |
# which mount.cifs &> /dev/null | |
cifsNeedsInstall="$?" | |
if [[ "$cifsNeedsInstall" = "1" ]] ; then | |
echo "You need to install 'cifs-utils' before you can continue." | |
exit 1; | |
elif [[ "$cifsNeedsInstall" = "0" ]] ; then | |
if [[ "$DEBUG" = "1" ]] ; then | |
echo "cifs-utils is installed - continuing with mount attempt" | |
fi | |
else | |
echo "Unexpected result from dpkg. Can not continue." | |
exit 1; | |
fi | |
# Mount remote share | |
mkdir -p "$localTmpMountPath" | |
echo "Mounting remote share" | |
# Unmount if mounted | |
umount "$localTmpMountPath" &> /dev/null || umount -l "$localTmpMountPath" &> /dev/null || true | |
mount -t cifs -o rw,uid=1000,gid=1000,noperm,guest "//$remoteSmbHost/$remoteSmbShare" "$localTmpMountPath" | |
# Catch the error so it can be handled below | |
mountFail="$(df -h | grep "$localTmpMountPath" &> /dev/null ; echo $?)" | |
if [[ "$mountFail" = "1" ]] ; then | |
echo "Network share could not be mounted." | |
exit 1; | |
elif [[ "$mountFail" = "0" ]] ; then | |
if [[ "$DEBUG" = "1" ]] ; then | |
echo "Mount successfully completed" | |
fi | |
else | |
echo "Unexpected result from mount. Can not continue." | |
exit 1; | |
fi | |
mkdir -p "$localTmpMountPath/$remoteSmbPathInShare/" &> /dev/null | |
# Mounting done - if we reached here, mount was successful | |
# output variables: | |
# OUT_REM = output of the removal | |
# OUT_RUN = output of the backup run | |
# OUT_VER = output of the backup verification | |
# Backup and purge old backups | |
echo "Removing old backups" | |
OUT_REM="$(duplicity remove-older-than 1Y --force file://$localTmpMountPath/$remoteSmbPathInShare/)" | |
# Run incremental backup, unless older than a week | |
echo "Running Backup" | |
OUT_RUN="$(duplicity --asynchronous-upload --allow-source-mismatch --full-if-older-than 1W $localDirs file://$localTmpMountPath/$remoteSmbPathInShare/)" | |
# Verify all the backups there | |
echo "Verifying backups" | |
OUT_VER="$(duplicity verify file://$localTmpMountPath/$remoteSmbPathInShare/ $localDirs)" | |
# Remove passphrase from environment | |
unset PASSPHRASE; | |
echo "Unmounting network mount" | |
umount "$localTmpMountPath" | |
successMail "${OUT_REM}" "${OUT_RUN}" "${OUT_VER}" | |
exit 0; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment