702 lines
25 KiB
Bash
Executable File
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 |