diff --git a/.gitignore b/.gitignore index 3e78d8e..9750d07 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,9 @@ postgres mongo mongo-volume + +# backup files created by backup.sh +mongo-volume-backup-*.tar.gz + +# backups directory for mongo-volume tarballs +/backups/ diff --git a/backup.sh b/backup.sh new file mode 100755 index 0000000..6783abc --- /dev/null +++ b/backup.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Configuration +MONGO_SERVICE="utility-bills-tracker_mongo" + +# scale down mongo service while we copy its volume +docker service scale "$MONGO_SERVICE"=0 + +# timestamp for filename +TIMESTAMP=$(date +"%Y-%m-%d-%H-%M") + +# backup directory and retention (can be overridden via env) +BACKUP_DIR="${BACKUP_DIR:-backups}" +KEEP="${KEEP:-7}" + +mkdir -p "$BACKUP_DIR" + +BACKUP_FILE="$BACKUP_DIR/mongo-volume-backup-$TIMESTAMP.tar.gz" + +sudo tar -czvpf "$BACKUP_FILE" mongo-volume + +# rotate old backups: keep only the newest $KEEP files +if [ "$KEEP" -gt 0 ]; then + # gather files sorted newest-first + mapfile -t files < <(ls -1t "$BACKUP_DIR"/mongo-volume-backup-*.tar.gz 2>/dev/null || true) + if [ "${#files[@]}" -gt "$KEEP" ]; then + for f in "${files[@]:$KEEP}"; do + echo "Removing old backup: $f" + rm -f -- "$f" + done + fi +fi + +# bring mongo service back up +docker service scale "$MONGO_SERVICE"=1 diff --git a/restore.sh b/restore.sh new file mode 100755 index 0000000..095e711 --- /dev/null +++ b/restore.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Configuration +MONGO_SERVICE="utility-bills-tracker_mongo" + +# Parse command line options +DO_PRE_BACKUP="" + +while [[ $# -gt 0 ]]; do + case $1 in + --do-pre-backup=*) + DO_PRE_BACKUP="${1#*=}" + shift + ;; + *) + TIMESTAMP="$1" + shift + ;; + esac +done + +# Usage: ./restore.sh [options] +# Example: ./restore.sh 2025-08-24-14-30 +# Options: --do-pre-backup=true/false (skip interactive prompt) + +if [ -z "${TIMESTAMP:-}" ]; then + echo "Usage: $0 [options] " + echo "Example: $0 2025-08-24-14-30" + echo "" + echo "Options:" + echo " --do-pre-backup=true Skip interactive prompt, create pre-restore backup" + echo " --do-pre-backup=false Skip interactive prompt, no pre-restore backup" + echo "" + echo "Available backups:" + ls -1t backups/mongo-volume-backup-*.tar.gz 2>/dev/null | sed 's/.*mongo-volume-backup-\(.*\)\.tar\.gz/ \1/' || echo " No backups found" + exit 1 +fi +BACKUP_DIR="${BACKUP_DIR:-backups}" +BACKUP_FILE="$BACKUP_DIR/mongo-volume-backup-$TIMESTAMP.tar.gz" + +# Check if backup file exists +if [ ! -f "$BACKUP_FILE" ]; then + echo "Error: Backup file '$BACKUP_FILE' not found" + echo "" + echo "Available backups:" + ls -1t "$BACKUP_DIR"/mongo-volume-backup-*.tar.gz 2>/dev/null | sed 's/.*mongo-volume-backup-\(.*\)\.tar\.gz/ \1/' || echo " No backups found" + exit 1 +fi + +echo "Restoring from backup: $BACKUP_FILE" +echo "WARNING: This will replace the current mongo-volume data!" +read -p "Are you sure you want to continue? (y/N): " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Restore cancelled" + exit 0 +fi + +# Scale down mongo service +echo "Scaling down mongo service..." +docker service scale "$MONGO_SERVICE"=0 + +# Handle pre-restore backup +CREATE_PRE_BACKUP=true +if [ "$DO_PRE_BACKUP" = "false" ]; then + CREATE_PRE_BACKUP=false +elif [ "$DO_PRE_BACKUP" = "true" ]; then + CREATE_PRE_BACKUP=true +elif [ -z "$DO_PRE_BACKUP" ]; then + # Ask user interactively + read -p "Create pre-restore safety backup? (Y/n): " -n 1 -r + echo + if [[ $REPLY =~ ^[Nn]$ ]]; then + CREATE_PRE_BACKUP=false + fi +else + echo "Error: --do-pre-backup must be 'true' or 'false'" + exit 1 +fi + +# Create pre-restore backup if requested +if [ "$CREATE_PRE_BACKUP" = true ]; then + SAFETY_BACKUP="$BACKUP_DIR/mongo-volume-pre-restore-$(date +%Y-%m-%d-%H-%M).tar.gz" + echo "Creating safety backup: $SAFETY_BACKUP" + sudo tar -czf "$SAFETY_BACKUP" mongo-volume 2>/dev/null || true +else + echo "Skipping pre-restore backup" + SAFETY_BACKUP="" +fi + +# Remove current volume +echo "Removing current mongo-volume..." +sudo rm -rf mongo-volume + +# Extract backup +echo "Extracting backup..." +sudo tar -xzf "$BACKUP_FILE" + +# Set proper permissions +echo "Setting permissions..." +sudo chown -R 999:999 mongo-volume + +# Scale mongo service back up +echo "Scaling mongo service back up..." +docker service scale "$MONGO_SERVICE"=1 + +echo "Restore completed successfully!" +if [ -n "$SAFETY_BACKUP" ]; then + echo "Safety backup saved as: $SAFETY_BACKUP" +fi