Rewritten to breakdown the script into specific functions

Added monthly backups that are only taken once a month
Added weekly backups that are only taken once a week
Added backup deletion protection when backups are failing to be taken
Added flags so that tasks can be run separately from each other
Added the ability to choose whether backups are actually deleted or a dry run is performed
Removed last backup folder and latest backup symbolic links
This commit is contained in:
atcommander
2022-06-23 20:22:11 +00:00
committed by Pau Rodriguez-Estivill
parent af916da211
commit d1793740b3
+206 -46
View File
@@ -1,4 +1,39 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Environmental variables
#POSTGRES_DB_FILE="**None**"
#POSTGRES_USER_FILE="**None**"
#POSTGRES_PASSWORD_FILE="**None**"
#POSTGRES_PASSFILE_STORE="**None**"
#BACKUP_DIR="/matrix/postgres-backup"
#POSTGRES_USER=matrix
#POSTGRES_PASSWORD=3wI9iPlxuMnv2xT3Ozk1rCYOOfF192GlK6rCcwkQD7KlMkTKgsjG9umPQQNAINJ9
#POSTGRES_HOST=matrix-postgres
#POSTGRES_DB=( synapse matrix_registration matrix_mautrix_telegram matrix_prometheus_postgres_exporter )
#POSTGRES_EXTRA_OPTS="-Z9 --schema=public --blobs"
#SCHEDULE=@daily
#HEALTHCHECK_PORT=8080
#POSTGRES_PORT=5432
BACKUP_KEEP_DAYS="2"
BACKUP_DELETE_DAYS=false
BACKUP_KEEP_WEEKS="0"
BACKUP_DELETE_WEEKS=false
BACKUP_KEEP_MONTHS="0"
BACKUP_DELETE_MONTHS=false
BACKUP_MONTH_DAY="01"
BACKUP_WEEK_DAY="Sunday"
# Import variables from environment
export PGHOST="${POSTGRES_HOST}"
export PGPORT="${POSTGRES_PORT}"
KEEP_MINS=${BACKUP_KEEP_MINS}
KEEP_DAYS=${BACKUP_KEEP_DAYS}
KEEP_WEEKS=`expr $((${BACKUP_KEEP_WEEKS} * 7))`
KEEP_MONTHS=`expr $((${BACKUP_KEEP_MONTHS} * 31))`
setup () {
set -Eeo pipefail set -Eeo pipefail
if [ "${POSTGRES_DB}" = "**None**" -a "${POSTGRES_DB_FILE}" = "**None**" ]; then if [ "${POSTGRES_DB}" = "**None**" -a "${POSTGRES_DB_FILE}" = "**None**" ]; then
@@ -53,28 +88,52 @@ else
echo "Missing POSTGRES_PASSWORD_FILE or POSTGRES_PASSFILE_STORE file." echo "Missing POSTGRES_PASSWORD_FILE or POSTGRES_PASSFILE_STORE file."
exit 1 exit 1
fi fi
export PGHOST="${POSTGRES_HOST}"
export PGPORT="${POSTGRES_PORT}"
KEEP_MINS=${BACKUP_KEEP_MINS}
KEEP_DAYS=${BACKUP_KEEP_DAYS}
KEEP_WEEKS=`expr $(((${BACKUP_KEEP_WEEKS} * 7) + 1))`
KEEP_MONTHS=`expr $(((${BACKUP_KEEP_MONTHS} * 31) + 1))`
#Initialize dirs FREQUENCY=( daily weekly monthly )
mkdir -p "${BACKUP_DIR}/last/" "${BACKUP_DIR}/daily/" "${BACKUP_DIR}/weekly/" "${BACKUP_DIR}/monthly/"
for f in ${FREQUENCY[@]}
do
mkdir -p "${BACKUP_DIR}/${f}/"
done
MONTH_DAY=`date +%d`
WEEK_DAY=`date +%A`
}
#Create Backups
create_backups () {
for DB in ${POSTGRES_DBS}
do
FILE="${BACKUP_DIR}/daily/${DB}-`date +%Y%m%d`${BACKUP_SUFFIX}"
create_dump
if [ "${BACKUP_MONTH_DAY}" = "${MONTH_DAY}" ]
then
create_hardlinks "${FILE}" "monthly"
elif [ "${BACKUP_WEEK_DAY}" = "${WEEK_DAY}" ]
then
create_hardlinks "${FILE}" "weekly"
fi
echo "SQL backup created successfully"
done
}
# Create dump of postgres database
create_dump () {
#Loop all databases
for DB in ${POSTGRES_DBS}; do
#Initialize filename vers
LAST_FILENAME="${DB}-`date +%Y%m%d-%H%M%S`${BACKUP_SUFFIX}"
DAILY_FILENAME="${DB}-`date +%Y%m%d`${BACKUP_SUFFIX}"
WEEKLY_FILENAME="${DB}-`date +%G%V`${BACKUP_SUFFIX}"
MONTHY_FILENAME="${DB}-`date +%Y%m`${BACKUP_SUFFIX}"
FILE="${BACKUP_DIR}/last/${LAST_FILENAME}"
DFILE="${BACKUP_DIR}/daily/${DAILY_FILENAME}"
WFILE="${BACKUP_DIR}/weekly/${WEEKLY_FILENAME}"
MFILE="${BACKUP_DIR}/monthly/${MONTHY_FILENAME}"
#Create dump
if [ "${POSTGRES_CLUSTER}" = "TRUE" ]; then if [ "${POSTGRES_CLUSTER}" = "TRUE" ]; then
echo "Creating cluster dump of ${DB} database from ${POSTGRES_HOST}..." echo "Creating cluster dump of ${DB} database from ${POSTGRES_HOST}..."
pg_dumpall -l "${DB}" ${POSTGRES_EXTRA_OPTS} | gzip > "${FILE}" pg_dumpall -l "${DB}" ${POSTGRES_EXTRA_OPTS} | gzip > "${FILE}"
@@ -82,36 +141,137 @@ for DB in ${POSTGRES_DBS}; do
echo "Creating dump of ${DB} database from ${POSTGRES_HOST}..." echo "Creating dump of ${DB} database from ${POSTGRES_HOST}..."
pg_dump -d "${DB}" -f "${FILE}" ${POSTGRES_EXTRA_OPTS} pg_dump -d "${DB}" -f "${FILE}" ${POSTGRES_EXTRA_OPTS}
fi fi
}
# Create hardlinks from daily backup to monthly and weekly backups
create_hardlinks () {
SRC=$1
INCREMENT=$2
if [ "${INCREMENT}" = "weekly" ]
then
echo "Creating Weekly Backup of ${DB} database from ${POSTGRES_HOST}..."
FILENAME="${DB}-`date +%G%V`${BACKUP_SUFFIX}"
elif [ "${INCREMENT}" = "monthly"]
then
echo "Creating Monthly Backup of ${DB} database from ${POSTGRES_HOST}..."
FILENAME="${DB}-`date +%Y%m`${BACKUP_SUFFIX}"
fi
DEST="${BACKUP_DIR}/${INCREMENT}/${FILENAME}"
#Copy (hardlink) for each entry #Copy (hardlink) for each entry
if [ -d "${FILE}" ]; then if [ -d "${SRC}" ]
DFILENEW="${DFILE}-new" then
WFILENEW="${WFILE}-new" ln -f "${SRC}/"* "${DEST}/"
MFILENEW="${MFILE}-new"
rm -rf "${DFILENEW}" "${WFILENEW}" "${MFILENEW}"
mkdir "${DFILENEW}" "${WFILENEW}" "${MFILENEW}"
ln -f "${FILE}/"* "${DFILENEW}/"
ln -f "${FILE}/"* "${WFILENEW}/"
ln -f "${FILE}/"* "${MFILENEW}/"
rm -rf "${DFILE}" "${WFILE}" "${MFILE}"
mv -v "${DFILENEW}" "${DFILE}"
mv -v "${WFILENEW}" "${WFILE}"
mv -v "${MFILENEW}" "${MFILE}"
else else
ln -vf "${FILE}" "${DFILE}" ln -vf "${SRC}" "${DEST}"
ln -vf "${FILE}" "${WFILE}"
ln -vf "${FILE}" "${MFILE}"
fi fi
# Update latest symlinks # Update latest symlinks
ln -svf "${LAST_FILENAME}" "${BACKUP_DIR}/last/${DB}-latest${BACKUP_SUFFIX}" ln -svf "${DEST}" "${BACKUP_DIR}/${INCREMENT}/${DB}-latest"
ln -svf "${DAILY_FILENAME}" "${BACKUP_DIR}/daily/${DB}-latest${BACKUP_SUFFIX}"
ln -svf "${WEEKLY_FILENAME}" "${BACKUP_DIR}/weekly/${DB}-latest${BACKUP_SUFFIX}" }
ln -svf "${MONTHY_FILENAME}" "${BACKUP_DIR}/monthly/${DB}-latest${BACKUP_SUFFIX}"
#Clean up old backups
cleanup_backups () {
for folder in "${FREQUENCY[@]}"
do
if [ $folder == "weekly" ]
then
KEEP=$KEEP_WEEKS
DELETE=$BACKUP_DELETE_WEEKS
elif [ $folder == 'monthly' ]
then
KEEP=$KEEP_MONTHS
DELETE=$BACKUP_DELETE_MONTHS
elif [ $folder == 'daily' ]
then
KEEP=$KEEP_DAYS
DELETE=$BACKUP_DELETE_DAYS
fi
for DB in ${POSTGRES_DBS}
do
#Clean old files #Clean old files
echo "Cleaning older files for ${DB} database from ${POSTGRES_HOST}..." echo "Cleaning older files in ${folder} for ${DB} database from ${POSTGRES_HOST}..."
find "${BACKUP_DIR}/last" -maxdepth 1 -mmin "+${KEEP_MINS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rf '{}' ';'
find "${BACKUP_DIR}/daily" -maxdepth 1 -mtime "+${KEEP_DAYS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rf '{}' ';' local all=( `find "${BACKUP_DIR}/${folder}" -maxdepth 1 -name "${DB}-*"` )
find "${BACKUP_DIR}/weekly" -maxdepth 1 -mtime "+${KEEP_WEEKS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rf '{}' ';'
find "${BACKUP_DIR}/monthly" -maxdepth 1 -mtime "+${KEEP_MONTHS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rf '{}' ';' if [ $KEEP -gt 0 ]
then
local files=( `find "${BACKUP_DIR}/${folder}" -maxdepth 1 -mtime "+$((${KEEP}-1))" -name "${DB}-*"` )
fi
if [ $((${#all[@]}-${#files[@]})) -lt ${KEEP} ]
then
echo "Only ${#all[@]} Backups exist for ${DB} and you want to keep $KEEP."
echo "If you have just started taking backups you may ignore this"
echo "Otherwise you may want to investigate why backups are not being taken"
elif $DELETE
then
for file in "${files[@]}"
do
echo "Deleting $file"
rm $file
done
else
for file in "${files[@]}"
do
echo "Dry Run: Delete $file"
done
fi
done done
echo "SQL backup created successfully" done
}
listCommands () {
echo "--create-backup -b Create Daily, Weekly and Monthly backups"
echo "--cleanup -c Cleanup old backups"
echo "--help -h List commands"
}
case $1 in
"--create-backup" | "-b")
setup
create_backups
;;
"--cleanup" | "-c")
setup
cleanup_backups
;;
"--help" | "-h")
listCommands
;;
*)
echo "No command found."
listCommands
esac