From 278df9b2f7f119a16d5c591e92da3783d15f8d88 Mon Sep 17 00:00:00 2001 From: Frederik Ring Date: Fri, 20 Aug 2021 08:56:04 +0200 Subject: [PATCH] use find instead of mc for pruning local backups --- src/backup.sh | 72 ++++++++++++++++++++++----------- test/compose/docker-compose.yml | 4 ++ test/compose/run.sh | 23 +++++++++++ test/swarm/docker-compose.yml | 2 + 4 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/backup.sh b/src/backup.sh index 718e3c8..b93f954 100644 --- a/src/backup.sh +++ b/src/backup.sh @@ -103,36 +103,62 @@ fi info "Backup finished" echo "Will wait for next scheduled backup." +probe_expired () { + local target=$1 + local is_local=$2 + if [ -z "$is_local" ]; then + mc rm $MC_GLOBAL_OPTIONS --fake --recursive --force \ + --older-than "${BACKUP_RETENTION_DAYS}d" \ + "$target" + else + find $target* -type f -mtime $BACKUP_RETENTION_DAYS + fi +} + +probe_all () { + local target=$1 + local is_local=$2 + if [ -z "$is_local" ]; then + mc ls $MC_GLOBAL_OPTIONS "$target" + else + find $target* -type f + fi +} + +delete () { + local target=$1 + local is_local=$2 + if [ -z "$is_local" ]; then + mc rm $MC_GLOBAL_OPTIONS --recursive --force \ + --older-than "${BACKUP_RETENTION_DAYS}d" \ + "$target" + else + find $target* -delete -type f -mtime $BACKUP_RETENTION_DAYS + fi +} + prune () { - target=$1 + local target=$1 + local is_local=$2 if [ ! -z "$BACKUP_PRUNING_PREFIX" ]; then target="$target/${BACKUP_PRUNING_PREFIX}" fi - rule_applies_to=$( - mc rm $MC_GLOBAL_OPTIONS --fake --recursive --force \ - --older-than "${BACKUP_RETENTION_DAYS}d" \ - "$target" \ - | wc -l - ) + rule_applies_to=$(probe_expired "$target" "$is_local" | wc -l) if [ "$rule_applies_to" == "0" ]; then - echo "No backups found older than the configured retention period of $BACKUP_RETENTION_DAYS days." + echo "No backups found older than the configured retention period of ${BACKUP_RETENTION_DAYS} days." echo "Doing nothing." - exit 0 + else + total=$(probe_all "$target" "$is_local" | wc -l) + + if [ "$rule_applies_to" == "$total" ]; then + echo "Using a retention of ${BACKUP_RETENTION_DAYS} days would prune all currently existing backups, will not continue." + echo "If this is what you want, please remove files manually instead of using this script." + else + delete "$target" "$is_local" + echo "Successfully pruned ${rule_applies_to} backups older than ${BACKUP_RETENTION_DAYS} days." + fi fi - - total=$(mc ls $MC_GLOBAL_OPTIONS "$target" | wc -l) - - if [ "$rule_applies_to" == "$total" ]; then - echo "Using a retention of ${BACKUP_RETENTION_DAYS} days would prune all currently existing backups, will not continue." - echo "If this is what you want, please remove files manually instead of using this script." - exit 1 - fi - - mc rm $MC_GLOBAL_OPTIONS \ - --recursive --force \ - --older-than "${BACKUP_RETENTION_DAYS}d" "$target" - echo "Successfully pruned ${rule_applies_to} backups older than ${BACKUP_RETENTION_DAYS} days." } if [ ! -z "$BACKUP_RETENTION_DAYS" ]; then @@ -145,6 +171,6 @@ if [ ! -z "$BACKUP_RETENTION_DAYS" ]; then fi if [ -d "$BACKUP_ARCHIVE" ]; then info "Pruning old backups from local archive" - prune "$BACKUP_ARCHIVE" + prune "$BACKUP_ARCHIVE" "local" fi fi diff --git a/test/compose/docker-compose.yml b/test/compose/docker-compose.yml index d54f331..c62747e 100644 --- a/test/compose/docker-compose.yml +++ b/test/compose/docker-compose.yml @@ -25,6 +25,10 @@ services: AWS_S3_BUCKET_NAME: backup BACKUP_FILENAME: test.tar.gz BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ? + BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7} + BACKUP_FORCE_PRUNE: ${BACKUP_FORCE_PRUNE:-} + BACKUP_PRUNING_LEEWAY: 5s + BACKUP_PRUNING_PREFIX: test volumes: - ./local:/archive - app_data:/backup/app_data:ro diff --git a/test/compose/run.sh b/test/compose/run.sh index 8d19419..9d65971 100755 --- a/test/compose/run.sh +++ b/test/compose/run.sh @@ -29,4 +29,27 @@ fi echo "[TEST:PASS] All containers running post backup." +docker-compose down + +# The second part of this test checks if backups get deleted when the retention +# is set to 0 days (which it should not as it would mean all backups get deleted) +# TODO: find out if we can test actual deletion without having to wait for a day +BACKUP_RETENTION_DAYS="0" docker-compose up -d +sleep 5 + +docker-compose exec backup backup + +docker run --rm -it \ + -v compose_backup_data:/data alpine \ + ash -c '[ $(find /data/backup/ -type f | wc -l) = "1" ]' + +echo "[TEST:PASS] Remote backups have not been deleted." + +if [ "$(find ./local -type f | wc -l)" != "1" ]; then + echo "[TEST:FAIL] Backups should not have been deleted, instead seen:" + find ./local -type f +fi + +echo "[TEST:PASS] Local backups have not been deleted." + docker-compose down --volumes diff --git a/test/swarm/docker-compose.yml b/test/swarm/docker-compose.yml index c188e2b..5c26e72 100644 --- a/test/swarm/docker-compose.yml +++ b/test/swarm/docker-compose.yml @@ -33,6 +33,8 @@ services: AWS_S3_BUCKET_NAME: backup BACKUP_FILENAME: test.tar.gz BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ? + BACKUP_RETENTION_DAYS: 7 + BACKUP_PRUNING_LEEWAY: 5s volumes: - pg_data:/backup/pg_data:ro - /var/run/docker.sock:/var/run/docker.sock