Files
kumonoboru/kumonoboru.sh

203 lines
6.2 KiB
Bash
Executable File

#!/bin/bash
##Simple script to run Restic backups
show_help()
{
echo "Kumonoboru - Back up important location to the B2 cloud using Restic."
echo " {-c|--clean} -- Force prune of the remote repositories"
echo " {-r|--repository} repository -- Only backup the specified repository."
echo " {-l|--limit} #[Kbps] -- Limit upload & download speed"
echo " {-v|--verbose} -- Print debug messages"
echo " {-h|--show_help} -- Print this show_help message and exit"
exit 0
}
#Pass arguments to the script
flags()
{
#This is utterly useless
if [[ $# == "0" ]]; then
:
fi
while test $# -gt 0
do
case "$1" in
(-c|--clean)
export CLEAN="1"
shift;;
(-r|--repository)
shift
export REPOSITORY="$1"
shift;;
(-l|--limit)
shift
export BWLIMIT="$1"
shift;;
(-h|--show_help)
show_help;;
(*) show_help;;
esac
done
}
flags "$@"
#File to write results to; picked up by Prometheus and yells about changes
PROM_FILE="/var/Red-Vol/Media/Containers/prometheus/data/kumonoboru.prom"
#Remove log from last runs, if present
if [[ -f $PROM_FILE ]]; then
rm $PROM_FILE
fi
## Monitoring codes:
#+ -3 - failed cleaning
#+ -2 - failed integrity check
#+ -1 - failed to unlock
#+ 0 - succesfully backed up
#+ 1 - failed backup
#+ 2 - passed integrity check
#+ 3- succesfully cleaned
#Defaults
if [[ -z $BWLIMIT ]]; then
export BWLIMIT="0"
else
echo -e "Bandwidth will be limited to" "$BWLIMIT Kbps"
fi
if [[ -n $CLEAN ]]; then
echo -e "Cleaning will take place per request."
fi
if [[ -n $REPOSITORY ]]; then
echo -e "Will only process repository" "$1"
fi
export B2_ACCOUNT_ID=8582a42a3b99 #Master Key
export B2_ACCOUNT_KEY=00041845e8dd29d7e3d091d77bb8a631ee71332be7 #Master Application ID
export RESTIC_PASSWORD='f$774$#je4%U8vp8ov*UsZMHqL$m3Smh#fEbbt7hyULQxfnnWmSiS5MEndzVWT$$n^@s$P*o4vV*^rgv3jvvrv@y35VppU$$y*vnG5V@botU&4$39Y6t9HSb3Z548M!4'
#Safety function; accepts repository to check
safety(){
REPOSITORY="$1"
echo -e "Checking if repository $REPOSITORY is in use "
#Check no other Restic process is using this repository; Free unnecessary locks, if present
if [[ -n $(ps aux | grep restic | grep "$REPOSITORY") ]]; then
echo -e "Repository is in use - ignoring"
echo "system_backup{name=\"$REPOSITORY\"} -1" >> $PROM_FILE
return 1 # code for ^ failed to unlock
# ^ If there's a restic process holding the repository, leave it alone.
else
echo -e "Repository is not in use - unlocking"
restic -q -r b2:$REPOSITORY unlock
# ^ If a lock exists but no process, the repository is safe and should be unlocked.
fi
}
#Backup function; accepts repository and path to backup
backup(){
REPOSITORY="$1"
REPOSITORY_PATH="$2"
if safety "$REPOSITORY"; then
#Run the backup
echo -e "Backing up repository" "$REPOSITORY"
if restic --cache-dir="$RESTIC_CACHE_DIR" -r b2:"$REPOSITORY" backup "$REPOSITORY_PATH" --limit-upload="$BWLIMIT" --limit-download="$BWLIMIT"; then
echo -e "$REPOSITORY_PATH" "completed upload to $REPOSITORY."
echo "system_backup{name=\"$REPOSITORY\"} 0" >> $PROM_FILE
else
echo -e "$REPOSITORY failed to upload path" "$REPOSITORY_PATH"
echo "system_backup{name=\"$REPOSITORY\"} 1" >> $PROM_FILE
fi
fi
}
check(){
REPOSITORY="$1"
PRUNE="$2"
echo -e "Checking integrity (prune: $PRUNE) of repository $REPOSITORY"
## ^ This variable will have value if repo is already clean, indicating
#+ This is a post backup check.
if [[ -n $PRUNE ]]; then
echo -e "This repository has been cleaned already; will not clean again."
fi
if safety "$REPOSITORY"; then
echo -e "Checking health of repository $REPOSITORY"
if restic -r b2:"$REPOSITORY" check --limit-upload="$BWLIMIT" --limit-download="$BWLIMIT"; then
echo -e "Repository $REPOSITORY passed integrity check"
echo "system_backup{name=\"$REPOSITORY\"} 2" >> $PROM_FILE
echo -e "Current snapshots:"
restic -r b2:"$REPOSITORY" snapshots | tee -a $LOG
else
echo -e "Repository $REPOSITORY failed integrity check"
echo "system_backup{name=\"$REPOSITORY\"} -2" >> $PROM_FILE
# code for ^ failed integrity check
fi
fi
}
clean(){
REPOSITORY="$1"
if safety "$REPOSITORY"; then
echo -e "Cleaning repository" "$REPOSITORY"
if restic -r b2:$REPOSITORY forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune --limit-upload="$BWLIMIT" --limit-download="$BWLIMIT"; then
echo -e "Repository $REPOSITORY is clean"
echo "system_backup{name=\"$REPOSITORY\"} 3" >> $PROM_FILE
echo -e "Running post clean check..."
check "$REPOSITORY" "1"
# Marks repository as cleaned already ^ so it won't passed to this function again.
else
echo -e "Failed to clean repository $REPOSITORY"
echo "system_backup{name=\"$REPOSITORY\"} -3" >> $PROM_FILE
# code for ^ failed pruning
fi
fi
}
REPO_FILE=".kumonoboru"
if [[ ! -f $REPO_FILE ]]; then
echo "Repository file $REPO_FILE is undefined. Please define $REPO_FILE."
echo "Format:"
echo "[B2-REPOSITORY] [LOCAL_PATH]"
echo "Example:"
echo "potato_tmp /tmp/potato"
exit 1
fi
if [[ -n $REPOSITORY ]]; then
repo_name=$(cat .kumonoboru | grep $REPOSITORY | awk '{print $1}')
repo_path=$(cat .kumonoboru | grep $REPOSITORY | awk '{print $2}')
if [[ -z $repo_name ]] || [[ -z $repo_path ]]; then
echo "Could not find repository $REPOSITORY"
else
REPOS["$repo_name"]=$repo_path
fi
else
declare -A REPOS
while read -r repo_entry; do
repo_name=$(echo "$repo_entry" | awk '{print $1}')
repo_path=$(echo "$repo_entry" | awk '{print $2}')
REPOS["$repo_name"]=$repo_path
done < .kumonoboru
fi
for repo in "${!REPOS[@]}"; do
repo_path=${REPOS[$repo]}
#If cleaning was forced, or if it's the first of this month - clean.
if [[ -n $CLEAN ]] || [[ $(date +%d) == "1" ]]; then
check $repo
clean $repo
#If a specific repository was requested, back it up; otherwise, back them all up.
elif [[ -z $CLEAN ]]; then
backup $repo $repo_path
fi
done
echo "All done; have a nice day!"
## Once the script finishes, the .prom file will live on for 2 minutes before being deleted.
#+ This allows Prometheus to pick up the alert, send out a notification, and move on with its life.
(
sleep 120
rm $PROM_FILE
) 2>1 >/dev/null &