324 lines
9.5 KiB
Bash
Executable File
324 lines
9.5 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Laravel Timebank Master Backup Script
|
|
# Orchestrates database and storage backups with health checks
|
|
# Usage: ./backup-all.sh [backup_type] [options]
|
|
# backup_type: daily (default), weekly, monthly
|
|
# options: --storage-only, --database-only, --verify, --notify
|
|
|
|
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"
|
|
HEALTH_CHECK_FILE="$BACKUP_ROOT_DIR/health_check.json"
|
|
|
|
# Create backup directories
|
|
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 with colors
|
|
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 -e "${timestamp} $level $message" | tee -a "$LOG_FILE"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Function to show usage
|
|
show_usage() {
|
|
echo "Usage: $0 [backup_type] [options]"
|
|
echo ""
|
|
echo "Backup Types:"
|
|
echo " daily - Daily backup (default)"
|
|
echo " weekly - Weekly backup"
|
|
echo " monthly - Monthly backup"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --storage-only - Backup only storage files"
|
|
echo " --database-only - Backup only database"
|
|
echo " --verify - Verify backups after creation"
|
|
echo " --notify - Send notification on completion"
|
|
echo " --help - Show this help message"
|
|
echo ""
|
|
exit 0
|
|
}
|
|
|
|
# Health check function
|
|
health_check() {
|
|
log "INFO" "Starting backup health check"
|
|
|
|
local status="healthy"
|
|
local issues=()
|
|
|
|
# Check disk space (warn if less than 1GB free)
|
|
local available_space=$(df "$BACKUP_ROOT_DIR" | awk 'NR==2 {print $4}')
|
|
local available_mb=$((available_space / 1024))
|
|
|
|
if [ "$available_mb" -lt 1024 ]; then
|
|
status="warning"
|
|
issues+=("Low disk space: ${available_mb}MB available")
|
|
fi
|
|
|
|
# Check if backup scripts exist and are executable
|
|
for script in "backup-database.sh" "backup-storage.sh"; do
|
|
if [ ! -x "$SCRIPT_DIR/$script" ]; then
|
|
status="error"
|
|
issues+=("Script not found or not executable: $script")
|
|
fi
|
|
done
|
|
|
|
# Check environment file
|
|
if [ ! -f "$PROJECT_ROOT/.env" ]; then
|
|
status="error"
|
|
issues+=("Environment file (.env) not found")
|
|
fi
|
|
|
|
# Generate health check report
|
|
cat > "$HEALTH_CHECK_FILE" <<EOF
|
|
{
|
|
"timestamp": "$(date -Iseconds)",
|
|
"status": "$status",
|
|
"available_space_mb": $available_mb,
|
|
"issues": [$(printf '"%s",' "${issues[@]}" | sed 's/,$//')],
|
|
"backup_directory": "$BACKUP_ROOT_DIR",
|
|
"last_check": "$(date)"
|
|
}
|
|
EOF
|
|
|
|
if [ "$status" = "error" ]; then
|
|
log "ERROR" "Health check failed. Issues found:"
|
|
for issue in "${issues[@]}"; do
|
|
log "ERROR" " - $issue"
|
|
done
|
|
return 1
|
|
elif [ "$status" = "warning" ]; then
|
|
log "WARNING" "Health check completed with warnings:"
|
|
for issue in "${issues[@]}"; do
|
|
log "WARNING" " - $issue"
|
|
done
|
|
else
|
|
log "SUCCESS" "Health check passed"
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Backup verification function
|
|
verify_backups() {
|
|
log "INFO" "Verifying recent backups"
|
|
|
|
local verification_passed=true
|
|
|
|
# Verify database backups
|
|
local latest_db_backup=$(find "$BACKUP_ROOT_DIR/database" -name "*.sql.gz" -type f -mtime -1 | head -n 1)
|
|
if [ -n "$latest_db_backup" ]; then
|
|
if gzip -t "$latest_db_backup" 2>/dev/null; then
|
|
log "SUCCESS" "Database backup verified: $(basename "$latest_db_backup")"
|
|
else
|
|
log "ERROR" "Database backup verification failed: $(basename "$latest_db_backup")"
|
|
verification_passed=false
|
|
fi
|
|
else
|
|
log "WARNING" "No recent database backup found"
|
|
fi
|
|
|
|
# Verify storage backups
|
|
local latest_storage_backup=$(find "$BACKUP_ROOT_DIR/storage" -name "*.tar.gz" -type f -mtime -1 | head -n 1)
|
|
if [ -n "$latest_storage_backup" ]; then
|
|
if tar -tzf "$latest_storage_backup" >/dev/null 2>&1; then
|
|
log "SUCCESS" "Storage backup verified: $(basename "$latest_storage_backup")"
|
|
else
|
|
log "ERROR" "Storage backup verification failed: $(basename "$latest_storage_backup")"
|
|
verification_passed=false
|
|
fi
|
|
else
|
|
log "WARNING" "No recent storage backup found"
|
|
fi
|
|
|
|
return $verification_passed
|
|
}
|
|
|
|
# Notification function
|
|
send_notification() {
|
|
local subject="$1"
|
|
local message="$2"
|
|
local status="$3"
|
|
|
|
# Try multiple notification methods
|
|
|
|
# Method 1: Email (if mail is available and configured)
|
|
if command -v mail >/dev/null 2>&1; then
|
|
echo "$message" | mail -s "$subject" "${BACKUP_NOTIFY_EMAIL:-$USER@localhost}" 2>/dev/null || true
|
|
fi
|
|
|
|
# Method 2: System notification (if notify-send is available)
|
|
if command -v notify-send >/dev/null 2>&1 && [ -n "$DISPLAY" ]; then
|
|
notify-send "$subject" "$message" 2>/dev/null || true
|
|
fi
|
|
|
|
# Method 3: Webhook (if BACKUP_WEBHOOK_URL is set)
|
|
if [ -n "$BACKUP_WEBHOOK_URL" ] && command -v curl >/dev/null 2>&1; then
|
|
curl -X POST "$BACKUP_WEBHOOK_URL" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"subject\":\"$subject\",\"message\":\"$message\",\"status\":\"$status\"}" \
|
|
2>/dev/null || true
|
|
fi
|
|
|
|
# Method 4: Log file notification marker
|
|
log "INFO" "NOTIFICATION: $subject - $message"
|
|
}
|
|
|
|
# Parse command line arguments
|
|
BACKUP_TYPE="daily"
|
|
STORAGE_ONLY=false
|
|
DATABASE_ONLY=false
|
|
VERIFY=false
|
|
NOTIFY=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
daily|weekly|monthly)
|
|
BACKUP_TYPE="$1"
|
|
shift
|
|
;;
|
|
--storage-only)
|
|
STORAGE_ONLY=true
|
|
shift
|
|
;;
|
|
--database-only)
|
|
DATABASE_ONLY=true
|
|
shift
|
|
;;
|
|
--verify)
|
|
VERIFY=true
|
|
shift
|
|
;;
|
|
--notify)
|
|
NOTIFY=true
|
|
shift
|
|
;;
|
|
--help)
|
|
show_usage
|
|
;;
|
|
*)
|
|
log "ERROR" "Unknown option: $1"
|
|
show_usage
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Main execution
|
|
main() {
|
|
log "INFO" "============================================"
|
|
log "INFO" "Starting Timebank $BACKUP_TYPE backup process"
|
|
log "INFO" "Time: $(date)"
|
|
log "INFO" "============================================"
|
|
|
|
local start_time=$(date +%s)
|
|
local backup_success=true
|
|
local status_message=""
|
|
|
|
# Pre-backup health check
|
|
if ! health_check; then
|
|
log "ERROR" "Health check failed, aborting backup"
|
|
exit 1
|
|
fi
|
|
|
|
# Database backup
|
|
if [ "$STORAGE_ONLY" = false ]; then
|
|
log "INFO" "Starting database backup..."
|
|
if "$SCRIPT_DIR/backup-database.sh" "$BACKUP_TYPE"; then
|
|
log "SUCCESS" "Database backup completed"
|
|
else
|
|
log "ERROR" "Database backup failed"
|
|
backup_success=false
|
|
fi
|
|
fi
|
|
|
|
# Storage backup
|
|
if [ "$DATABASE_ONLY" = false ]; then
|
|
log "INFO" "Starting storage backup..."
|
|
if "$SCRIPT_DIR/backup-storage.sh" "$BACKUP_TYPE"; then
|
|
log "SUCCESS" "Storage backup completed"
|
|
else
|
|
log "ERROR" "Storage backup failed"
|
|
backup_success=false
|
|
fi
|
|
fi
|
|
|
|
# Backup verification
|
|
if [ "$VERIFY" = true ]; then
|
|
if verify_backups; then
|
|
log "SUCCESS" "Backup verification passed"
|
|
else
|
|
log "WARNING" "Backup verification had issues"
|
|
fi
|
|
fi
|
|
|
|
# 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)
|
|
|
|
# Generate final status
|
|
if [ "$backup_success" = true ]; then
|
|
status_message="Backup completed successfully in $execution_time_formatted"
|
|
log "SUCCESS" "$status_message"
|
|
|
|
# Generate backup summary
|
|
log "INFO" "Backup Summary:"
|
|
log "INFO" " - Type: $BACKUP_TYPE"
|
|
log "INFO" " - Duration: $execution_time_formatted"
|
|
log "INFO" " - Location: $BACKUP_ROOT_DIR"
|
|
|
|
if [ "$NOTIFY" = true ]; then
|
|
send_notification "Timebank Backup Success" "$status_message" "success"
|
|
fi
|
|
|
|
else
|
|
status_message="Backup completed with errors in $execution_time_formatted"
|
|
log "ERROR" "$status_message"
|
|
|
|
if [ "$NOTIFY" = true ]; then
|
|
send_notification "Timebank Backup Failed" "$status_message" "error"
|
|
fi
|
|
|
|
exit 1
|
|
fi
|
|
|
|
log "INFO" "============================================"
|
|
log "INFO" "Backup process finished"
|
|
log "INFO" "============================================"
|
|
}
|
|
|
|
# Trap to handle interrupts
|
|
trap 'log "ERROR" "Backup interrupted by user"; exit 1' INT TERM
|
|
|
|
# Run main function
|
|
main "$@" |