From a36be25ae948b2e254130527ba6d4016f3af7acf Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 8 Jan 2025 00:46:12 +0800 Subject: [PATCH] Ver 1.7 Improved restoration script, Automatic Backup Tagging, Resolved issues with incorrect handling of database restoration paths --- changelogs.md | 45 +++++ manifest.jps | 21 ++- scripts/imports/backup_all.sh | 42 ++++- scripts/imports/manage_backup_schedule.sh | 133 +++++++------- scripts/imports/restore_backup_direct.sh | 208 +++++++++++++--------- 5 files changed, 292 insertions(+), 157 deletions(-) diff --git a/changelogs.md b/changelogs.md index b07ca1a..7722b5e 100644 --- a/changelogs.md +++ b/changelogs.md @@ -1,5 +1,50 @@ # Changelog +## Version 1.7 + +### Added +- **`restore_backup_direct.sh` Enhancements**: + - Improved restoration script to handle specific backup types (core files, media files, database backups) based on tags. + - Integrated functionality to restore databases directly by piping `.sql` files from Restic to MySQL. + - Added automatic detection of database credentials from `wp-config.php` with fallback to default values for `DB_HOST`. + - Ensured proper environment setup with `RESTIC_PASSWORD` retrieved securely from `/etc/restic-password`. + +- **Automatic Backup Tagging**: + - Modified `backup_all.sh` to differentiate between manual (`manual-backup-YYYY-MM-DD_HH-MM-SS`) and automated (`auto-backup-YYYY-MM-DD_HH-MM-SS`) backups. + - Ensured backups triggered by cron jobs are tagged appropriately for easy identification. + +- **`manage_backup_schedule.sh` Enhancements**: + - Ensured `backup_all.sh` runs in `auto` mode when added to cron, guaranteeing automated backups have the correct tags. + - Validated cron job syntax and dependencies to avoid misconfigurations. + - Added explicit logging of cron actions, including schedule additions, updates, removals, and listing. + +- **Improved Error Messaging**: + - Enhanced restoration script to provide detailed error messages when database restoration fails, including incorrect credentials or insufficient privileges. + +### Fixed +- Resolved issues with incorrect handling of database restoration paths, ensuring `.sql` files are restored directly into MySQL when detected. +- Addressed potential confusion in tagging by clearly segregating manual and automated backups in logs and tags. +- Corrected empty `DB_HOST` values in the restoration script by setting a default to `localhost` when no value is provided in `wp-config.php`. + +### Updated +- **Logging and Traceability**: + - Enhanced all relevant scripts (`restore_backup_direct.sh`, `backup_all.sh`, `manage_backup_schedule.sh`) to log detailed timestamps and descriptive messages. + - Improved consistency in log formatting across scripts for better traceability. + - Added detailed logs for all cron operations in `manage_backup_schedule.sh` to track automated backups effectively. + +### Improved +- **Backup and Restore Modularity**: + - Streamlined the orchestration of backups and restores to ensure modularity and easier debugging. + - Improved robustness of `restore_backup_direct.sh` by handling different backup types dynamically using snapshot tags. + - Simplified management of cron schedules with better error handling and validation in `manage_backup_schedule.sh`. + +- **Error Handling**: + - Ensured all scripts exit gracefully on errors with detailed logs to pinpoint issues. + - Enhanced dependency validation to check for all required tools (`restic`, `mysql`, `jq`, `crontab`, etc.) before execution. + +- **Code Maintenance**: + - Centralized key operations such as password retrieval, lock handling, and backup tagging across scripts for easier maintenance and fewer redundancies. + ## Version 1.6 ### Added diff --git a/manifest.jps b/manifest.jps index 2e2f830..2bd3497 100644 --- a/manifest.jps +++ b/manifest.jps @@ -1,5 +1,5 @@ type: update -jpsVersion: 1.6 +jpsVersion: 1.7 name: MightyBox WordPress Backup/Restore Addon id: mb-backup-manager description: Custom Backup and Restore Addon for WordPress using Restic. Supports backing up databases, core files, media files, and full backups with scheduling and retention policies. @@ -52,6 +52,12 @@ menu: title: Configure Automated Backup Schedule submitButtonText: Save Schedule + - caption: List Scheduled Backups + action: listScheduledBackups + confirmText: List scheduled backups? + loadingText: Listing scheduled backups... + successText: Scheduled backups listed successfully + - caption: Remove Auto Backup action: removeAutoBackup confirmText: Remove automated backup schedule? @@ -160,6 +166,14 @@ actions: type: info message: "Daily backup schedule configured successfully" + listScheduledBackups: + - cmd[cp]: + user: root + commands: bash /home/litespeed/mb-backups/manage_backup_schedule.sh list + - return: + type: info + message: "${response.out}" + removeAutoBackup: - cmd[cp]: user: root @@ -179,7 +193,7 @@ actions: backupnow: - cmd[cp]: user: root - commands: bash /home/jelastic/mb-backups/backup_all.sh backup_now + commands: bash /home/jelastic/mb-backups/backup_all.sh manual - return: type: info message: "${response.out}" @@ -332,7 +346,8 @@ actions: - mkdir -p /home/litespeed/mb-backups/logs/auto - mkdir -p /home/litespeed/mb-backups/logs/manual - mkdir -p /home/litespeed/mb-backups/logs/restore - - chown -R litespeed:litespeed /home/litespeed/mb-backups + - sudo chown -R litespeed:litespeed /home/litespeed/mb-backups/logs + - sudo chmod -R u+rw /home/litespeed/mb-backups/logs - cd /home/jelastic/mb-backups - curl -O https://deploy-proxy.mightybox.io/addons/mb-backup-manager/raw/branch/main/scripts/imports/backup_all.sh - curl -O https://deploy-proxy.mightybox.io/addons/mb-backup-manager/raw/branch/main/scripts/imports/backup_core_files.sh diff --git a/scripts/imports/backup_all.sh b/scripts/imports/backup_all.sh index 4c44202..f5d003b 100644 --- a/scripts/imports/backup_all.sh +++ b/scripts/imports/backup_all.sh @@ -9,7 +9,7 @@ LOG_DIR="/home/jelastic/mb-backups/logs" CORE_BACKUP_SCRIPT="/home/jelastic/mb-backups/backup_core_files.sh" DATABASE_BACKUP_SCRIPT="/home/jelastic/mb-backups/backup_database.sh" MEDIA_BACKUP_SCRIPT="/home/jelastic/mb-backups/backup_media.sh" -MANUAL_BACKUP_TAG="manual-backup-$(date +'%Y-%m-%d_%H-%M-%S')" +TIMESTAMP=$(date +'%Y-%m-%d_%H-%M-%S') # Ensure log directory exists mkdir -p "$LOG_DIR" @@ -22,24 +22,37 @@ log_message() { # Main execution main() { - log_message "Starting full backup process with tag: $MANUAL_BACKUP_TAG" + local backup_type="$1" + local backup_tag="" + + # Determine the backup tag based on the type + if [ "$backup_type" == "manual" ]; then + backup_tag="manual-backup-$TIMESTAMP" + log_message "Starting manual backup process with tag: $backup_tag" + elif [ "$backup_type" == "auto" ]; then + backup_tag="automated-backup-$TIMESTAMP" + log_message "Starting automated backup process with tag: $backup_tag" + else + log_message "ERROR: Invalid backup type. Use 'manual' or 'auto'." + exit 1 + fi # Run individual backup scripts - if bash "$CORE_BACKUP_SCRIPT" "$(cat /etc/restic-password)" "$MANUAL_BACKUP_TAG"; then + if bash "$CORE_BACKUP_SCRIPT" "$(cat /etc/restic-password)" "$backup_tag"; then log_message "Core files backup completed successfully." else log_message "ERROR: Core files backup failed." exit 1 fi - if bash "$DATABASE_BACKUP_SCRIPT" "$(cat /etc/restic-password)" "$MANUAL_BACKUP_TAG"; then + if bash "$DATABASE_BACKUP_SCRIPT" "$(cat /etc/restic-password)" "$backup_tag"; then log_message "Database backup completed successfully." else log_message "ERROR: Database backup failed." exit 1 fi - if bash "$MEDIA_BACKUP_SCRIPT" "$(cat /etc/restic-password)" "$MANUAL_BACKUP_TAG"; then + if bash "$MEDIA_BACKUP_SCRIPT" "$(cat /etc/restic-password)" "$backup_tag"; then log_message "Media files backup completed successfully." else log_message "ERROR: Media files backup failed." @@ -50,9 +63,20 @@ main() { } # Argument handling -if [ "$1" == "backup_now" ]; then - main -else - echo "Usage: $0 backup_now" +if [ "$#" -ne 1 ]; then + echo "Usage: $0 {manual|auto}" exit 1 fi + +case "$1" in + manual) + main "manual" + ;; + auto) + main "auto" + ;; + *) + echo "Usage: $0 {manual|auto}" + exit 1 + ;; +esac diff --git a/scripts/imports/manage_backup_schedule.sh b/scripts/imports/manage_backup_schedule.sh index 990f73d..938876d 100644 --- a/scripts/imports/manage_backup_schedule.sh +++ b/scripts/imports/manage_backup_schedule.sh @@ -5,44 +5,53 @@ BACKUP_SCRIPT="/home/litespeed/mb-backups/backup_all.sh" LOG_DIR="/home/litespeed/mb-backups/logs/auto" ACTION_LOG_FILE="${LOG_DIR}/schedule_actions.log" BACKUP_LOG_PREFIX="${LOG_DIR}/backup_" +CRON_FILE="/var/spool/cron/crontabs/$(whoami)" +CRON_PATH="/usr/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # Ensure the log directory exists mkdir -p "$LOG_DIR" +# Logging function log_action() { - echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >> "$ACTION_LOG_FILE" + echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$ACTION_LOG_FILE" } +# Function: Validate dependencies +validate_dependencies() { + for cmd in dnf crontab systemctl restic; do + if ! command -v "$cmd" &>/dev/null; then + log_action "ERROR: Required command '$cmd' not found." + exit 1 + fi + done +} + +# Function: Install and start cron service if needed check_and_install_cron() { - if ! command -v crontab &> /dev/null; then - echo "Cron is not installed. Installing..." - sudo dnf install -y cronie || { echo "Failed to install cron."; exit 1; } + if ! command -v crontab &>/dev/null; then + log_action "Cron is not installed. Installing..." + sudo dnf install -y cronie || { log_action "Failed to install cron."; exit 1; } fi if ! systemctl is-active --quiet crond; then - echo "Starting cron service..." + log_action "Starting cron service..." sudo systemctl start crond - sudo systemctl enable crond + sudo systemctl enable crond || { log_action "Failed to enable cron service."; exit 1; } fi - if systemctl is-active --quiet crond; then - echo "Cron service is running." - else - echo "Failed to start cron service." - log_action "Failed to start cron service." - exit 1 - fi + log_action "Cron service is running and ready." } +# Function: Validate cron schedule format validate_cron_syntax() { local schedule="$1" if ! echo "$schedule" | grep -Eq '^(\*|[0-9]|[0-5][0-9]) (\*|[0-9]|1[0-9]|2[0-3]) (\*|[0-9]|3[0-1]) (\*|[1-9]|1[0-2]) (\*|[0-6])$'; then - echo "Invalid cron schedule format: $schedule" - log_action "Invalid cron schedule format: $schedule" + log_action "ERROR: Invalid cron schedule format: $schedule" exit 1 fi } +# Function: Add or update a cron job add_update_cron_job() { local action="$1" local schedule="$2" @@ -51,66 +60,66 @@ add_update_cron_job() { validate_cron_syntax "$schedule" if [ -z "$restic_password" ]; then - echo "Restic password is required." - log_action "Attempted to $action a schedule without providing a Restic password." - exit 1 - fi - - local restic_path="/usr/local/bin/restic" - if [ ! -x "$restic_path" ]; then - echo "Error: restic not found at $restic_path. Please verify installation." - log_action "restic not found at $restic_path" + log_action "ERROR: Restic password is required." exit 1 fi # Prepare the cron job command - local cmd="SHELL=/bin/bash" - cmd+=" PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - cmd+=" RESTIC_PASSWORD=\"$restic_password\"" - cmd+=" $BACKUP_SCRIPT" + local cmd="SHELL=/bin/bash PATH=$CRON_PATH RESTIC_PASSWORD=\"$restic_password\"" + cmd+=" $BACKUP_SCRIPT auto" cmd+=" > \"${BACKUP_LOG_PREFIX}\$(date +\\%Y-\\%m-\\%d_\\%H-\\%M-\\%S).log\" 2>&1" - # Debug: Output the command to verify - echo "Adding the following cron job:" - echo "$schedule $cmd" - - # Remove any existing lines containing $BACKUP_SCRIPT, then add the new one + # Remove existing job and add a new one (crontab -l 2>/dev/null | grep -v "$BACKUP_SCRIPT"; echo "$schedule $cmd") | crontab - - if crontab -l | grep -q "$BACKUP_SCRIPT"; then - echo "Cron job $action successfully." + if crontab -l | grep -q "$BACKUP_SCRIPT auto"; then log_action "Cron job $action successfully: $schedule" else - echo "Failed to $action cron job. Please check logs for details." - log_action "Failed to $action cron job: $schedule" + log_action "ERROR: Failed to $action cron job. Please check logs." exit 1 fi } -# Main execution -check_and_install_cron +# Function: Remove cron jobs +remove_cron_jobs() { + crontab -l 2>/dev/null | grep -v "$BACKUP_SCRIPT auto" | crontab - + log_action "All backup schedules removed." +} -case $1 in - add|update) - if [ "$#" -ne 3 ]; then - echo "Usage for add/update: $0 {add|update} 'schedule' 'restic_password'" - log_action "Incorrect usage for $1. Format not followed." +# Function: List cron jobs +list_cron_jobs() { + log_action "Listing all current cron jobs:" + crontab -l 2>/dev/null | tee -a "$ACTION_LOG_FILE" +} + +# Main execution +main() { + validate_dependencies + check_and_install_cron + + case "$1" in + add|update) + if [ "$#" -ne 3 ]; then + echo "Usage for add/update: $0 {add|update} 'schedule' 'restic_password'" + log_action "Incorrect usage for $1. Format not followed." + exit 1 + else + add_update_cron_job "$1" "$2" "$3" + fi + ;; + remove) + remove_cron_jobs + ;; + list) + list_cron_jobs + ;; + *) + echo "Usage: $0 {add|update|remove|list} [schedule] [restic_password]" + log_action "Invalid action attempted: $1" exit 1 - else - add_update_cron_job "$1" "$2" "$3" - fi - ;; - remove) - tmp_cron=$(mktemp) - crontab -l 2>/dev/null | grep -v "$BACKUP_SCRIPT" > "$tmp_cron" - crontab "$tmp_cron" - rm -f "$tmp_cron" - echo "All backup schedules removed." - log_action "All backup schedules removed." - ;; - *) - echo "Invalid action: $1. Use add, update, or remove." - log_action "Invalid action attempted: $1" - exit 1 - ;; -esac + ;; + esac +} + +# Execute main function +main "$@" diff --git a/scripts/imports/restore_backup_direct.sh b/scripts/imports/restore_backup_direct.sh index 2c2ea26..8adbd71 100644 --- a/scripts/imports/restore_backup_direct.sh +++ b/scripts/imports/restore_backup_direct.sh @@ -1,23 +1,23 @@ #!/bin/bash -# Exit immediately on errors +# Exit on errors and enable error tracing set -e +trap 'log "ERROR: An error occurred during the restoration process."' ERR # Validate input parameters -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " exit 1 fi # Assign input to variables SNAPSHOT_ID=$1 -RESTIC_PASSWORD=$2 +RESTIC_PASSWORD_FILE="/etc/restic-password" RESTIC_REPOSITORY="/mnt/backups" LOG_DIR="/home/litespeed/mb-backups/logs/restore" WP_CONFIG="/var/www/webroot/ROOT/wp-config.php" -# Set up the environment -export RESTIC_PASSWORD +# Ensure the log directory exists mkdir -p "$LOG_DIR" LOG_FILE="${LOG_DIR}/restore_$(date +'%Y-%m-%d_%H-%M-%S').log" @@ -26,95 +26,137 @@ log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } -# Check for required dependencies -for cmd in restic jq mysql; do - if ! command -v $cmd >/dev/null 2>&1; then - log "Error: '$cmd' command not found. Please install $cmd." +# Validate required dependencies +validate_dependencies() { + for cmd in restic jq mysql; do + if ! command -v $cmd >/dev/null 2>&1; then + log "ERROR: '$cmd' command not found. Please install $cmd." + exit 1 + fi + done +} + +# Set up Restic environment +setup_restic_environment() { + if [ ! -f "$RESTIC_PASSWORD_FILE" ]; then + log "ERROR: Restic password file not found at $RESTIC_PASSWORD_FILE." exit 1 fi -done -# Ensure there are no stale locks in the repository -log "Checking for stale locks in the repository..." -if restic -r "$RESTIC_REPOSITORY" list locks | grep -q "lock"; then - log "Stale lock detected. Unlocking repository..." - restic -r "$RESTIC_REPOSITORY" unlock - log "Repository unlocked successfully." -else - log "No stale locks found. Proceeding with restoration." -fi + export RESTIC_PASSWORD=$(cat "$RESTIC_PASSWORD_FILE") + export RESTIC_REPOSITORY="$RESTIC_REPOSITORY" + log "Restic environment set up successfully." +} + +# Ensure no stale locks exist in the repository +remove_stale_locks() { + log "Checking for stale locks in the repository..." + if restic list locks | grep -q "lock"; then + log "Stale lock detected. Unlocking repository..." + restic unlock || { + log "ERROR: Failed to remove stale locks." + exit 1 + } + log "Repository unlocked successfully." + else + log "No stale locks found. Proceeding with restoration." + fi +} # Extract database credentials from wp-config.php -if [ ! -f "$WP_CONFIG" ]; then - log "Error: wp-config.php not found at $WP_CONFIG. Ensure WordPress is installed." - exit 1 -fi - -DB_NAME=$(awk -F"'" '/define\( *'"'"'DB_NAME'"'"'/{print $4}' "$WP_CONFIG") -DB_USER=$(awk -F"'" '/define\( *'"'"'DB_USER'"'"'/{print $4}' "$WP_CONFIG") -DB_PASSWORD=$(awk -F"'" '/define\( *'"'"'DB_PASSWORD'"'"'/{print $4}' "$WP_CONFIG") - -if [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then - log "Error: Could not extract database credentials from wp-config.php." - exit 1 -fi - -log "Starting restoration for snapshot ID: $SNAPSHOT_ID..." - -# Retrieve snapshot data -SNAPSHOT_DATA=$(restic -r "$RESTIC_REPOSITORY" snapshots --json | jq -r ".[] | select(.short_id == \"$SNAPSHOT_ID\")") -if [ -z "$SNAPSHOT_DATA" ]; then - log "Error: Snapshot ID $SNAPSHOT_ID not found in repository." - exit 1 -fi - -SNAPSHOT_PATH=$(echo "$SNAPSHOT_DATA" | jq -r ".paths[] // empty") -SNAPSHOT_TAGS=$(echo "$SNAPSHOT_DATA" | jq -r ".tags[] // empty") - -if [ -z "$SNAPSHOT_PATH" ]; then - log "Error: Snapshot $SNAPSHOT_ID does not contain valid paths." - exit 1 -fi - -log "Snapshot Data Retrieved: Path=$SNAPSHOT_PATH, Tags=$SNAPSHOT_TAGS" - -# Determine the restoration type based on the tags -if [[ "$SNAPSHOT_TAGS" == *"wordpress_db"* ]] && [[ "$SNAPSHOT_PATH" == "/stdin" ]]; then - log "Detected database backup. Restoring database $DB_NAME..." - if restic -r "$RESTIC_REPOSITORY" dump "$SNAPSHOT_ID" stdin | mysql -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME"; then - log "Database restoration completed successfully for $DB_NAME from Snapshot ID: $SNAPSHOT_ID." - else - log "Error: Database restoration failed for Snapshot ID: $SNAPSHOT_ID." +extract_db_credentials() { + if [ ! -f "$WP_CONFIG" ]; then + log "ERROR: wp-config.php not found at $WP_CONFIG. Ensure WordPress is installed." exit 1 fi -elif [[ "$SNAPSHOT_TAGS" == *"core_files"* ]]; then - RESTORE_DIR="/var/www/webroot/ROOT" - log "Detected core files backup. Restoring to $RESTORE_DIR..." - if restic -r "$RESTIC_REPOSITORY" restore "$SNAPSHOT_ID" --target "$RESTORE_DIR"; then - log "Core files restoration completed successfully for Snapshot ID: $SNAPSHOT_ID." - else - log "Error: Core files restoration failed for Snapshot ID: $SNAPSHOT_ID." + + DB_NAME=$(awk -F"'" '/define\( *'"'"'DB_NAME'"'"'/{print $4}' "$WP_CONFIG") + DB_USER=$(awk -F"'" '/define\( *'"'"'DB_USER'"'"'/{print $4}' "$WP_CONFIG") + DB_PASSWORD=$(awk -F"'" '/define\( *'"'"'DB_PASSWORD'"'"'/{print $4}' "$WP_CONFIG") + DB_HOST=$(awk -F"'" '/define\( *'"'"'DB_HOST'"'"'/{print $4}' "$WP_CONFIG") + + # Set default DB_HOST if empty + if [ -z "$DB_HOST" ]; then + DB_HOST="localhost" + fi + + if [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then + log "ERROR: Could not extract database credentials from wp-config.php." exit 1 fi -elif [[ "$SNAPSHOT_TAGS" == *"media_themes"* ]]; then - RESTORE_DIR="/var/www/webroot/ROOT/wp-content/uploads" - log "Detected media files backup. Restoring to $RESTORE_DIR..." - if restic -r "$RESTIC_REPOSITORY" restore "$SNAPSHOT_ID" --target "$RESTORE_DIR"; then - log "Media files restoration completed successfully for Snapshot ID: $SNAPSHOT_ID." - else - log "Error: Media files restoration failed for Snapshot ID: $SNAPSHOT_ID." +} + +# Retrieve snapshot metadata +retrieve_snapshot_metadata() { + log "Retrieving metadata for snapshot ID: $SNAPSHOT_ID..." + SNAPSHOT_DATA=$(restic snapshots --json | jq -r ".[] | select(.short_id == \"$SNAPSHOT_ID\")") + + if [ -z "$SNAPSHOT_DATA" ]; then + log "ERROR: Snapshot ID $SNAPSHOT_ID not found in the repository." exit 1 fi -else - log "Unknown snapshot type. Attempting general restoration to /..." - TEMP_RESTORE_DIR="/tmp/restoration_$SNAPSHOT_ID" - mkdir -p "$TEMP_RESTORE_DIR" - if restic -r "$RESTIC_REPOSITORY" restore "$SNAPSHOT_ID" --target "$TEMP_RESTORE_DIR"; then - log "General file restoration completed successfully to temporary directory: $TEMP_RESTORE_DIR." - else - log "Error: File restoration failed for Snapshot ID: $SNAPSHOT_ID." + + SNAPSHOT_PATH=$(echo "$SNAPSHOT_DATA" | jq -r ".paths[] // empty") + SNAPSHOT_TAGS=$(echo "$SNAPSHOT_DATA" | jq -r ".tags[] // empty") + + if [ -z "$SNAPSHOT_PATH" ]; then + log "ERROR: Snapshot $SNAPSHOT_ID does not contain valid paths." exit 1 fi -fi + + log "Snapshot metadata retrieved: Path=$SNAPSHOT_PATH, Tags=$SNAPSHOT_TAGS" +} + +# Perform the restoration based on snapshot tags +restore_snapshot() { + if [[ "$SNAPSHOT_TAGS" == *"wordpress_db"* ]] && [[ "$SNAPSHOT_PATH" == *".sql"* ]]; then + log "Detected database backup. Restoring database $DB_NAME..." + log "Using DB credentials: User=$DB_USER, Host=$DB_HOST, DB=$DB_NAME" + + if restic dump "$SNAPSHOT_ID" "$SNAPSHOT_PATH" | mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME"; then + log "Database restoration completed successfully for $DB_NAME." + else + log "ERROR: Database restoration failed. Verify MySQL credentials or permissions." + log "Check that 'DB_USER=$DB_USER' has necessary privileges on 'DB_NAME=$DB_NAME'." + exit 1 + fi + elif [[ "$SNAPSHOT_TAGS" == *"core_files"* ]]; then + RESTORE_DIR="/var/www/webroot/ROOT" + log "Detected core files backup. Restoring to $RESTORE_DIR..." + if restic restore "$SNAPSHOT_ID" --target "$RESTORE_DIR"; then + log "Core files restoration completed successfully." + else + log "ERROR: Core files restoration failed." + exit 1 + fi + elif [[ "$SNAPSHOT_TAGS" == *"media_themes"* ]]; then + RESTORE_DIR="/var/www/webroot/ROOT/wp-content/uploads" + log "Detected media files backup. Restoring to $RESTORE_DIR..." + if restic restore "$SNAPSHOT_ID" --target "$RESTORE_DIR"; then + log "Media files restoration completed successfully." + else + log "ERROR: Media files restoration failed." + exit 1 + fi + else + log "Unknown snapshot type. Attempting general restoration to a temporary directory..." + TEMP_RESTORE_DIR="/tmp/restoration_$SNAPSHOT_ID" + mkdir -p "$TEMP_RESTORE_DIR" + if restic restore "$SNAPSHOT_ID" --target "$TEMP_RESTORE_DIR"; then + log "General restoration completed successfully to $TEMP_RESTORE_DIR." + else + log "ERROR: General restoration failed." + exit 1 + fi + fi +} + +# Main execution flow +validate_dependencies +setup_restic_environment +remove_stale_locks +extract_db_credentials +retrieve_snapshot_metadata +restore_snapshot log "Restoration process completed successfully."