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-11-12 17:21:04 +00:00
local backup_repo_path = " /mnt/backups/ ${ ENV_NAME } "
2024-11-12 17:00:19 +00:00
local password_file = "/etc/restic-password"
2024-11-12 17:21:04 +00:00
local backup_log_file = "/var/log/backup_addon.log"
2024-11-12 17:00:19 +00:00
2024-11-12 17:18:35 +00:00
# Ensure the backup repository directory exists
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:18:35 +00:00
# Generate a new 10-character random password if password file does not exist or is empty
if [ ! -f " $password_file " ] || [ -z " $( cat " $password_file " ) " ] ; then
local new_password = $( head /dev/urandom | tr -dc A-Za-z0-9 | head -c 10)
echo " $new_password " > " $password_file "
echo " $( date) Password file created with a new random password. " | tee -a " ${ backup_log_file } "
2024-11-12 17:00:19 +00:00
fi
2024-11-12 17:18:35 +00:00
# Load the password from the file for use with Restic
export RESTIC_PASSWORD = $( cat " $password_file " )
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:21:04 +00:00
# Check if the repository is accessible with the current password
2024-03-13 13:25:45 +00:00
if [ " ${ FILES_COUNT } " -gt 0 ] ; then
2024-11-12 17:18:35 +00:00
echo " $( date) ${ ENV_NAME } Checking the backup repository integrity and consistency " | tee -a " ${ backup_log_file } "
2024-11-12 17:21:04 +00:00
if ! GOGC = 20 restic -r " ${ backup_repo_path } " snapshots > /dev/null 2>& 1; then
echo " $( date) ${ ENV_NAME } ERROR: Repository exists but password does not match. " | tee -a " ${ backup_log_file } "
2024-11-12 17:23:39 +00:00
echo " $( date) Reinitializing the repository with a new password. " | tee -a " ${ backup_log_file } "
rm -rf " ${ backup_repo_path } " /*
GOGC = 20 restic init -r " ${ backup_repo_path } "
echo " $( date) Repository reinitialized with a new password. " | tee -a " ${ backup_log_file } "
else
# Remove stale lock if exists
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 -r " ${ backup_repo_path } " unlock
sendEmailNotification
fi
2024-11-12 17:18:35 +00:00
2024-11-12 17:23:39 +00:00
# Run the repository check command
if ! GOGC = 20 restic -q -r " ${ backup_repo_path } " check --read-data-subset= 5%; then
echo "Backup repository integrity check failed." | tee -a " ${ backup_log_file } "
exit 1
fi
2024-03-13 13:25:45 +00:00
fi
else
2024-11-12 17:18:35 +00:00
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:23:39 +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 $?