openstack-helm-infra/mariadb/templates/bin/_restore_mariadb.sh.tpl
Huang, Sophie (sh879n) a23a60921a MariaDB backup and restore with grants of all users
This patchset captures the grants of all the MariaDB users
in the backup tarball and restores the grants during the
all databases restore.
Percona tool pt-show-grants is installed to the image to
accomplish the task in this PS:
https://review.opendev.org/#/c/739149/

Change-Id: I26882956f96c961b6202b1004b8cf0faee6e73eb
2020-07-07 21:22:03 +00:00

290 lines
7.9 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.
# 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 \
--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
}
# 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=mariadb.$MARIADB_POD_NAMESPACE.all.sql
if [[ -e $TMP_DIR/$SQL_FILE ]]; then
current_db_desc ${DATABASE} ${TMP_DIR}/${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=mariadb.$MARIADB_POD_NAMESPACE.all.sql
if [[ -e $TMP_DIR/$SQL_FILE ]]; then
current_db_desc ${DATABASE} ${TMP_DIR}/${SQL_FILE} \
| grep "INSERT INTO \`${TABLE}\` VALUES" > $ROW_FILE
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=mariadb.$MARIADB_POD_NAMESPACE.all.sql
if [[ -e $TMP_DIR/$SQL_FILE ]]; then
DB_FILE=$(mktemp -p /tmp)
current_db_desc ${DATABASE} ${TMP_DIR}/${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=mariadb.$MARIADB_POD_NAMESPACE.all.sql
if [[ -f ${TMP_DIR}/$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 < ${TMP_DIR}/$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=mariadb.$MARIADB_POD_NAMESPACE.all.sql
if [[ -f ${TMP_DIR}/$SQL_FILE ]]
then
$MYSQL < ${TMP_DIR}/$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[@]}