scripts/helios/external-backup.sh

274 lines
7.4 KiB
Bash
Raw Normal View History

2021-08-12 13:07:36 +00:00
#!/bin/bash
#
2021-08-12 15:44:15 +00:00
# Script rotiert Backup-Verzeichnisse und zieht per rsync Backups
# http://www.heinlein-support.de
2021-08-12 13:07:36 +00:00
#
# https://www.heinlein-support.de/howto/backups-und-snapshots-von-linux-servern-mit-rsync-und-ssh
#
# Zusammengeführt und angepasst durch Tobias Strobel (2021)
#
2021-08-12 15:44:15 +00:00
LOGFILE="$(mktemp)"
2021-08-12 13:07:36 +00:00
SERVER="$(hostname)"
# ### Konfiguration
# Sollen wir pruefen, ob noch ein gewisser Prozentsatz
# an Plattenplatz und Inodes frei ist?
HDMINFREE=90
# Welcher Pfad soll gesichert werden?
SRC_PATH=/
setLED () {
# Set LED status
echo heartbeat > "/sys/class/leds/helios64:blue:usb3/trigger"
echo 1 > "/sys/class/leds/helios64:blue:usb3/brightness"
}
clearLED () {
# Clear LED status
echo usbport > "/sys/class/leds/helios64:blue:usb3/trigger"
echo 0 > "/sys/class/leds/helios64:blue:usb3/brightness"
}
finishUp () {
# Clean up tempfiles
2021-08-12 15:44:15 +00:00
rm "$LOGFILE"
# Just to be sure
2021-08-12 13:07:36 +00:00
sync -f $DATA_PATH
}
healthchecksStart () {
2021-08-12 15:44:15 +00:00
curl -fsS -m 10 --retry 5 -o /dev/null "$HCURL"/start
2021-08-12 13:07:36 +00:00
}
healthchecksFinish () {
2021-08-12 15:44:15 +00:00
# $1 Status Code
curl -fsS -m 10 --retry 5 -o /dev/null --data-binary "@$LOGFILE" "$HCURL"/"$1"
2021-08-12 13:07:36 +00:00
}
notify () {
# $1 Action
2021-08-12 15:44:15 +00:00
# $2 Status code
2021-08-12 13:07:36 +00:00
# $3 Custom Title
# $4 Custom Message
# $5 Custom Priority
NOTIFY_TITLE="[$SERVER] "
NOTIFY_MESSAGE=""
NOTIFY_PRIORITY=1
case "$1" in
2021-08-12 15:44:15 +00:00
start)
2021-08-12 13:07:36 +00:00
NOTIFY_TITLE+="Backup started"
NOTIFY_MESSAGE="Backup to external hdd started"
;;
2021-08-12 15:44:15 +00:00
finish)
NOTIFY_TITLE+="Backup finished"
NOTIFY_MESSAGE="Backup to external hdd finished"
NOTIFY_PRIORITY=5
2021-08-12 13:07:36 +00:00
;;
2021-08-12 15:44:15 +00:00
error)
NOTIFY_TITLE+="Backup has ERRORS"
2021-09-29 19:09:15 +00:00
NOTIFY_MESSAGE="Exit code $2. See logs attached to healthchecks for more information."
2021-08-12 15:44:15 +00:00
NOTIFY_PRIORITY=8
;;
2021-08-12 13:07:36 +00:00
*)
NOTIFY_TITLE+="$3"
NOTIFY_MESSAGE="$4"
NOTIFY_PRIORITY="$5"
;;
esac
2021-08-12 15:44:15 +00:00
curl -fsS -m 10 --retry 5 -o /dev/null "$GOTIFYURL" -F "title=$NOTIFY_TITLE" -F "message=$NOTIFY_MESSAGE" -F "priority=$NOTIFY_PRIORITY"
2021-08-12 13:07:36 +00:00
}
checkFreeSpace () {
# Pruefe auf freien Plattenplatz
GETPERCENTAGE='s/.* \([0-9]\{1,3\}\)%.*/\1/'
KBISFREE=$(df /$DATA_PATH | tail -n1 | sed -e "$GETPERCENTAGE")
INODEISFREE=$(df -i /$DATA_PATH | tail -n1 | sed -e "$GETPERCENTAGE")
if [ "$KBISFREE" -ge $HDMINFREE ] || [ "$INODEISFREE" -ge $HDMINFREE ] ; then
echo "Fatal: Not enough space left for rotating backups!"
2021-08-12 15:44:15 +00:00
healthchecksFinish fail
notify custom "NOT_ENOUGH_SPACE_LEFT" "FATAL" "Not enough space left for rotating backups!"
2021-08-12 13:07:36 +00:00
exit
fi
}
basicChecks () {
2021-09-29 19:09:15 +00:00
CONFFILE=~/.config/externalbackup.conf
if ! [ -f $CONFFILE ] ; then
cat >>$CONFFILE <<EOF
# GOTIFYURL="https://push.domain.tld/message?token=MYSECRETTOKEN"
GOTIFYURL=""
# HCURL="https://ping.domain.tld/ping/aaaaaaaa-bbbb-cccc-dddddddddddd"
HCURL=""
EOF
fi
source $CONFFILE
if [ -z $GOTIFYURL ] || [ -z $HCURL ] ; then
echo "Fatal: GOTIFYURL and HCURL must be set in $CONFFILE. Please edit the file and set correct values, then try again."
exit 1
fi
if [ -z "$1" ] ; then
echo "A hdd name to backup to must be given as first parameter! (E.g. backupone, for /mnt/backupone)"
notify custom "NO_HDD_NAME_GIVEN" "FATAL" "No hdd name given to backup to. (E.g. backupone, for /mnt/backupone)"
exit 1
fi
HDDNAME="${1}"
# Unter welchem Pfad wird gesichert?
DATA_PATH="/mnt/${HDDNAME}"
2021-08-12 13:07:36 +00:00
if ! [ -d $DATA_PATH ] ; then
echo "Fatal: Data path does not exist: $DATA_PATH"
2021-08-12 15:44:15 +00:00
healthchecksFinish fail
notify custom "DATA_PATH_NON_EXISTENT" "FATAL" "Data path does not exist: $DATA_PATH"
2021-08-12 13:07:36 +00:00
exit
fi
checkFreeSpace
# Ggf. Verzeichnis anlegen
if ! [ -d $DATA_PATH/"$SERVER"/daily.0 ] ; then
2021-08-12 15:44:15 +00:00
mkdir -p $DATA_PATH/"$SERVER"/daily.0
2021-08-12 13:07:36 +00:00
fi
}
rotate () {
echo "Rotating snapshots of $SERVER..."
# Das hoechste Snapshot abloeschen
2021-09-13 08:37:08 +00:00
if [ -d $DATA_PATH/"$SERVER"/daily.12 ] ; then
rm -rf $DATA_PATH/"$SERVER"/daily.12
2021-08-12 13:07:36 +00:00
fi
# Alle anderen Snapshots eine Nummer nach oben verschieben
2021-08-12 15:44:15 +00:00
for OLD in 12 11 10 9 8 7 6 5 4 3 2 1 ; do
2021-08-12 13:07:36 +00:00
if [ -d $DATA_PATH/"$SERVER"/daily.$OLD ] ; then
2021-08-12 15:44:15 +00:00
NEW=$(( OLD + 1 ))
2021-08-12 13:07:36 +00:00
# Datum sichern
touch $DATA_PATH/.timestamp -r $DATA_PATH/"$SERVER"/daily.$OLD
mv $DATA_PATH/"$SERVER"/daily.$OLD $DATA_PATH/"$SERVER"/daily."$NEW"
# Datum zurueckspielen
touch $DATA_PATH/"$SERVER"/daily."$NEW" -r $DATA_PATH/.timestamp
fi
done
# Snapshot von Level-0 per hardlink-Kopie nach Level-1 kopieren
if [ -d $DATA_PATH/"$SERVER"/daily.0 ] ; then
2021-08-12 15:44:15 +00:00
cp -al $DATA_PATH/"$SERVER"/daily.0 $DATA_PATH/"$SERVER"/daily.1
2021-08-12 13:07:36 +00:00
fi
2021-08-12 15:44:15 +00:00
STATUSCODE=$?
if [ "$STATUSCODE" -ne 0 ] ; then
echo "Fatal: rotation finished on $SERVER with errors!"
healthchecksFinish "$STATUSCODE"
notify error "$STATUSCODE"
exit "$STATUSCODE"
fi
2021-08-12 13:07:36 +00:00
echo "Finished rotating backups of $SERVER..."
}
2021-09-29 19:09:15 +00:00
backupNC () {
NCDIR="/var/www/nextcloud"
NCOCC="sudo -u www-data php $NCDIR/occ"
NCDATADIR="$($NCOCC config:system:get datadirectory)"
NCDUMPSDIR="$NCDATADIR/sqldumps"
2021-09-30 07:53:30 +00:00
NCBKPPATH="$DATA_PATH/"$SERVER"/daily.0$NCDATADIR"
2021-09-29 19:09:15 +00:00
DBPASSWORD="$($NCOCC config:system:get dbpassword)"
DBNAME="$($NCOCC config:system:get dbname)"
DBHOST="$($NCOCC config:system:get dbhost)"
DBUSER="$($NCOCC config:system:get dbuser)"
DELETEDAYS=15
if [ ! -f "$NCDIR/config/config.php" ]; then
echo "WARN: Nextcloud config not found! Skip Nextcloud backup..."
notify custom "NC_CONFIG_NOT_FOUND" "WARN" "Nextcloud config not found! Skip Nextcloud backup..."
return 1
fi
mkdir -p $NCDUMPSDIR
find $NCDUMPSDIR/nextcloud-sqlbkp_* -maxdepth 0 -mmin +$(($DELETEDAYS*60*24)) -exec rm -rvf {} \; > 2&>1
echo "Starting nextcloud backup..."
$NCOCC maintenance:mode --on
echo "Backup Nextcloud DB"
PGPASSWORD=$DBPASSWORD pg_dump $DBNAME -h $DBHOST -U $DBUSER -f "$NCDUMPSDIR/nextcloud-sqlbkp_`date +"%Y-%m-%d-%H-%M-%S"`.bak"
echo "Backup $NCDATADIR"
2021-09-30 07:53:30 +00:00
mkdir -p $NCBKPPATH
rsync -aAXHh --stats --numeric-ids --noatime --delete --delete-excluded $NCDATADIR/ $NCBKPPATH
2021-09-29 19:09:15 +00:00
STATUSCODE=$?
# Rückgabewert prüfen.
# 0 = fehlerfrei,
# 24 ist harmlos; tritt auf, wenn während der Laufzeit
# von rsync noch (/tmp?) Dateien verändert oder gelöscht wurden.
# Alles andere ist fatal -- siehe man (1) rsync
if [ "$STATUSCODE" -ne 24 ] && [ "$STATUSCODE" -ne 0 ] ; then
echo "Fatal: rsync for Nextcloud finished on $SERVER with errors!"
healthchecksFinish "$STATUSCODE"
notify error "$STATUSCODE"
$NCOCC maintenance:mode --off
exit "$STATUSCODE"
fi
echo "Finished nextcloud backup..."
$NCOCC maintenance:mode --off
}
2021-08-12 13:07:36 +00:00
backup () {
2021-09-29 19:09:15 +00:00
backupNC
2021-08-12 13:07:36 +00:00
echo "Starting rsync backup from $SERVER..."
2021-08-12 15:44:15 +00:00
rsync -aAXHh --stats --numeric-ids --noatime --delete --delete-excluded \
2021-09-29 19:09:15 +00:00
--include={"/mnt/storage","/mnt/storage/media**","/mnt/storage/backup**"} \
2021-08-12 15:44:15 +00:00
--exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found","/.snapshots"} \
$SRC_PATH $DATA_PATH/"$SERVER"/daily.0
2021-08-12 13:07:36 +00:00
2021-08-12 15:44:15 +00:00
STATUSCODE=$?
2021-08-12 13:07:36 +00:00
# Rückgabewert prüfen.
# 0 = fehlerfrei,
# 24 ist harmlos; tritt auf, wenn während der Laufzeit
# von rsync noch (/tmp?) Dateien verändert oder gelöscht wurden.
# Alles andere ist fatal -- siehe man (1) rsync
2021-08-12 15:44:15 +00:00
if [ "$STATUSCODE" -ne 24 ] && [ "$STATUSCODE" -ne 0 ] ; then
echo "Fatal: rsync finished on $SERVER with errors!"
healthchecksFinish "$STATUSCODE"
notify error "$STATUSCODE"
exit "$STATUSCODE"
2021-08-12 13:07:36 +00:00
fi
# Verzeichnis anfassen, um Backup-Datum zu speichern
touch $DATA_PATH/"$SERVER"/daily.0
echo "Finished rsync backup from $SERVER..."
}
2021-08-12 15:44:15 +00:00
# Write output to logfile
exec > >(tee -i "${LOGFILE}")
exec 2>&1
2021-09-29 19:09:15 +00:00
basicChecks ${1}
2021-08-12 15:44:15 +00:00
healthchecksStart
notify start
2021-08-12 13:07:36 +00:00
setLED
backup
rotate
2021-08-12 15:44:15 +00:00
healthchecksFinish
notify finish 0
2021-08-12 13:07:36 +00:00
finishUp
clearLED