Files
kolla/docker/mariadb-server/backup_replica.sh
Michal Nasiadka c245289176 mariadb: Bump to 11.4
11.4 is the next LTS release (see [1])

New variable ``VERIFY_DB_SERVER_CERT`` is added to mitigate the MariaDB
client variable ``ssl-verify-server-cert`` change from ``FALSE`` to
``TRUE``. [2]
This variable can be overidden by assigning ``TRUE`` to environment
variable with the same name.

[1]: https://mariadb.org/11-4-lts/
[2]: https://jira.mariadb.org/browse/MDEV-31857

Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/928487
Depends-On: https://review.opendev.org/c/openstack/kolla-ansible/+/958281

Change-Id: Ifb41c0c48c4743e70e95fa7e1d329e91362e966c
Signed-off-by: Seunghun Lee <seunghun@stackhpc.com>
2025-10-14 16:07:46 +01:00

150 lines
4.5 KiB
Bash

#!/usr/bin/env bash
set -eu
set -o pipefail
BACKUP_DIR=/backup/
DEFAULT_MY_CNF="/etc/mysql/my.cnf"
REPLICA_MY_CNF="$(mktemp)"
RETRY_INTERVAL=5 # Interval between retries (in seconds)
MAX_RETRIES=12 # Max retries (12 retries * 5 seconds = 60 seconds)
VERIFY_DB_SERVER_CERT="${VERIFY_DB_SERVER_CERT:=FALSE}"
# Cleanup function to remove the REPLICA_MY_CNF file
cleanup() {
rm -f "${REPLICA_MY_CNF}"
}
# Set trap to ensure cleanup occurs on exit or error
trap cleanup EXIT
cd "${BACKUP_DIR}"
# Execute a full backup
backup_full() {
echo "Taking a full backup"
LAST_FULL_DATE=$(date +%d-%m-%Y-%s)
BACKUP_FILE="backup-full-${LAST_FULL_DATE}.mbs.gz"
BACKUP_PATH="${BACKUP_DIR}/full-${LAST_FULL_DATE}"
mkdir -p "${BACKUP_PATH}"
mariabackup \
--defaults-file="${REPLICA_MY_CNF}" \
--backup \
--stream=mbstream \
--history="${LAST_FULL_DATE}" \
| gzip > "${BACKUP_PATH}/${BACKUP_FILE}"
echo "${BACKUP_PATH}/${BACKUP_FILE}" > "${BACKUP_DIR}/last_full_file"
}
# Execute an incremental backup
backup_incremental() {
if [ ! -r "${BACKUP_DIR}/last_full_file" ]; then
echo "Error: No full backup file found."
exit 1
fi
FULL_BACKUP_FILE=$(cat "${BACKUP_DIR}/last_full_file")
LAST_FULL_DATE=$(basename "$(dirname "${FULL_BACKUP_FILE}")" | sed 's/^full-//')
NOW=$(date +%H-%M-%S-%d-%m-%Y)
INCR_DIR="${BACKUP_DIR}/incr-${NOW}-since-${LAST_FULL_DATE}"
mkdir -p "${INCR_DIR}"
# Temp dir for full base restore
TMP_BASEDIR=$(mktemp -d)
echo "Decompressing full backup to temp dir: ${TMP_BASEDIR}"
gunzip -c "${FULL_BACKUP_FILE}" | mbstream -x -C "${TMP_BASEDIR}"
mariabackup \
--defaults-file="${REPLICA_MY_CNF}" \
--backup \
--stream=mbstream \
--incremental-basedir="${TMP_BASEDIR}" \
--history="incr-${NOW}" \
| gzip > "${INCR_DIR}/backup-incremental-${NOW}.mbs.gz"
rm -rf "${TMP_BASEDIR}"
}
# Retry logic for database queries
retry_mysql_query() {
local query="$1"
local result=""
local attempt=1
while [ ${attempt} -le ${MAX_RETRIES} ]; do
result=$(mariadb --ssl-verify-server-cert="${VERIFY_DB_SERVER_CERT}" -h "${HOST}" -u "${USER}" -p"${PASS}" -s -N -e "${query}" 2>/dev/null || true)
if [ -n "${result}" ]; then
echo "${result}"
return 0
fi
echo "Attempt ${attempt}/${MAX_RETRIES} failed. Retrying in ${RETRY_INTERVAL} seconds..."
sleep "${RETRY_INTERVAL}"
attempt=$((attempt + 1))
done
echo "Error: Failed to execute the query after ${MAX_RETRIES} attempts."
return 1
}
get_and_set_replica_server() {
HOST="$(grep '^host' "${DEFAULT_MY_CNF}" | awk -F '=' '{print $2}' | xargs)"
USER="$(grep '^user' "${DEFAULT_MY_CNF}" | awk -F '=' '{print $2}' | xargs)"
PASS="$(grep '^password' "${DEFAULT_MY_CNF}" | awk -F '=' '{print $2}' | xargs)"
ALL_HOSTS_SELECT="SELECT REGEXP_REPLACE(VARIABLE_VALUE, ':[0-9]*','') FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';"
ALL_HOSTS=$(retry_mysql_query "${ALL_HOSTS_SELECT}")
if [ -z "${ALL_HOSTS}" ]; then
echo "Backup failed due to inability to fetch a list of servers."
exit 1
fi
ACTIVE_HOST_SELECT='SELECT @@hostname;'
ACTIVE_HOST=$(retry_mysql_query "${ACTIVE_HOST_SELECT}" | xargs getent hosts | awk '{print $1}')
if [ -z "${ACTIVE_HOST}" ]; then
echo "Backup failed due to inability to fetch active host."
exit 1
fi
# Multinode
if echo "${ALL_HOSTS}" | grep -q ','; then
for server in $(echo "${ALL_HOSTS}" | tr ',' '\n'); do
if [[ "${server}" != "${ACTIVE_HOST}" ]]; then
REPLICA_HOST="${server}"
break
fi
done
# Single node
else
REPLICA_HOST="${ALL_HOSTS}"
fi
if [ -z "${REPLICA_HOST}" ]; then
echo "Backup failed due to inability to determine replica host."
exit 1
fi
cp "${DEFAULT_MY_CNF}" "${REPLICA_MY_CNF}"
sed -i "s/${HOST}/${REPLICA_HOST}/g" "${REPLICA_MY_CNF}"
}
if [ -n "${BACKUP_TYPE}" ]; then
get_and_set_replica_server
case "${BACKUP_TYPE}" in
"full")
backup_full
;;
"incremental")
backup_incremental
;;
*)
echo "Only full or incremental options are supported."
exit 1
;;
esac
else
echo "You need to specify either full or incremental backup options."
exit 1
fi