#!/usr/bin/env bash # # StemeDB Backup Script # # Creates a timestamped backup of WAL and database files. # # Usage: # ./scripts/backup-stemedb.sh # Default backup to backups/ # ./scripts/backup-stemedb.sh --output /mnt/nfs # Custom output directory # ./scripts/backup-stemedb.sh --wal-only # Backup WAL only (faster) # # Exit codes: # 0 - Backup completed successfully # 1 - Backup failed # set -euo pipefail # Configuration readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly PROJECT_DIR="$(dirname "$SCRIPT_DIR")" readonly WAL_DIR="${STEMEDB_WAL_DIR:-${PROJECT_DIR}/data/wal}" readonly DB_DIR="${STEMEDB_DB_DIR:-${PROJECT_DIR}/data/db}" readonly TIMESTAMP="$(date +%Y%m%d-%H%M%S)" # Colors (if terminal supports it) if [[ -t 1 ]]; then RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' NC='\033[0m' else RED='' GREEN='' YELLOW='' BLUE='' NC='' fi # Logging helpers info() { echo -e "${BLUE}[INFO]${NC} $*"; } success() { echo -e "${GREEN}[OK]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; } # Defaults OUTPUT_DIR="${PROJECT_DIR}/backups" WAL_ONLY=false # Parse arguments while [[ $# -gt 0 ]]; do case $1 in --output) OUTPUT_DIR="$2" shift 2 ;; --wal-only) WAL_ONLY=true shift ;; --help|-h) echo "Usage: $0 [--output ] [--wal-only]" echo "" echo "Create a timestamped backup of StemeDB data." echo "" echo "Options:" echo " --output Output directory (default: backups/)" echo " --wal-only Backup WAL directory only (skip DB)" echo " --help Show this help message" echo "" echo "Environment:" echo " STEMEDB_WAL_DIR WAL directory (default: data/wal)" echo " STEMEDB_DB_DIR Database directory (default: data/db)" exit 0 ;; *) fail "Unknown argument: $1 (use --help for usage)" ;; esac done readonly BACKUP_DIR="${OUTPUT_DIR}/stemedb-backup-${TIMESTAMP}" # Cleanup partial backup on failure cleanup() { local exit_code=$? if [[ $exit_code -ne 0 && -d "$BACKUP_DIR" ]]; then warn "Backup failed, removing partial backup at ${BACKUP_DIR}" rm -rf "$BACKUP_DIR" fi } trap cleanup EXIT main() { echo "" echo "==========================================" echo " StemeDB Backup" echo "==========================================" echo "" # Validate source directories if [[ ! -d "$WAL_DIR" ]]; then fail "WAL directory not found: ${WAL_DIR}" fi if [[ -z "$(ls -A "$WAL_DIR" 2>/dev/null)" ]]; then fail "WAL directory is empty: ${WAL_DIR}" fi if [[ "$WAL_ONLY" == "false" ]]; then if [[ ! -d "$DB_DIR" ]]; then fail "DB directory not found: ${DB_DIR}" fi if [[ -z "$(ls -A "$DB_DIR" 2>/dev/null)" ]]; then fail "DB directory is empty: ${DB_DIR}" fi fi # Create backup directory mkdir -p "$BACKUP_DIR" info "Backup directory: ${BACKUP_DIR}" # Backup WAL (append-only, safe to copy live) info "Copying WAL directory..." rsync -a "${WAL_DIR}/" "${BACKUP_DIR}/wal/" local wal_files wal_files=$(find "${BACKUP_DIR}/wal" -type f | wc -l) local wal_size wal_size=$(du -sh "${BACKUP_DIR}/wal" | cut -f1) success "WAL: ${wal_files} files, ${wal_size}" # Backup DB (unless --wal-only) local db_files=0 local db_size="0" if [[ "$WAL_ONLY" == "false" ]]; then info "Copying DB directory..." rsync -a "${DB_DIR}/" "${BACKUP_DIR}/db/" db_files=$(find "${BACKUP_DIR}/db" -type f | wc -l) db_size=$(du -sh "${BACKUP_DIR}/db" | cut -f1) success "DB: ${db_files} files, ${db_size}" else info "Skipping DB (--wal-only)" fi # Compute total size local total_size total_size=$(du -sh "$BACKUP_DIR" | cut -f1) # Write metadata cat > "${BACKUP_DIR}/backup-metadata.json" </dev/null | grep -o '"stemedb-api","version":"[^"]*"' | head -1 | cut -d'"' -f6 || echo "unknown")" } METADATA success "Metadata written" # Summary echo "" echo "==========================================" echo -e " ${GREEN}Backup complete${NC}" echo "==========================================" echo "" echo " Location: ${BACKUP_DIR}" echo " WAL files: ${wal_files} (${wal_size})" if [[ "$WAL_ONLY" == "false" ]]; then echo " DB files: ${db_files} (${db_size})" fi echo " Total: ${total_size}" echo "" echo "Restore with:" echo " ./scripts/restore-stemedb.sh ${BACKUP_DIR}" echo "" } main "$@"