mb-backup-manager/scripts/backup-logic.sh

259 lines
11 KiB
Bash
Raw Normal View History

2024-03-13 13:25:45 +00:00
#!/bin/bash
BASE_URL=$2
BACKUP_TYPE=$3
BACKUP_LOG_FILE=$4
ENV_NAME=$5
BACKUP_COUNT=$6
APP_PATH=$7
USER_SESSION=$8
USER_EMAIL=$9
BACKUP_PATH=${10}
# Ensure restic is installed
if ! which restic &>/dev/null; then
if which dnf &>/dev/null; then
dnf install -y epel-release
dnf install -y restic
elif which yum &>/dev/null; then
yum-config-manager --add-repo https://copr.fedorainfracloud.org/coprs/copart/restic/repo/epel-7/copart-restic-epel-7.repo
yum-config-manager --enable copart-restic
yum -y install restic
yum-config-manager --disable copart-restic
fi
fi
# Function definitions remain the same, but adjustments are made to use $BACKUP_PATH
function update_restic(){
restic self-update 2>&1;
}
2024-11-12 17:13:53 +00:00
function check_backup_repo() {
2024-03-13 13:25:45 +00:00
local backup_repo_path="/mnt/backups/${ENV_NAME}"
2024-11-12 17:00:19 +00:00
local password_file="/etc/restic-password"
# Create the backup repository path if it does not exist
2024-03-13 13:25:45 +00:00
[ -d "${backup_repo_path}" ] || mkdir -p "${backup_repo_path}"
2024-11-12 17:00:19 +00:00
2024-11-12 17:13:53 +00:00
# Check if the password file exists, otherwise create a new random password
2024-11-12 17:00:19 +00:00
if [ -f "$password_file" ]; then
stored_password=$(cat "$password_file")
2024-11-12 17:13:53 +00:00
if [ -z "$stored_password" ] || [[ ${#stored_password} -lt 10 ]]; then
# Generate a new password if the existing one is less than 10 characters
echo "$(date) Password is invalid or too short. Generating a new password." | tee -a "${BACKUP_LOG_FILE}"
stored_password=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 10)
echo "$stored_password" > "$password_file"
2024-11-12 17:00:19 +00:00
fi
else
2024-11-12 17:13:53 +00:00
# Generate and save a random 10-character password
stored_password=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 10)
echo "$stored_password" > "$password_file"
echo "$(date) Password file created with password: ${stored_password}" | tee -a "${BACKUP_LOG_FILE}"
2024-11-12 17:00:19 +00:00
fi
# Export the repository password
2024-11-12 17:13:53 +00:00
export RESTIC_PASSWORD="$stored_password"
2024-11-12 17:00:19 +00:00
export RESTIC_REPOSITORY="$backup_repo_path"
2024-03-13 13:25:45 +00:00
export FILES_COUNT=$(find "${backup_repo_path}" -mindepth 1 | wc -l)
2024-11-12 17:13:53 +00:00
2024-11-12 17:00:19 +00:00
# Check repository integrity if it has files, otherwise initialize it
2024-03-13 13:25:45 +00:00
if [ "${FILES_COUNT}" -gt 0 ]; then
echo "$(date) ${ENV_NAME} Checking the backup repository integrity and consistency" | tee -a "${BACKUP_LOG_FILE}"
if [[ $(ls -A "${backup_repo_path}/locks") ]]; then
echo "$(date) ${ENV_NAME} Backup repository has a stale lock, removing" | tee -a "${BACKUP_LOG_FILE}"
2024-11-12 17:00:19 +00:00
GOGC=20 restic -r "${backup_repo_path}" unlock
2024-03-13 13:25:45 +00:00
sendEmailNotification
fi
2024-11-12 17:00:19 +00:00
if ! GOGC=20 restic -q -r "${backup_repo_path}" check --read-data-subset=5%; then
2024-03-13 13:25:45 +00:00
echo "Backup repository integrity check failed." | tee -a "${BACKUP_LOG_FILE}"
exit 1
fi
else
echo "$(date) ${ENV_NAME} Initializing new backup repository" | tee -a "${BACKUP_LOG_FILE}"
2024-11-12 17:00:19 +00:00
GOGC=20 restic init -r "${backup_repo_path}"
2024-03-13 13:25:45 +00:00
fi
}
2024-11-12 17:13:53 +00:00
2024-03-13 13:25:45 +00:00
function sendEmailNotification() {
if [ -e "/usr/lib/jelastic/modules/api.module" ]; then
[ -e "/var/run/jem.pid" ] && return 0;
CURRENT_PLATFORM_MAJOR_VERSION=$(jem api apicall -s --connect-timeout 3 --max-time 15 [API_DOMAIN]/1.0/statistic/system/rest/getversion 2>/dev/null | jq .version | grep -o [0-9.]* | awk -F . '{print $1}')
if [ "${CURRENT_PLATFORM_MAJOR_VERSION}" -ge "7" ]; then
echo "$(date) ${ENV_NAME} Sending e-mail notification about removing the stale lock" | tee -a "$BACKUP_LOG_FILE"
SUBJECT="Stale lock is removed on ${BACKUP_PATH}/${ENV_NAME} backup repo"
BODY="Please pay attention to ${BACKUP_PATH}/${ENV_NAME} backup repo because the stale lock left from previous operation is removed during the integrity check and backup rotation. Manual check of backup repo integrity and consistency is highly desired."
jem api apicall -s --connect-timeout 3 --max-time 15 [API_DOMAIN]/1.0/message/email/rest/send --data-urlencode "session=$USER_SESSION" --data-urlencode "to=$USER_EMAIL" --data-urlencode "subject=$SUBJECT" --data-urlencode "body=$BODY"
if [[ $? != 0 ]]; then
echo "$(date) ${ENV_NAME} Sending of e-mail notification failed" | tee -a "$BACKUP_LOG_FILE"
else
echo "$(date) ${ENV_NAME} E-mail notification is sent successfully" | tee -a "$BACKUP_LOG_FILE"
fi
elif [ -z "${CURRENT_PLATFORM_MAJOR_VERSION}" ]; then
echo "$(date) ${ENV_NAME} Error when checking the platform version" | tee -a "$BACKUP_LOG_FILE"
else
echo "$(date) ${ENV_NAME} Email notification is not sent because this functionality is unavailable for current platform version." | tee -a "$BACKUP_LOG_FILE"
fi
else
echo "$(date) ${ENV_NAME} Email notification is not sent because this functionality is unavailable for current platform version." | tee -a "$BACKUP_LOG_FILE"
fi
}
function rotate_snapshots(){
local backup_repo_path="/mnt/backups/${ENV_NAME}"
echo "$(date) ${ENV_NAME} Rotating snapshots by keeping the last ${BACKUP_COUNT}" | tee -a "${BACKUP_LOG_FILE}"
if [[ $(ls -A "${backup_repo_path}/locks") ]]; then
echo "$(date) ${ENV_NAME} Backup repository has a stale lock, removing" | tee -a "${BACKUP_LOG_FILE}"
GOGC=20 RESTIC_PASSWORD="${ENV_NAME}" restic -r "${backup_repo_path}" unlock
sendEmailNotification
fi
if ! GOGC=20 RESTIC_COMPRESSION=off RESTIC_PACK_SIZE=8 RESTIC_PASSWORD="${ENV_NAME}" restic forget -q -r "${backup_repo_path}" --keep-last "${BACKUP_COUNT}" --prune | tee -a "${BACKUP_LOG_FILE}"; then
echo "Backup rotation failed." | tee -a "${BACKUP_LOG_FILE}"
exit 1
fi
}
function create_snapshot(){
local backup_repo_path="/mnt/backups/${ENV_NAME}"
DUMP_NAME=$(date "+%F_%H%M%S_%Z")
echo "$(date) ${ENV_NAME} Begin uploading the ${DUMP_NAME} snapshot to backup storage" | tee -a "${BACKUP_LOG_FILE}"
if ! GOGC=20 RESTIC_COMPRESSION=off RESTIC_PACK_SIZE=8 RESTIC_READ_CONCURRENCY=8 RESTIC_PASSWORD="${ENV_NAME}" restic backup -q -r "${backup_repo_path}" --tag "${DUMP_NAME} ${BACKUP_ADDON_COMMIT_ID} ${BACKUP_TYPE}" "${APP_PATH}" ~/wp_db_backup.sql | tee -a "${BACKUP_LOG_FILE}"; then
echo "Backup snapshot creation failed." | tee -a "${BACKUP_LOG_FILE}"
exit 1
fi
echo "$(date) ${ENV_NAME} End uploading the ${DUMP_NAME} snapshot to backup storage" | tee -a "${BACKUP_LOG_FILE}"
}
2024-03-13 18:03:04 +00:00
function backup_database() {
local backup_repo_path="/mnt/backups/${ENV_NAME}/db"
local log_file="/home/litespeed/mbmanager/logs/${ENV_NAME}_db_backup.log"
# Ensure the backup and log directories exist
2024-03-13 17:45:48 +00:00
mkdir -p "${backup_repo_path}"
2024-03-13 18:03:04 +00:00
mkdir -p "$(dirname "${log_file}")"
2024-03-13 17:45:48 +00:00
2024-03-13 18:03:04 +00:00
echo "$(date) ${ENV_NAME} Starting database backup..." | tee -a "${log_file}"
2024-03-13 17:45:48 +00:00
2024-03-13 18:03:04 +00:00
# Extract database credentials from wp-config.php
2024-03-13 17:45:48 +00:00
DB_NAME=$(grep DB_NAME /var/www/webroot/ROOT/wp-config.php | cut -d "'" -f 4)
DB_USER=$(grep DB_USER /var/www/webroot/ROOT/wp-config.php | cut -d "'" -f 4)
DB_PASSWORD=$(grep DB_PASSWORD /var/www/webroot/ROOT/wp-config.php | cut -d "'" -f 4)
DB_HOST=$(grep DB_HOST /var/www/webroot/ROOT/wp-config.php | cut -d "'" -f 4 | awk -F':' '{print $1}')
2024-03-13 18:03:04 +00:00
DB_PORT=$(grep DB_HOST /var/www/webroot/ROOT/wp-config.php | cut -d "'" -f 4 | awk -F':' '{print $2}' | sed 's/)//')
2024-03-13 17:45:48 +00:00
DB_PORT=${DB_PORT:-3306}
2024-03-13 13:25:45 +00:00
2024-03-13 18:03:04 +00:00
# Determine the correct --column-statistics option based on MySQL or MariaDB version
local column_statistics_option=""
SERVER_VERSION=$(mysql -h "${DB_HOST}" -u "${DB_USER}" -p"${DB_PASSWORD}" -e 'SELECT VERSION();' -s -N)
if [[ "${SERVER_VERSION}" =~ ^5\.7|^8\.0|MariaDB ]]; then
column_statistics_option="--column-statistics=0"
fi
# Create a database dump
local dump_file="${backup_repo_path}/${ENV_NAME}_$(date "+%Y-%m-%d_%H-%M-%S").sql"
mysqldump -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASSWORD}" ${column_statistics_option} --force --single-transaction --quote-names --opt "${DB_NAME}" > "${dump_file}"
2024-03-13 17:45:48 +00:00
if [ $? -ne 0 ]; then
2024-03-13 18:03:04 +00:00
echo "$(date) ${ENV_NAME} Database backup process failed." | tee -a "${log_file}"
2024-03-13 13:25:45 +00:00
exit 1
fi
2024-03-13 18:03:04 +00:00
# Backup the dump file using Restic
restic -r "${backup_repo_path}" backup "${dump_file}" --tag "db" --host "${ENV_NAME}"
2024-03-13 17:45:48 +00:00
if [ $? -ne 0 ]; then
2024-03-13 18:03:04 +00:00
echo "$(date) ${ENV_NAME} Restic backup process failed." | tee -a "${log_file}"
2024-03-13 13:25:45 +00:00
exit 1
fi
2024-03-13 18:03:04 +00:00
echo "$(date) ${ENV_NAME} Database backup completed successfully." | tee -a "${log_file}"
# Optionally, remove the dump file after successful backup
rm -f "${dump_file}"
2024-03-13 13:25:45 +00:00
}
function backup_wp_core() {
echo "Starting backup of WordPress core files excluding uploads directory..."
# Define the path to the WordPress installation and the backup tag
local wp_path="$APP_PATH"
local backup_tag="wp-core-$(date "+%F_%H%M%S_%Z")"
# Exclude the uploads directory using the --exclude option
GOGC=20 RESTIC_PASSWORD="$RESTIC_PASSWORD" restic -r "$backupPath" backup \
--tag "$backup_tag" \
--exclude="$wp_path/wp-content/uploads" \
"$wp_path"
echo "WordPress core files backup completed."
}
function backup_uploads() {
echo "Starting backup of WordPress uploads directory..."
# Define the path to the uploads directory and the backup tag
local uploads_path="$APP_PATH/wp-content/uploads"
local backup_tag="wp-uploads-$(date "+%F_%H%M%S_%Z")"
# Perform the backup
GOGC=20 RESTIC_PASSWORD="$RESTIC_PASSWORD" restic -r "$backupPath" backup \
--tag "$backup_tag" \
"$uploads_path"
echo "WordPress uploads directory backup completed."
}
function backup_database() {
echo "Starting backup of WordPress database..."
# Define the backup tag and the path for the temporary SQL dump
local backup_tag="wp-db-$(date "+%F_%H%M%S_%Z")"
local sql_dump_path="/tmp/wp_db_backup.sql"
# Create a database dump
mysqldump -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" > "$sql_dump_path"
# Perform the backup
GOGC=20 RESTIC_PASSWORD="$RESTIC_PASSWORD" restic -r "$backupPath" backup \
--tag "$backup_tag" \
"$sql_dump_path"
# Remove the temporary SQL dump file
rm -f "$sql_dump_path"
echo "WordPress database backup completed."
}
case "$1" in
backup)
backup_wp_core
backup_uploads
backup_database
;;
backup_wp_core)
backup_wp_core
;;
backup_uploads)
backup_uploads
;;
backup_database)
backup_database
;;
check_backup_repo)
check_backup_repo
;;
rotate_snapshots)
rotate_snapshots
;;
create_snapshot)
create_snapshot
;;
update_restic)
update_restic
;;
*)
echo "Usage: $0 {backup|backup_wp_core|backup_uploads|backup_database|check_backup_repo|rotate_snapshots|create_snapshot|update_restic}"
exit 2
esac
exit $?