Files
timebank-cc-public/scripts/cleanup-backups.sh
Ronald Huynen 2547717edb Initial commit
2026-03-23 21:37:59 +01:00

702 lines
25 KiB
Bash
Executable File

#!/bin/bash
# Laravel Timebank Backup Cleanup Script
# Cleans up old backups based on retention policies and monitors disk usage
# Usage: ./cleanup-backups.sh [options]
# Options: --dry-run, --force, --verbose
set -e # Exit on any error
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
BACKUP_ROOT_DIR="$PROJECT_ROOT/backups"
LOG_FILE="$BACKUP_ROOT_DIR/backup.log"
# Configuration file path
CONFIG_FILE="$SCRIPT_DIR/backup-retention.conf"
# Default retention policies (days) - used as fallback if config file is missing or invalid
DEFAULT_DAILY_RETENTION=7
DEFAULT_WEEKLY_RETENTION=28 # 4 weeks
DEFAULT_MONTHLY_RETENTION=365 # 12 months
DEFAULT_PRE_RESTORE_RETENTION=30
DEFAULT_LOG_RETENTION=30
# Default count limits - used as fallback
DEFAULT_DAILY_COUNT_LIMIT=7
DEFAULT_WEEKLY_COUNT_LIMIT=4
DEFAULT_MONTHLY_COUNT_LIMIT=12
DEFAULT_PRE_RESTORE_COUNT_LIMIT=5
DEFAULT_SNAPSHOT_COUNT_LIMIT=3
# Default disk usage thresholds
DEFAULT_DISK_WARNING_THRESHOLD=85 # Warn at 85% disk usage
DEFAULT_DISK_CRITICAL_THRESHOLD=95 # Force cleanup at 95% disk usage
# Default settings
DEFAULT_EMAIL_NOTIFICATIONS_ENABLED=true
DEFAULT_CLEANUP_MODE="both"
DEFAULT_CLEANUP_EMPTY_DIRS=true
DEFAULT_VERIFY_BEFORE_DELETE=false
# Function to load configuration with validation and fallbacks
load_config() {
# Set defaults first
DAILY_RETENTION=$DEFAULT_DAILY_RETENTION
WEEKLY_RETENTION=$DEFAULT_WEEKLY_RETENTION
MONTHLY_RETENTION=$DEFAULT_MONTHLY_RETENTION
PRE_RESTORE_RETENTION=$DEFAULT_PRE_RESTORE_RETENTION
LOG_RETENTION=$DEFAULT_LOG_RETENTION
DAILY_COUNT_LIMIT=$DEFAULT_DAILY_COUNT_LIMIT
WEEKLY_COUNT_LIMIT=$DEFAULT_WEEKLY_COUNT_LIMIT
MONTHLY_COUNT_LIMIT=$DEFAULT_MONTHLY_COUNT_LIMIT
PRE_RESTORE_COUNT_LIMIT=$DEFAULT_PRE_RESTORE_COUNT_LIMIT
SNAPSHOT_COUNT_LIMIT=$DEFAULT_SNAPSHOT_COUNT_LIMIT
DISK_WARNING_THRESHOLD=$DEFAULT_DISK_WARNING_THRESHOLD
DISK_CRITICAL_THRESHOLD=$DEFAULT_DISK_CRITICAL_THRESHOLD
EMAIL_NOTIFICATIONS_ENABLED=$DEFAULT_EMAIL_NOTIFICATIONS_ENABLED
CLEANUP_MODE=$DEFAULT_CLEANUP_MODE
CLEANUP_EMPTY_DIRS=$DEFAULT_CLEANUP_EMPTY_DIRS
VERIFY_BEFORE_DELETE=$DEFAULT_VERIFY_BEFORE_DELETE
# Load config file if it exists
if [ -f "$CONFIG_FILE" ]; then
log "INFO" "Loading retention configuration from: $CONFIG_FILE"
# Source the config file with error handling
if source "$CONFIG_FILE" 2>/dev/null; then
log "INFO" "Configuration loaded successfully"
# Validate numeric values and reset to defaults if invalid
validate_numeric "DAILY_RETENTION" "$DEFAULT_DAILY_RETENTION" 1 365
validate_numeric "WEEKLY_RETENTION" "$DEFAULT_WEEKLY_RETENTION" 1 730
validate_numeric "MONTHLY_RETENTION" "$DEFAULT_MONTHLY_RETENTION" 1 2555 # ~7 years
validate_numeric "PRE_RESTORE_RETENTION" "$DEFAULT_PRE_RESTORE_RETENTION" 1 365
validate_numeric "LOG_RETENTION" "$DEFAULT_LOG_RETENTION" 1 365
validate_numeric "DAILY_COUNT_LIMIT" "$DEFAULT_DAILY_COUNT_LIMIT" 1 100
validate_numeric "WEEKLY_COUNT_LIMIT" "$DEFAULT_WEEKLY_COUNT_LIMIT" 1 100
validate_numeric "MONTHLY_COUNT_LIMIT" "$DEFAULT_MONTHLY_COUNT_LIMIT" 1 100
validate_numeric "PRE_RESTORE_COUNT_LIMIT" "$DEFAULT_PRE_RESTORE_COUNT_LIMIT" 1 50
validate_numeric "SNAPSHOT_COUNT_LIMIT" "$DEFAULT_SNAPSHOT_COUNT_LIMIT" 1 20
validate_numeric "DISK_WARNING_THRESHOLD" "$DEFAULT_DISK_WARNING_THRESHOLD" 50 99
validate_numeric "DISK_CRITICAL_THRESHOLD" "$DEFAULT_DISK_CRITICAL_THRESHOLD" 60 100
# Ensure critical threshold is higher than warning threshold
if [ $DISK_CRITICAL_THRESHOLD -le $DISK_WARNING_THRESHOLD ]; then
log "WARNING" "Critical threshold ($DISK_CRITICAL_THRESHOLD%) must be higher than warning threshold ($DISK_WARNING_THRESHOLD%). Resetting to defaults."
DISK_WARNING_THRESHOLD=$DEFAULT_DISK_WARNING_THRESHOLD
DISK_CRITICAL_THRESHOLD=$DEFAULT_DISK_CRITICAL_THRESHOLD
fi
# Validate boolean values
validate_boolean "EMAIL_NOTIFICATIONS_ENABLED" "$DEFAULT_EMAIL_NOTIFICATIONS_ENABLED"
validate_boolean "CLEANUP_EMPTY_DIRS" "$DEFAULT_CLEANUP_EMPTY_DIRS"
validate_boolean "VERIFY_BEFORE_DELETE" "$DEFAULT_VERIFY_BEFORE_DELETE"
# Validate cleanup mode
if [[ ! "$CLEANUP_MODE" =~ ^(age_only|count_only|both)$ ]]; then
log "WARNING" "Invalid CLEANUP_MODE: $CLEANUP_MODE. Using default: $DEFAULT_CLEANUP_MODE"
CLEANUP_MODE=$DEFAULT_CLEANUP_MODE
fi
else
log "WARNING" "Error loading config file. Using default values."
fi
else
log "INFO" "Config file not found: $CONFIG_FILE. Using default retention policies."
log "INFO" "Run: cp $CONFIG_FILE.example $CONFIG_FILE to create a customizable config file."
fi
}
# Function to validate numeric configuration values
validate_numeric() {
local var_name="$1"
local default_val="$2"
local min_val="$3"
local max_val="$4"
local current_val
eval "current_val=\$$var_name"
# Check if it's a valid number
if ! [[ "$current_val" =~ ^[0-9]+$ ]]; then
log "WARNING" "Invalid $var_name: '$current_val'. Using default: $default_val"
eval "$var_name=$default_val"
return
fi
# Check range
if [ "$current_val" -lt "$min_val" ] || [ "$current_val" -gt "$max_val" ]; then
log "WARNING" "$var_name ($current_val) out of range ($min_val-$max_val). Using default: $default_val"
eval "$var_name=$default_val"
fi
}
# Function to validate boolean configuration values
validate_boolean() {
local var_name="$1"
local default_val="$2"
local current_val
eval "current_val=\$$var_name"
# Normalize to lowercase
current_val=$(echo "$current_val" | tr '[:upper:]' '[:lower:]')
case "$current_val" in
true|yes|1|on)
eval "$var_name=true"
;;
false|no|0|off)
eval "$var_name=false"
;;
*)
log "WARNING" "Invalid $var_name: '$current_val'. Using default: $default_val"
eval "$var_name=$default_val"
;;
esac
}
# Create log directory
mkdir -p "$BACKUP_ROOT_DIR/logs"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging function
log() {
local level="$1"
local message="$2"
local timestamp="[$(date '+%Y-%m-%d %H:%M:%S')]"
case "$level" in
"INFO")
echo -e "${timestamp} ${BLUE}[INFO]${NC} $message" | tee -a "$LOG_FILE"
;;
"SUCCESS")
echo -e "${timestamp} ${GREEN}[SUCCESS]${NC} $message" | tee -a "$LOG_FILE"
;;
"WARNING")
echo -e "${timestamp} ${YELLOW}[WARNING]${NC} $message" | tee -a "$LOG_FILE"
;;
"ERROR")
echo -e "${timestamp} ${RED}[ERROR]${NC} $message" | tee -a "$LOG_FILE"
;;
*)
echo "$timestamp $message" | tee -a "$LOG_FILE"
;;
esac
}
# Function to send email notifications
send_notification() {
local subject="$1"
local message="$2"
# Check if email notifications are enabled
if [ "$EMAIL_NOTIFICATIONS_ENABLED" != "true" ]; then
log "INFO" "Email notifications disabled in config, skipping: $subject"
return 0
fi
if command -v mail >/dev/null 2>&1; then
echo "$message" | mail -s "$subject" "${BACKUP_NOTIFY_EMAIL:-$USER@localhost}" 2>/dev/null || true
log "INFO" "Email notification sent: $subject"
else
log "WARNING" "Mail command not available, notification not sent"
fi
}
# Function to show usage
show_usage() {
# Load config to show current values
load_config
echo "Usage: $0 [options]"
echo ""
echo "Options:"
echo " --dry-run - Show what would be deleted without actually deleting"
echo " --force - Force cleanup even if disk usage is not critical"
echo " --verbose - Show detailed information"
echo " --help - Show this help message"
echo ""
echo "Current Configuration:"
echo " Config file: $CONFIG_FILE"
if [ -f "$CONFIG_FILE" ]; then
echo " Config status: Loaded"
else
echo " Config status: Using defaults (file not found)"
fi
echo ""
echo "Time-based Retention (days):"
echo " Daily backups: $DAILY_RETENTION days"
echo " Weekly backups: $WEEKLY_RETENTION days"
echo " Monthly backups: $MONTHLY_RETENTION days"
echo " Pre-restore: $PRE_RESTORE_RETENTION days"
echo " Log files: $LOG_RETENTION days"
echo ""
echo "Count-based Retention (keep N most recent):"
echo " Daily backups: $DAILY_COUNT_LIMIT files"
echo " Weekly backups: $WEEKLY_COUNT_LIMIT files"
echo " Monthly backups: $MONTHLY_COUNT_LIMIT files"
echo " Pre-restore: $PRE_RESTORE_COUNT_LIMIT files"
echo " Storage snapshots: $SNAPSHOT_COUNT_LIMIT files"
echo ""
echo "Disk Space Thresholds:"
echo " Warning threshold: $DISK_WARNING_THRESHOLD%"
echo " Critical threshold: $DISK_CRITICAL_THRESHOLD%"
echo ""
echo "Settings:"
echo " Email notifications: $EMAIL_NOTIFICATIONS_ENABLED"
echo " Cleanup mode: $CLEANUP_MODE"
echo " Clean empty dirs: $CLEANUP_EMPTY_DIRS"
echo " Verify before delete: $VERIFY_BEFORE_DELETE"
echo ""
echo "To customize retention policies:"
echo " Edit: $CONFIG_FILE"
echo ""
exit 0
}
# Function to check disk usage
check_disk_usage() {
local backup_dir="$1"
local disk_usage=$(df "$backup_dir" | awk 'NR==2 {print substr($5,1,length($5)-1)}')
echo "$disk_usage"
}
# Function to get human readable size
get_size() {
local path="$1"
if [ -f "$path" ]; then
du -h "$path" | cut -f1
elif [ -d "$path" ]; then
du -sh "$path" | cut -f1
else
echo "0B"
fi
}
# Function to cleanup old backups by age
cleanup_by_age() {
local backup_dir="$1"
local retention_days="$2"
local backup_type="$3"
local pattern="$4"
local dry_run="$5"
if [ ! -d "$backup_dir" ]; then
return 0
fi
log "INFO" "Cleaning up $backup_type backups older than $retention_days days"
local files_found=0
local files_deleted=0
local total_size_deleted=0
# Find files older than retention period
while IFS= read -r -d '' backup_file; do
files_found=$((files_found + 1))
local file_size_kb=$(du -k "$backup_file" | cut -f1)
local file_size_hr=$(get_size "$backup_file")
if [ "$dry_run" = true ]; then
if [ "$VERBOSE" = true ]; then
log "INFO" "Would delete: $(basename "$backup_file") ($file_size_hr)"
fi
else
if [ "$VERBOSE" = true ]; then
log "INFO" "Deleting: $(basename "$backup_file") ($file_size_hr)"
fi
rm "$backup_file"
files_deleted=$((files_deleted + 1))
total_size_deleted=$((total_size_deleted + file_size_kb))
fi
done < <(find "$backup_dir" -name "$pattern" -type f -mtime +$retention_days -print0 2>/dev/null)
if [ $files_found -gt 0 ]; then
local total_size_hr=$(echo "$total_size_deleted" | awk '{printf "%.1fMB", $1/1024}')
if [ "$dry_run" = true ]; then
log "INFO" "$backup_type: Would delete $files_found files ($total_size_hr)"
else
log "SUCCESS" "$backup_type: Deleted $files_deleted files ($total_size_hr)"
fi
else
log "INFO" "$backup_type: No old files to clean up"
fi
return 0
}
# Function to cleanup by count (keep only N most recent)
cleanup_by_count() {
local backup_dir="$1"
local keep_count="$2"
local backup_type="$3"
local pattern="$4"
local dry_run="$5"
if [ ! -d "$backup_dir" ]; then
return 0
fi
log "INFO" "Ensuring only $keep_count most recent $backup_type backups are kept"
local files_to_delete=($(find "$backup_dir" -name "$pattern" -type f | sort -r | tail -n +$((keep_count + 1))))
if [ ${#files_to_delete[@]} -gt 0 ]; then
local total_size_deleted=0
for backup_file in "${files_to_delete[@]}"; do
local file_size_kb=$(du -k "$backup_file" | cut -f1)
local file_size_hr=$(get_size "$backup_file")
if [ "$dry_run" = true ]; then
if [ "$VERBOSE" = true ]; then
log "INFO" "Would delete (count): $(basename "$backup_file") ($file_size_hr)"
fi
else
if [ "$VERBOSE" = true ]; then
log "INFO" "Deleting (count): $(basename "$backup_file") ($file_size_hr)"
fi
rm "$backup_file"
total_size_deleted=$((total_size_deleted + file_size_kb))
fi
done
local total_size_hr=$(echo "$total_size_deleted" | awk '{printf "%.1fMB", $1/1024}')
if [ "$dry_run" = true ]; then
log "INFO" "$backup_type: Would delete ${#files_to_delete[@]} excess files ($total_size_hr)"
else
log "SUCCESS" "$backup_type: Deleted ${#files_to_delete[@]} excess files ($total_size_hr)"
fi
else
log "INFO" "$backup_type: No excess files to clean up"
fi
return 0
}
# Function to clean up empty directories
cleanup_empty_dirs() {
local backup_root="$1"
local dry_run="$2"
log "INFO" "Cleaning up empty directories"
local empty_dirs=($(find "$backup_root" -type d -empty 2>/dev/null))
if [ ${#empty_dirs[@]} -gt 0 ]; then
for empty_dir in "${empty_dirs[@]}"; do
# Skip the root backup directories
if [[ "$empty_dir" =~ (database|storage|logs)$ ]]; then
continue
fi
if [ "$dry_run" = true ]; then
if [ "$VERBOSE" = true ]; then
log "INFO" "Would remove empty directory: $empty_dir"
fi
else
if [ "$VERBOSE" = true ]; then
log "INFO" "Removing empty directory: $empty_dir"
fi
rmdir "$empty_dir" 2>/dev/null || true
fi
done
if [ "$dry_run" = true ]; then
log "INFO" "Would remove ${#empty_dirs[@]} empty directories"
else
log "SUCCESS" "Removed empty directories"
fi
else
log "INFO" "No empty directories to clean up"
fi
}
# Function to generate cleanup report
generate_report() {
local backup_root="$1"
log "INFO" "Backup storage report:"
if [ -d "$backup_root" ]; then
# Database backups
if [ -d "$backup_root/database" ]; then
local db_count=$(find "$backup_root/database" -name "*.sql.gz" | wc -l)
local db_size=$(get_size "$backup_root/database")
log "INFO" " Database backups: $db_count files ($db_size)"
fi
# Storage backups
if [ -d "$backup_root/storage" ]; then
local storage_count=$(find "$backup_root/storage" -name "*.tar.gz" | wc -l)
local storage_size=$(get_size "$backup_root/storage")
log "INFO" " Storage backups: $storage_count files ($storage_size)"
fi
# Total size
local total_size=$(get_size "$backup_root")
log "INFO" " Total backup size: $total_size"
# Disk usage
local disk_usage=$(check_disk_usage "$backup_root")
local available_space=$(df -h "$backup_root" | awk 'NR==2 {print $4}')
log "INFO" " Disk usage: ${disk_usage}% (${available_space} available)"
# Oldest and newest backups
local oldest_backup=$(find "$backup_root" -name "*.gz" -type f -printf '%T@ %p\n' 2>/dev/null | sort -n | head -n 1 | cut -d' ' -f2-)
local newest_backup=$(find "$backup_root" -name "*.gz" -type f -printf '%T@ %p\n' 2>/dev/null | sort -n | tail -n 1 | cut -d' ' -f2-)
if [ -n "$oldest_backup" ]; then
local oldest_date=$(date -r "$oldest_backup" '+%Y-%m-%d %H:%M:%S')
log "INFO" " Oldest backup: $(basename "$oldest_backup") ($oldest_date)"
fi
if [ -n "$newest_backup" ]; then
local newest_date=$(date -r "$newest_backup" '+%Y-%m-%d %H:%M:%S')
log "INFO" " Newest backup: $(basename "$newest_backup") ($newest_date)"
fi
else
log "WARNING" "No backup directory found"
fi
}
# Parse command line arguments
DRY_RUN=false
FORCE=false
VERBOSE=false
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run)
DRY_RUN=true
shift
;;
--force)
FORCE=true
shift
;;
--verbose)
VERBOSE=true
shift
;;
--help)
show_usage
;;
*)
log "ERROR" "Unknown option: $1"
show_usage
;;
esac
done
# Main execution
main() {
# Load configuration before starting
load_config
log "INFO" "============================================"
if [ "$DRY_RUN" = true ]; then
log "INFO" "Starting backup cleanup (DRY RUN)"
else
log "INFO" "Starting backup cleanup"
fi
log "INFO" "Time: $(date)"
log "INFO" "============================================"
local start_time=$(date +%s)
# Check if backup directory exists
if [ ! -d "$BACKUP_ROOT_DIR" ]; then
log "WARNING" "Backup directory not found: $BACKUP_ROOT_DIR"
exit 0
fi
# Check disk usage
local disk_usage=$(check_disk_usage "$BACKUP_ROOT_DIR")
log "INFO" "Current disk usage: ${disk_usage}%"
local should_cleanup=false
if [ $disk_usage -ge $DISK_CRITICAL_THRESHOLD ]; then
log "WARNING" "Disk usage critical (${disk_usage}% >= ${DISK_CRITICAL_THRESHOLD}%), forcing cleanup"
send_notification "Timebank Cleanup Critical - Aggressive Cleanup Started" \
"CRITICAL: Disk usage has reached ${disk_usage}% (>= ${DISK_CRITICAL_THRESHOLD}%)
Aggressive backup cleanup has been automatically triggered to free disk space.
Location: $BACKUP_ROOT_DIR
Current usage: ${disk_usage}%
Critical threshold: ${DISK_CRITICAL_THRESHOLD}%
Time: $(date)
This is an automated cleanup to prevent disk space issues. Please check the system if this occurs frequently."
should_cleanup=true
elif [ $disk_usage -ge $DISK_WARNING_THRESHOLD ]; then
log "WARNING" "Disk usage high (${disk_usage}% >= ${DISK_WARNING_THRESHOLD}%)"
send_notification "Timebank Cleanup Warning - Low Disk Space" \
"WARNING: Disk usage is getting high at ${disk_usage}% (>= ${DISK_WARNING_THRESHOLD}%)
Backup cleanup will be performed to prevent potential disk space issues.
Location: $BACKUP_ROOT_DIR
Current usage: ${disk_usage}%
Warning threshold: ${DISK_WARNING_THRESHOLD}%
Critical threshold: ${DISK_CRITICAL_THRESHOLD}%
Time: $(date)
Please monitor disk usage and consider expanding storage if warnings occur frequently."
should_cleanup=true
elif [ "$FORCE" = true ]; then
log "INFO" "Force cleanup requested"
should_cleanup=true
else
log "INFO" "Disk usage normal, running standard cleanup"
should_cleanup=true
fi
if [ "$should_cleanup" = true ]; then
# Cleanup database backups
if [ -d "$BACKUP_ROOT_DIR/database" ]; then
# Load environment for database name
if [ -f "$PROJECT_ROOT/.env" ]; then
source "$SCRIPT_DIR/load-env.sh"
load_env "$PROJECT_ROOT/.env"
fi
local db_pattern="*.sql.gz"
if [ -n "$DB_DATABASE" ]; then
db_pattern="${DB_DATABASE}_*.sql.gz"
fi
cleanup_by_age "$BACKUP_ROOT_DIR/database/daily" $DAILY_RETENTION "daily database" "$db_pattern" "$DRY_RUN"
cleanup_by_age "$BACKUP_ROOT_DIR/database/weekly" $WEEKLY_RETENTION "weekly database" "$db_pattern" "$DRY_RUN"
cleanup_by_age "$BACKUP_ROOT_DIR/database/monthly" $MONTHLY_RETENTION "monthly database" "$db_pattern" "$DRY_RUN"
cleanup_by_age "$BACKUP_ROOT_DIR/database/pre-restore" $PRE_RESTORE_RETENTION "pre-restore database" "*.sql.gz" "$DRY_RUN"
# Also enforce count limits
cleanup_by_count "$BACKUP_ROOT_DIR/database/daily" $DAILY_COUNT_LIMIT "daily database" "$db_pattern" "$DRY_RUN"
cleanup_by_count "$BACKUP_ROOT_DIR/database/weekly" $WEEKLY_COUNT_LIMIT "weekly database" "$db_pattern" "$DRY_RUN"
cleanup_by_count "$BACKUP_ROOT_DIR/database/monthly" $MONTHLY_COUNT_LIMIT "monthly database" "$db_pattern" "$DRY_RUN"
fi
# Cleanup storage backups
if [ -d "$BACKUP_ROOT_DIR/storage" ]; then
cleanup_by_age "$BACKUP_ROOT_DIR/storage/daily" $DAILY_RETENTION "daily storage" "*.tar.gz" "$DRY_RUN"
cleanup_by_age "$BACKUP_ROOT_DIR/storage/weekly" $WEEKLY_RETENTION "weekly storage" "*.tar.gz" "$DRY_RUN"
cleanup_by_age "$BACKUP_ROOT_DIR/storage/monthly" $MONTHLY_RETENTION "monthly storage" "*.tar.gz" "$DRY_RUN"
cleanup_by_age "$BACKUP_ROOT_DIR/storage/pre-restore" $PRE_RESTORE_RETENTION "pre-restore storage" "*.tar.gz" "$DRY_RUN"
# Count limits for storage
cleanup_by_count "$BACKUP_ROOT_DIR/storage/daily" $DAILY_COUNT_LIMIT "daily storage" "*.tar.gz" "$DRY_RUN"
cleanup_by_count "$BACKUP_ROOT_DIR/storage/weekly" $WEEKLY_COUNT_LIMIT "weekly storage" "*.tar.gz" "$DRY_RUN"
cleanup_by_count "$BACKUP_ROOT_DIR/storage/monthly" $MONTHLY_COUNT_LIMIT "monthly storage" "*.tar.gz" "$DRY_RUN"
# Cleanup old snapshots
cleanup_by_count "$BACKUP_ROOT_DIR/storage/snapshots" $SNAPSHOT_COUNT_LIMIT "storage snapshots" "*" "$DRY_RUN"
fi
# Cleanup empty directories
cleanup_empty_dirs "$BACKUP_ROOT_DIR" "$DRY_RUN"
# Cleanup old log files
if [ -d "$BACKUP_ROOT_DIR/logs" ]; then
cleanup_by_age "$BACKUP_ROOT_DIR/logs" $LOG_RETENTION "log files" "*.log" "$DRY_RUN"
fi
fi
# Generate final report
generate_report "$BACKUP_ROOT_DIR"
# Calculate execution time
local end_time=$(date +%s)
local execution_time=$((end_time - start_time))
local execution_time_formatted=$(date -d@$execution_time -u +%H:%M:%S)
# Send completion summary email if cleanup was triggered by disk space conditions
local final_disk_usage=$(check_disk_usage "$BACKUP_ROOT_DIR")
if [ "$should_cleanup" = true ] && ([ $disk_usage -ge $DISK_WARNING_THRESHOLD ] || [ "$FORCE" = true ]); then
local cleanup_type="Standard"
if [ $disk_usage -ge $DISK_CRITICAL_THRESHOLD ]; then
cleanup_type="Aggressive (Critical)"
elif [ $disk_usage -ge $DISK_WARNING_THRESHOLD ]; then
cleanup_type="Warning Level"
elif [ "$FORCE" = true ]; then
cleanup_type="Manual Force"
fi
# Get backup statistics
local db_count=0
local db_size="0B"
local storage_count=0
local storage_size="0B"
local total_size="Unknown"
if [ -d "$BACKUP_ROOT_DIR/database" ]; then
db_count=$(find "$BACKUP_ROOT_DIR/database" -name "*.sql.gz" 2>/dev/null | wc -l)
db_size=$(get_size "$BACKUP_ROOT_DIR/database")
fi
if [ -d "$BACKUP_ROOT_DIR/storage" ]; then
storage_count=$(find "$BACKUP_ROOT_DIR/storage" -name "*.tar.gz" 2>/dev/null | wc -l)
storage_size=$(get_size "$BACKUP_ROOT_DIR/storage")
fi
if [ -d "$BACKUP_ROOT_DIR" ]; then
total_size=$(get_size "$BACKUP_ROOT_DIR")
fi
local mode_text="cleanup completed"
if [ "$DRY_RUN" = true ]; then
mode_text="cleanup analysis completed (DRY RUN)"
fi
send_notification "Timebank Backup Cleanup Completed" \
"Backup $mode_text successfully.
Cleanup Details:
- Type: $cleanup_type cleanup
- Duration: $execution_time_formatted
- Initial disk usage: ${disk_usage}%
- Final disk usage: ${final_disk_usage}%
Current Backup Status:
- Database backups: $db_count files ($db_size)
- Storage backups: $storage_count files ($storage_size)
- Total backup size: $total_size
Location: $BACKUP_ROOT_DIR
Completed: $(date)
For detailed logs, check: $LOG_FILE"
fi
if [ "$DRY_RUN" = true ]; then
log "SUCCESS" "Backup cleanup analysis completed in $execution_time_formatted"
else
log "SUCCESS" "Backup cleanup completed in $execution_time_formatted"
fi
log "INFO" "============================================"
log "INFO" "Cleanup process finished"
log "INFO" "============================================"
}
# Run main function
main