openstack-helm-infra/mariadb/templates/bin/_restore_mariadb.sh.tpl
Andrii Ostapenko 094acf9c86 Support old mariadb dump file naming
Fallback to old dump file naming for read operation to support archives
with legacy naming.

Change-Id: I0c9c7b2c1feaac9aca817041dae617b4d1056b84
Signed-off-by: Andrii Ostapenko <andrii.ostapenko@att.com>
2020-09-04 00:53:37 +00:00

328 lines
9.2 KiB
Smarty
Executable File

#!/bin/bash
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
{{- $envAll := . }}
# Capture the user's command line arguments
ARGS=("$@")
if [[ -s /tmp/restore_main.sh ]]; then
source /tmp/restore_main.sh
else
echo "File /tmp/restore_main.sh does not exist."
exit 1
fi
# Export the variables needed by the framework
export DB_NAME="mariadb"
export DB_NAMESPACE=${MARIADB_POD_NAMESPACE}
export ARCHIVE_DIR=${MARIADB_BACKUP_BASE_DIR}/db/${DB_NAMESPACE}/${DB_NAME}/archive
RESTORE_USER='restoreuser'
RESTORE_PW=$(pwgen 16 1)
RESTORE_LOG='/tmp/restore_error.log'
rm -f $RESTORE_LOG
# This is for commands which require admin access
MYSQL="mysql \
--defaults-file=/etc/mysql/admin_user.cnf \
--host=$MARIADB_SERVER_SERVICE_HOST \
--connect-timeout 10"
# This is for commands which we want the temporary "restore" user
# to execute
RESTORE_CMD="mysql \
--user=${RESTORE_USER} \
--password=${RESTORE_PW} \
--host=$MARIADB_SERVER_SERVICE_HOST \
{{- if .Values.manifests.certificates }}
--ssl-ca=/etc/mysql/certs/ca.crt \
--ssl-key=/etc/mysql/certs/tls.key \
--ssl-cert=/etc/mysql/certs/tls.crt \
{{- end }}
--connect-timeout 10"
# Get a single database data from the SQL file.
# $1 - database name
# $2 - sql file path
current_db_desc() {
PATTERN="-- Current Database:"
sed -n "/${PATTERN} \`$1\`/,/${PATTERN}/p" $2
}
#Return all database from an archive
get_databases() {
TMP_DIR=$1
DB_FILE=$2
if [[ -e ${TMP_DIR}/db.list ]]
then
DBS=$(cat ${TMP_DIR}/db.list )
else
DBS=" "
fi
echo $DBS > $DB_FILE
}
# Determine sql file from 2 options - current and legacy one
# if current is not found check that there is no other namespaced dump file
# before falling back to legacy one
_get_sql_file() {
TMP_DIR=$1
SQL_FILE="${TMP_DIR}/mariadb.${MARIADB_POD_NAMESPACE}.*.sql"
LEGACY_SQL_FILE="${TMP_DIR}/mariadb.*.sql"
INVALID_SQL_FILE="${TMP_DIR}/mariadb.*.*.sql"
if [ -f ${SQL_FILE} ]
then
echo "Found $(ls ${SQL_FILE})" > /dev/stderr
printf ${SQL_FILE}
elif [ -f ${INVALID_SQL_FILE} ]
then
echo "Expected to find ${SQL_FILE} or ${LEGACY_SQL_FILE}, but found $(ls ${INVALID_SQL_FILE})" > /dev/stderr
elif [ -f ${LEGACY_SQL_FILE} ]
then
echo "Falling back to legacy naming ${LEGACY_SQL_FILE}. Found $(ls ${LEGACY_SQL_FILE})" > /dev/stderr
printf ${LEGACY_SQL_FILE}
fi
}
# Extract all tables of a database from an archive and put them in the requested
# file.
get_tables() {
DATABASE=$1
TMP_DIR=$2
TABLE_FILE=$3
SQL_FILE=$(_get_sql_file $TMP_DIR)
if [ ! -z $SQL_FILE ]; then
current_db_desc ${DATABASE} ${SQL_FILE} \
| grep "^CREATE TABLE" | awk -F '`' '{print $2}' \
> $TABLE_FILE
else
# Error, cannot report the tables
echo "No SQL file found - cannot extract the tables"
return 1
fi
}
# Extract all rows in the given table of a database from an archive and put
# them in the requested file.
get_rows() {
DATABASE=$1
TABLE=$2
TMP_DIR=$3
ROW_FILE=$4
SQL_FILE=$(_get_sql_file $TMP_DIR)
if [ ! -z $SQL_FILE ]; then
current_db_desc ${DATABASE} ${SQL_FILE} \
| grep "INSERT INTO \`${TABLE}\` VALUES" > $ROW_FILE
return 0
else
# Error, cannot report the rows
echo "No SQL file found - cannot extract the rows"
return 1
fi
}
# Extract the schema for the given table in the given database belonging to
# the archive file found in the TMP_DIR.
get_schema() {
DATABASE=$1
TABLE=$2
TMP_DIR=$3
SCHEMA_FILE=$4
SQL_FILE=$(_get_sql_file $TMP_DIR)
if [ ! -z $SQL_FILE ]; then
DB_FILE=$(mktemp -p /tmp)
current_db_desc ${DATABASE} ${SQL_FILE} > ${DB_FILE}
sed -n /'CREATE TABLE `'$TABLE'`'/,/'--'/p ${DB_FILE} > ${SCHEMA_FILE}
if [[ ! (-s ${SCHEMA_FILE}) ]]; then
sed -n /'CREATE TABLE IF NOT EXISTS `'$TABLE'`'/,/'--'/p ${DB_FILE} \
> ${SCHEMA_FILE}
fi
rm -f ${DB_FILE}
else
# Error, cannot report the rows
echo "No SQL file found - cannot extract the schema"
return 1
fi
}
# Create temporary user for restoring specific databases.
create_restore_user() {
restore_db=$1
# Ensure any old restore user is removed first, if it exists.
# If it doesn't exist it may return error, so do not exit the
# script if that's the case.
delete_restore_user "dont_exit_on_error"
$MYSQL --execute="GRANT SELECT ON *.* TO ${RESTORE_USER}@'%' IDENTIFIED BY '${RESTORE_PW}';" 2>>$RESTORE_LOG
if [[ "$?" -eq 0 ]]
then
$MYSQL --execute="GRANT ALL ON ${restore_db}.* TO ${RESTORE_USER}@'%' IDENTIFIED BY '${RESTORE_PW}';" 2>>$RESTORE_LOG
if [[ "$?" -ne 0 ]]
then
cat $RESTORE_LOG
echo "Failed to grant restore user ALL permissions on database ${restore_db}"
return 1
fi
else
cat $RESTORE_LOG
echo "Failed to grant restore user select permissions on all databases"
return 1
fi
}
# Delete temporary restore user
delete_restore_user() {
error_handling=$1
$MYSQL --execute="DROP USER ${RESTORE_USER}@'%';" 2>>$RESTORE_LOG
if [[ "$?" -ne 0 ]]
then
if [ "$error_handling" == "exit_on_error" ]
then
cat $RESTORE_LOG
echo "Failed to delete temporary restore user - needs attention to avoid a security hole"
return 1
fi
fi
}
#Restore a single database
restore_single_db() {
SINGLE_DB_NAME=$1
TMP_DIR=$2
if [[ -z "$SINGLE_DB_NAME" ]]
then
echo "Restore single DB called but with wrong parameter."
return 1
fi
SQL_FILE=$(_get_sql_file $TMP_DIR)
if [ ! -z $SQL_FILE ]; then
# Restoring a single database requires us to create a temporary user
# which has capability to only restore that ONE database. One gotcha
# is that the mysql command to restore the database is going to throw
# errors because of all the other databases that it cannot access. So
# because of this reason, the --force option is used to prevent the
# command from stopping on an error.
create_restore_user $SINGLE_DB_NAME
if [[ $? -ne 0 ]]
then
echo "Restore $SINGLE_DB_NAME failed create restore user."
return 1
fi
$RESTORE_CMD --force < $SQL_FILE 2>>$RESTORE_LOG
if [[ "$?" -eq 0 ]]
then
echo "Database $SINGLE_DB_NAME Restore successful."
else
cat $RESTORE_LOG
delete_restore_user "exit_on_error"
echo "Database $SINGLE_DB_NAME Restore failed."
return 1
fi
delete_restore_user "exit_on_error"
if [[ $? -ne 0 ]]
then
echo "Restore $SINGLE_DB_NAME failed delete restore user."
return 1
fi
if [ -f ${TMP_DIR}/${SINGLE_DB_NAME}_grant.sql ]
then
$MYSQL < ${TMP_DIR}/${SINGLE_DB_NAME}_grant.sql 2>>$RESTORE_LOG
if [[ "$?" -eq 0 ]]
then
if ! $MYSQL --execute="FLUSH PRIVILEGES;"; then
echo "Failed to flush privileges for $SINGLE_DB_NAME."
return 1
fi
echo "Database $SINGLE_DB_NAME Permission Restore successful."
else
cat $RESTORE_LOG
echo "Database $SINGLE_DB_NAME Permission Restore failed."
return 1
fi
else
echo "There is no permission file available for $SINGLE_DB_NAME"
return 1
fi
else
echo "There is no database file available to restore from"
return 1
fi
return 0
}
#Restore all the databases
restore_all_dbs() {
TMP_DIR=$1
SQL_FILE=$(_get_sql_file $TMP_DIR)
if [ ! -z $SQL_FILE ]; then
# Check the scope of the archive.
SCOPE=$(echo ${SQL_FILE} | awk -F'.' '{print $(NF-1)}')
if [[ "${SCOPE}" != "all" ]]; then
# This is just a single database backup. The user should
# instead use the single database restore option.
echo "Cannot use the restore all option for an archive containing only a single database."
echo "Please use the single database restore option."
return 1
fi
$MYSQL < $SQL_FILE 2>$RESTORE_LOG
if [[ "$?" -eq 0 ]]
then
echo "Databases $( echo $DBS | tr -d '\n') Restore successful."
else
cat $RESTORE_LOG
echo "Databases $( echo $DBS | tr -d '\n') Restore failed."
return 1
fi
if [[ -f ${TMP_DIR}/grants.sql ]]
then
$MYSQL < ${TMP_DIR}/grants.sql 2>$RESTORE_LOG
if [[ "$?" -eq 0 ]]
then
if ! $MYSQL --execute="FLUSH PRIVILEGES;"; then
echo "Failed to flush privileges."
return 1
fi
echo "Databases Permission Restore successful."
else
cat $RESTORE_LOG
echo "Databases Permission Restore failed."
return 1
fi
else
echo "There is no permission file available"
return 1
fi
else
echo "There is no database file available to restore from"
return 1
fi
return 0
}
# Call the CLI interpreter, providing the archive directory path and the
# user arguments passed in
cli_main ${ARGS[@]}