From eb5ede75f0b16e5dc4c67427a6de34ebbce4c34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kov=C3=A1cs=20Zolt=C3=A1n?= Date: Thu, 6 Mar 2025 18:55:00 +0100 Subject: [PATCH] Additional export backups feature. --- .metadata | Bin 14515 -> 14916 bytes .templates/nginx/nginx_xport.inc | 18 ++++ configs/.gitignore | 1 + configs/xport_backup | 3 + storage/.gitignore | 5 + storage/backups/.gitignore | 5 + storage/backups/export/.gitignore | 4 + storage/backups/export/.rotate_folder.conf | 9 ++ tools/backup.d/xport_backup.sh | 105 +++++++++++++++++++++ 9 files changed, 150 insertions(+) create mode 100644 .templates/nginx/nginx_xport.inc create mode 100644 configs/xport_backup create mode 100644 storage/.gitignore create mode 100644 storage/backups/.gitignore create mode 100644 storage/backups/export/.gitignore create mode 100644 storage/backups/export/.rotate_folder.conf create mode 100644 tools/backup.d/xport_backup.sh diff --git a/.metadata b/.metadata index 782f4981d0916888ae17a983ae5935956afdf6a2..13935af2ee82e076418b6da56bbf5305e9544e27 100644 GIT binary patch delta 467 zcmdm7c%)=QGaHZagOlkDK=7E$S7>q~x9H@4W!1?BBD|ZgvF%`*+{Q1!mReDeUsN*L zP)b5*0#vcW)0@&DO&c0FcW^eb@?3?AYyACSHTfg2_T=|ktdp;sXiU!I?|@5Q+V#*1 zWWyvm*~tbLypwI@1Q{JCH}H$WY?#Nd$Skt<12}+vJDx>XUy9@K0W#V7ocMB$)*OG%ugw delta 259 zcmX?7vbk_WGaHZR+7syvKw#y#nRD_)QPIf_=3p)xr~zk|0nKxNLhja3MZvM%q lOlI&*`t>pu +# License: GNU/GPL v3+ (https://www.gnu.org/licenses/gpl-3.0.en.html) +# 2025-03-06 v0.1 Initial release + +# Accepted environment variables and their defaults. +PAR_BASEDIR=${PAR_BASEDIR:-""} # Service's base folder +PAR_DUMPDIR=${PAR_DUMPDIR:-""} # Absolute path to DB dumps +PAR_EXPORTDIR=${PAR_EXPORTDIR:-""} # Absolute path to export dir +PAR_RETAINDAYS=${PAR_RETAINDAYS:-"1"} # Days to retain the copies +PAR_TARBALLDIR=${PAR_TARBALLDIR:-""} # Absolute path to tgz dumps + +# Other initialisations. +CLASSES_PATTERN="^([^.]*)\..*\.$HOSTNAME\.(dmp|sql\.gz|tgz|log)$" +DUMPPATH="storage/backups/dumps" # Default path to DB dumps +EXPORTPATH="storage/backups/export" # Default path to export dir +TARBALLPATH="storage/backups/tarballs" # Default path to tgz dumps +USER=${USER:-LOGNAME} # Fix for cron enviroment only +YMLFILE="docker-compose.yml" + +# Messages. +MSG_MISSINGDEP="Fatal: missing dependency" +MSG_MISSINGYML="Fatal: didn't find the docker-compose.yml file" +MSG_NONWRITE="The target directory isn't writable" + +# Checks the dependencies. +TR=$(which tr 2>/dev/null) +if [ -z "$TR" ]; then echo "$MSG_MISSINGDEP tr."; exit 1 ; fi +for item in cp cut date dirname grep hostname readlink rotate_folder tar +do + if [ -n "$(which $item)" ] + then export $(echo $item | "$TR" '[:lower:]' '[:upper:]' | "$TR" '-' '_')=$(which $item) + else echo "$MSG_MISSINGDEP $item." >&2; exit 1; fi +done + +# Where I'm? +# https://gist.github.com/TheMengzor/968e5ea87e99d9c41782 +SOURCE="$0" +while [ -h "$SOURCE" ]; do + # resolve $SOURCE until the file is no longer a symlink + SCRPATH="$( cd -P "$("$DIRNAME" "$SOURCE" )" && pwd )" #" + SOURCE="$("$READLINK" "$SOURCE")" + # if $SOURCE was a relative symlink, we need to resolve it + # relative to the path where the symlink file was located + [[ $SOURCE != /* ]] && SOURCE="$SCRPATH/$SOURCE" +done; SCRPATH="$( cd -P "$("$DIRNAME" "$SOURCE" )" && pwd )" #" + +# Searches the base folder, containing a docker-compose.yml file. +# Called from the base folder (./)? +BASE_DIR="$PAR_BASEDIR" +TEST_DIR="$SCRPATH" +[[ -z "$BASE_DIR" ]] && [[ -r "$TEST_DIR/$YMLFILE" ]] && BASE_DIR="$TEST_DIR" +# Called from ./tools? +TEST_DIR="$("$DIRNAME" "$TEST_DIR")" +[[ -z "$BASE_DIR" ]] && [[ -r "$TEST_DIR/$YMLFILE" ]] && BASE_DIR="$TEST_DIR" +# Called from ./tools/*.d? +TEST_DIR="$("$DIRNAME" "$TEST_DIR")" +[[ -z "$BASE_DIR" ]] && [[ -r "$TEST_DIR/$YMLFILE" ]] && BASE_DIR="$TEST_DIR" +# On failure gives it up here. +if [ -z "$BASE_DIR" -o ! -r "$BASE_DIR/$YMLFILE" ]; then + echo "$MSG_MISSINGYML" >&2; exit 1 +fi +# Sets the absolute paths. +DUMPDIR="${PAR_DUMPDIR:-$BASE_DIR/$DUMPPATH}" +EXPORTDIR="${PAR_EXPORTDIR:-$BASE_DIR/$EXPORTPATH}" +TARBALLDIR="${PAR_TARBALLDIR:-$BASE_DIR/$TARBALLPATH}" + +# Exits silently if EXPORTDIR isn't present. +[[ ! -e "$EXPORTDIR" ]] && exit 0 +# EXPORTDIR must be writable. +[[ ! -w "$EXPORTDIR" ]] \ +&& echo "$MSG_NONWRITE: $BACKUPDIR" >&2 && exit 1 + +# Let's select and copy the appropriate backup files. +# +# We'll call rotate_folder (dry run) with CLASSES_PATTERN and PAR_RETAINDAYS +# set above to select relevant files created in the backup folders within last +# PAR_RETAINDAYS days. These files are synchronized with the cp -u statement. +# +# Enumerates the folders. +for folder in "$DUMPDIR" "$TARBALLDIR" +do + # Selects the appropriate files (which have the "DR" - daily retain - tag). + for filename in $((export CLASSES_PATTERN="$CLASSES_PATTERN" \ + RETAIN_DAYS="$PAR_RETAINDAYS" RETAIN_WEEKS=0 RETAIN_MONTHS=0; \ + "$ROTATE_FOLDER" --noconf -f "$folder") | \ + "$GREP" '^DR ' | "$CUT" -d' ' -f2) "" + do + # Updates the current file. + if [ -n "$filename" ]; then + "$CP" -u "$folder/$filename" "$EXPORTDIR/" 2>/dev/null + fi + done +done + +# That's all, Folks! :)