From 379b0529cfa0784b9968d4e5809963271436c9ca Mon Sep 17 00:00:00 2001 From: velvettear Date: Mon, 28 Oct 2024 13:42:07 +0100 Subject: [PATCH] add restic scripts --- scripts/restic/backup.sh | 35 ++++++++++++++++++++++++++++ scripts/restic/prune.sh | 26 +++++++++++++++++++++ scripts/restic/restic.env | 35 ++++++++++++++++++++++++++++ scripts/restic/restic.sh | 48 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100755 scripts/restic/backup.sh create mode 100755 scripts/restic/prune.sh create mode 100644 scripts/restic/restic.env create mode 100755 scripts/restic/restic.sh diff --git a/scripts/restic/backup.sh b/scripts/restic/backup.sh new file mode 100755 index 0000000..3e63cb5 --- /dev/null +++ b/scripts/restic/backup.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env zsh + +# author: Daniel Sommer +# license: MIT + +# check if we're running in a subshell, forbid direct execution +[[ "$ZSH_EVAL_CONTEXT" == "toplevel" ]] && printf "error: direct execution of this script is forbidden!\n" >&2 && exit 1 + +# get the "home" directory +home="$(dirname $(realpath "$0"))" + +# check if .env file exists and source it +env="$home/$(hostname).env" +[[ ! -r "$env" ]] && printf "error: config file '"$env"' does not exist!\n" >&2 && exit 1 +source "$env" + +# check if backup directories are defined +[[ -z "$RESTIC_DIRECTORIES" ]] && printf "error: config file '"$env"' does not define any backup directories!\n" >&2 && exit 1 + +printf ">> starting restic backup to repository '"$RESTIC_REPOSITORY"'...\n" + +# execute "pre" action if defined +[[ -n "$RESTIC_BACKUP_PRE" ]] && eval "$RESTIC_BACKUP_PRE" + +for directory in ${RESTIC_DIRECTORIES[@]}; do + seconds="$SECONDS" + printf "\n> backing up '"$directory"'...\n" + sudo --preserve-env -u "$RESTIC_USER" restic backup --verbose --no-scan --retry-lock 3h --no-cache "$directory" + printf "> backup of '"$directory"' finished after "$(( $SECONDS - $seconds ))" seconds!\n" +done + +# execute "post" action if defined +[[ -n "$RESTIC_BACKUP_POST" ]] && eval "$RESTIC_BACKUP_POST" + +printf "\n>> restic backup finished after "$SECONDS" seconds!\n" diff --git a/scripts/restic/prune.sh b/scripts/restic/prune.sh new file mode 100755 index 0000000..da8bcf8 --- /dev/null +++ b/scripts/restic/prune.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env zsh + +# author: Daniel Sommer +# license: MIT + +# check if we're running in a subshell, forbid direct execution +[[ "$ZSH_EVAL_CONTEXT" == "toplevel" ]] && printf "error: direct execution of this script is forbidden!\n" >&2 && exit 1 + +# define title and icon for the notification +export RESTIC_NTFY_TITLE="prune" +export RESTIC_NTFY_ICON="red_circle" + +# clear cache directory +rm -rf "/var/cache/restic" + +printf ">> pruning repository '"$RESTIC_REPOSITORY"'...\n\n" + +# execute "pre" action if defined +[[ -n "$RESTIC_PRUNE_PRE" ]] && eval "$RESTIC_PRUNE_PRE" + +sudo --preserve-env -u "$RESTIC_USER" restic forget --keep-daily 7 --keep-weekly 1 --keep-monthly 1 --prune --retry-lock 3h --no-cache + +# execute "post" action if defined +[[ -n "$RESTIC_PRUNE_POST" ]] && eval "$RESTIC_PRUNE_POST" + +printf "\n>> repository pruned after "$SECONDS" seconds!\n" diff --git a/scripts/restic/restic.env b/scripts/restic/restic.env new file mode 100644 index 0000000..1bd6aae --- /dev/null +++ b/scripts/restic/restic.env @@ -0,0 +1,35 @@ +#!/usr/bin/env zsh + +# author: Daniel Sommer +# license: MIT + +# define user +export RESTIC_USER="restic" + +# override default repository +export RESTIC_REPOSITORY="/mnt/restic" + +# define pre and post backup actions +export RESTIC_BACKUP_PRE="printf '\n> mounting remote storage...\n' && mount -t nfs -o vers=4,soft,noatime,nolock,retrans=1,timeo=10 192.168.100.1:/mnt/storage /mnt/n100" +export RESTIC_BACKUP_POST="printf '\n> unmounting remote storage...\n' && umount /mnt/n100" + +# define pre and post prune actions +export RESTIC_PRUNE_PRE="" +export RESTIC_PRUNE_POST="" + +# define title and icon for the notification +export RESTIC_NTFY_TITLE="storage" +export RESTIC_NTFY_ICON="yellow_circle" + +# define backup directories +export RESTIC_DIRECTORIES=( + "/mnt/n100/audiobooks" + "/mnt/n100/comics" + "/mnt/n100/documents" + "/mnt/n100/ebooks" + "/mnt/n100/images" + "/mnt/n100/music" + "/mnt/n100/software" + "/mnt/n100/syncthing" + "/mnt/n100/videos" +) diff --git a/scripts/restic/restic.sh b/scripts/restic/restic.sh new file mode 100755 index 0000000..4e9c507 --- /dev/null +++ b/scripts/restic/restic.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env zsh + +# author: Daniel Sommer +# license: MIT + +# exit on error +set -e + +# check permissions +[[ "$EUID" != 0 ]] && printf "error: permission denied!\n" >&2 && exit 1 + +# check which action to execute +[[ -n "$1" ]] && action="$1" || action="backup" + +# check if script exists +script="$(dirname $(realpath "$0"))/$action.sh" +[[ ! -x "$script" ]] && printf "error: script '"$script"' does not exist or is not executable!\n" >&2 && exit 1 + +# get the "home" directory +home="$(dirname $(realpath "$0"))" + +# setup restic +export RESTIC_USER="$(whoami)" +export RESTIC_REPOSITORY="rest:http://192.168.100.101:8000" +export RESTIC_PASSWORD="\$Velvet90" +export RESTIC_COMPRESSION="max" +export RESTIC_CACHE_DIR="/var/cache/restic" +export RESTIC_LOG="/var/log/restic-$action.log" + +# check if .env file exists and source it +env="$home/$(hostname).env" +[[ -r "$env" ]] && source "$env" + +# set default values for the notification if undefined +[[ -z "$RESTIC_NTFY_TITLE" ]] && RESTIC_NTFY_TITLE="$(hostname)" +[[ -z "$RESTIC_NTFY_ICON" ]] && RESTIC_NTFY_ICON="white_circle" + +# execute "pre" action if defined +[[ -n "$RESTIC_ACTION_PRE" ]] && eval "$RESTIC_ACTION_PRE" + +# source / execute restic script +source "$script" > >(tee "$RESTIC_LOG") 2>&1 + +# execute "post" action if defined +[[ -n "$RESTIC_ACTION_POST" ]] && eval "$RESTIC_ACTION_POST" + +# send a notification +/etc/velvettear/scripts/notify.sh "restic" "$RESTIC_LOG" --title "$RESTIC_NTFY_TITLE" --icon "$RESTIC_NTFY_ICON" > /dev/null