diff --git a/changelogs.md b/changelogs.md index cc7599d..bda1c33 100644 --- a/changelogs.md +++ b/changelogs.md @@ -1,5 +1,26 @@ # Changelog +## Version 1.5 + +### Added +- Simplified `backup_all.sh` by delegating backup tasks to individual scripts (`backup_core_files.sh`, `backup_database.sh`, `backup_media.sh`). +- Introduced centralized orchestration of all backups in `backup_all.sh` with a unified `manual-backup` tag for consistency. +- Ensured individual scripts can be reused independently or called as part of a larger workflow. + +### Fixed +- Corrected `trap` command in `backup_all.sh` to ensure errors are properly logged to `backup_error.log`. +- Addressed issues with redundant logic in `backup_all.sh` by consolidating common functionality into the individual backup scripts. +- Resolved potential inconsistencies in tag usage by applying a standard `manual-backup` tag with the current server date across all backup scripts. + +### Updated +- Refactored `backup_all.sh` to dynamically call individual backup scripts instead of duplicating logic for core, database, and media backups. +- Adjusted YAML configuration for `backupnow` to call `backup_all.sh` as the primary entry point for the backup process. + +### Improved +- Centralized the backup process to enhance modularity and maintainability by separating core, database, and media backup logic. +- Ensured consistent tagging and logging across all backup types for easier monitoring and debugging. +- Streamlined the orchestration script (`backup_all.sh`) for improved readability and reduced duplication. + ## Version 1.4 ### Added diff --git a/manifest.jps b/manifest.jps index 561ed65..e5d5608 100644 --- a/manifest.jps +++ b/manifest.jps @@ -1,5 +1,5 @@ type: update -jpsVersion: 1.4 +jpsVersion: 1.5 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. @@ -173,7 +173,7 @@ actions: backupnow: - cmd[cp]: user: root - commands: bash /home/jelastic/mb-backups/backup-logic.sh "$(cat /etc/restic-password)" "backup" + commands: bash /home/jelastic/mb-backups/backup_all.sh backup_now - return: type: info message: "${response.out}" diff --git a/scripts/backup-logic.sh b/scripts/backup-logic.sh index 6fe81d5..5e77c7d 100644 --- a/scripts/backup-logic.sh +++ b/scripts/backup-logic.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e # Exit on error -trap 'echo "ERROR: An error occurred while executing $COMMAND for $ENV_NAME. Exiting."' ERR +trap 'log_message "ERROR: An error occurred while executing $COMMAND for $ENV_NAME. Exiting."' ERR # Validate arguments if [ $# -lt 2 ]; then @@ -17,30 +17,23 @@ COMMAND="$2" LOG_FILE="/var/log/${ENV_NAME}_backup_script.log" BACKUP_REPO_PATH="/mnt/backups/${ENV_NAME}" PASSWORD_FILE="/etc/restic-password" - -# Validate ENV_NAME -if [ -z "$ENV_NAME" ]; then - echo "Error: ENV_NAME is not provided or empty." - exit 1 -fi +LOCK_FILE="/tmp/restic_global.lock" # Ensure dynamic paths exist mkdir -p "$BACKUP_REPO_PATH" -# Set environment variables -if [ ! -f "$PASSWORD_FILE" ]; then - echo "Error: Password file not found at $PASSWORD_FILE." - exit 1 -fi - -export RESTIC_REPOSITORY="$BACKUP_REPO_PATH" -export RESTIC_PASSWORD=$(cat "$PASSWORD_FILE") - # Logging function log_message() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } +# Validate password file and set Restic password +if [ ! -f "$PASSWORD_FILE" ]; then + log_message "ERROR: Password file not found at $PASSWORD_FILE." + exit 1 +fi +export RESTIC_PASSWORD=$(cat "$PASSWORD_FILE") + # Ensure Restic is installed install_restic() { if ! which restic &>/dev/null; then @@ -57,6 +50,34 @@ install_restic() { log_message "Restic is installed." } +# Acquire global lock to serialize operations +acquire_lock() { + log_message "Acquiring global lock for Restic operations..." + exec 9>"$LOCK_FILE" + if ! flock -n 9; then + log_message "Another Restic operation is running. Exiting." + exit 1 + fi + log_message "Global lock acquired." +} + +# Release global lock +release_lock() { + exec 9>&- +} + +# Check and remove stale locks +check_stale_locks() { + log_message "Checking for stale locks in the repository..." + if restic -r "$BACKUP_REPO_PATH" list locks | grep -q "lock"; then + log_message "Stale locks detected. Unlocking the repository..." + restic -r "$BACKUP_REPO_PATH" unlock + log_message "Repository unlocked successfully." + else + log_message "No stale locks found." + fi +} + # Initialize or validate repository check_backup_repo() { if ! restic -r "$BACKUP_REPO_PATH" snapshots &>/dev/null; then @@ -95,34 +116,54 @@ case "$COMMAND" in backup) log_message "Starting full backup for environment: $ENV_NAME" install_restic + acquire_lock + check_stale_locks check_backup_repo perform_backup "/var/www/webroot/ROOT/wp-content" "wp-core" "--exclude /var/www/webroot/ROOT/wp-content/uploads" perform_backup "/var/www/webroot/ROOT/wp-content/uploads" "wp-uploads" backup_database + release_lock ;; backup_wp_core) log_message "Backing up WordPress core files for environment: $ENV_NAME" + acquire_lock + check_stale_locks perform_backup "/var/www/webroot/ROOT/wp-content" "wp-core" "--exclude /var/www/webroot/ROOT/wp-content/uploads" + release_lock ;; backup_uploads) log_message "Backing up WordPress uploads for environment: $ENV_NAME" + acquire_lock + check_stale_locks perform_backup "/var/www/webroot/ROOT/wp-content/uploads" "wp-uploads" + release_lock ;; backup_database) + acquire_lock + check_stale_locks backup_database + release_lock ;; check_backup_repo) log_message "Checking backup repository for environment: $ENV_NAME" + acquire_lock + check_stale_locks check_backup_repo + release_lock ;; rotate_snapshots) log_message "Rotating snapshots for environment: $ENV_NAME" + acquire_lock restic -r "$BACKUP_REPO_PATH" forget --keep-last 5 --prune + release_lock log_message "Snapshot rotation completed." ;; create_snapshot) log_message "Creating snapshot for environment: $ENV_NAME" + acquire_lock + check_stale_locks restic -r "$BACKUP_REPO_PATH" backup --tag "manual-snapshot" + release_lock log_message "Snapshot creation completed." ;; update_restic) diff --git a/scripts/imports/backup_all.sh b/scripts/imports/backup_all.sh index 02c66f5..4c44202 100644 --- a/scripts/imports/backup_all.sh +++ b/scripts/imports/backup_all.sh @@ -2,119 +2,51 @@ # Enable error handling set -e - -# Define log file path -LOG_DIR="/home/jelastic/mb-backups/logs" -mkdir -p "$LOG_DIR" - -# Properly escape the trap command -trap 'echo "[$(date +'%Y-%m-%d %H:%M:%S')] Backup failed" >> "$LOG_DIR/backup_error.log"' ERR - -# Load the backup logic functions -source /home/jelastic/mb-backups/backup-logic.sh +trap 'echo "[$(date +%Y-%m-%d %H:%M:%S)] Backup failed" >> "$LOG_DIR/backup_error.log"' ERR # Configuration -password_file="/etc/restic-password" -APP_PATH="/var/www/webroot/ROOT" -WP_CONFIG="${APP_PATH}/wp-config.php" -backupPath="/mnt/backups" -TEMP_DIR="/tmp/wp_backup_tmp" -MAX_BACKUP_SIZE=$((10 * 1024 * 1024 * 1024)) # 10GB +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')" -# Function: Ensure required commands are available -validate_dependencies() { - for cmd in restic mysqldump jq; do - if ! command -v "$cmd" &>/dev/null; then - echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: Required command '$cmd' not found" | tee -a "$LOG_DIR/backup_error.log" - exit 1 - fi - done -} +# Ensure log directory exists +mkdir -p "$LOG_DIR" -# Function: Initialize logging +# Logging function log_message() { - local log_file="$1" - local message="$2" - echo "[$(date +'%Y-%m-%d %H:%M:%S')] $message" | tee -a "$log_file" -} - -# Function: Check if backup size exceeds limit -check_backup_size() { - local path="$1" - local size - size=$(du -sb "$path" | cut -f1) - - if [ "$size" -gt "$MAX_BACKUP_SIZE" ]; then - log_message "$LOG_DIR/backup_warning.log" "Warning: Backup size exceeds 10GB for $path" - return 1 - fi - return 0 -} - -# Function: Verify backup -verify_backup() { - local tag="$1" - local latest_snapshot - latest_snapshot=$(restic snapshots --latest 1 --tag "$tag" --json | jq -r '.[0].id') - if [ -n "$latest_snapshot" ]; then - restic check --read-data "$latest_snapshot" - return $? - fi - return 1 -} - -# Function: Initialize backup -initialize_backup() { - if [ ! -f "$password_file" ]; then - log_message "$LOG_DIR/backup_error.log" "ERROR: Password file not found at $password_file" - exit 1 - fi - export RESTIC_PASSWORD=$(cat "$password_file") - export RESTIC_REPOSITORY="$backupPath" -} - -# Function: Backup core files -backup_core_files() { - local log_file="${LOG_DIR}/backup_core_files_$(date +'%Y-%m-%d').log" - log_message "$log_file" "Starting Core Files Backup" - - check_backup_size "$APP_PATH" || return 1 - - local excludePaths=("$APP_PATH/wp-content/uploads") - local excludeOptions="" - for path in "${excludePaths[@]}"; do - excludeOptions+="--exclude $path " - done - - if restic backup $excludeOptions "$APP_PATH" --tag core_files --tag full_backup; then - verify_backup "core_files" || return 1 - log_message "$log_file" "Core files backup completed successfully" - return 0 - fi - return 1 + local message="$1" + echo "[$(date +'%Y-%m-%d %H:%M:%S')] $message" | tee -a "${LOG_DIR}/backup_all.log" } # Main execution main() { - validate_dependencies - initialize_backup + log_message "Starting full backup process with tag: $MANUAL_BACKUP_TAG" - local start_time=$(date +%s) - local backup_date=$(date +'%Y-%m-%d_%H-%M-%S') - local main_log="${LOG_DIR}/full_backup_${backup_date}.log" - - log_message "$main_log" "Starting full backup process" - - backup_core_files || exit 1 - backup_media_themes || exit 1 - backup_database || exit 1 - - cleanup_old_backups - - local end_time=$(date +%s) - local duration=$((end_time - start_time)) - - log_message "$main_log" "Full backup completed in $duration seconds" + # Run individual backup scripts + if bash "$CORE_BACKUP_SCRIPT" "$(cat /etc/restic-password)" "$MANUAL_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 + 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 + log_message "Media files backup completed successfully." + else + log_message "ERROR: Media files backup failed." + exit 1 + fi + + log_message "Full backup process completed successfully." } # Argument handling