47e31b894e
The --skip-locks flag can be used along with --migrate in deployments where table locking operations can't be performed. For example, Percona XtraDB Cluster only has experimental support for explicit table locking operations and attempts to use locking will result in errors when PXC Strict Mode is set to ENFORCING. Change-Id: I3df5686d13c1ce0cc38402a1317acb661ad74cec Story: #2006670
308 lines
8.6 KiB
Bash
Executable File
308 lines
8.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# This script will attempt to migrate your nova-api placement data to
|
|
# a new placement database. Run it with --help for usage, and --mkconfig
|
|
# to write a template config file to use.
|
|
|
|
# Defaults we can guess
|
|
DEFAULT_MIGRATE_TABLES="allocations placement_aggregates consumers inventories projects "
|
|
DEFAULT_MIGRATE_TABLES+="resource_classes resource_provider_aggregates resource_provider_traits "
|
|
DEFAULT_MIGRATE_TABLES+="resource_providers traits users "
|
|
MIGRATE_TABLES=${MIGRATE_TABLES:-$DEFAULT_MIGRATE_TABLES}
|
|
PLACEMENT_DB_HOST=${PLACEMENT_DB_HOST:-localhost}
|
|
PLACEMENT_DB=${PLACEMENT_DB:-placement}
|
|
NOVA_API_DB_HOST=${NOVA_API_DB_HOST:-localhost}
|
|
NOVA_API_DB=${NOVA_API_DB:-nova_api}
|
|
TMPDIR=${TMPDIR:-/tmp}
|
|
LAST_MYSQL_ERR=${TMPDIR}/migrate-mysql-db.err
|
|
INITIAL_PLACEMENT_DB_VERSION=${INITIAL_DB_VERSION:-b4ed3a175331}
|
|
ME=$(basename "$0")
|
|
|
|
declare -a ARGS
|
|
declare -a OPTS
|
|
|
|
function getflag() {
|
|
# Return true if --$flag is present on the command line
|
|
# Usage: getflag help -> 0
|
|
local flag="$1"
|
|
for opt in ${OPTS[*]}; do
|
|
if [ "$opt" == "--${flag}" ]; then
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
function parse_argv() {
|
|
# Parse command line arguments into positional arguments and
|
|
# option flags. Store each in $ARGS, $OPTS.
|
|
# Usage: parse_argv $*
|
|
for item in $*; do
|
|
if echo $item | grep -q -- '^--'; then
|
|
OPTS+=($item)
|
|
else
|
|
ARGS+=($item)
|
|
fi
|
|
done
|
|
}
|
|
|
|
function db_var() {
|
|
# Return an attribute of database config based on the symbolic
|
|
# name
|
|
# Usage: db_var PLACEMENT USER -> $PLACEMENT_USER
|
|
local db="$1"
|
|
local var="$2"
|
|
|
|
eval echo "\$${db}_${var}"
|
|
}
|
|
|
|
function mysql_command() {
|
|
# Run a mysql command with the usual connection information taken
|
|
# from a symbolic configuration name
|
|
# Usage: mysql_command PLACEMENT [command] [args..] -> stdout
|
|
local whichdb="$1"
|
|
shift
|
|
local command=mysql
|
|
if [ "$2" ]; then
|
|
command=${1:-mysql}
|
|
shift
|
|
fi
|
|
local db=$(db_var $whichdb DB)
|
|
local host=$(db_var $whichdb DB_HOST)
|
|
local user=$(db_var $whichdb USER)
|
|
local pass=$(db_var $whichdb PASS)
|
|
|
|
if [ "$command" = "mysql" ]; then
|
|
command="mysql --skip-column-names"
|
|
fi
|
|
|
|
$command -h$host -u$user -p$pass $db $* 2>$LAST_MYSQL_ERR
|
|
}
|
|
|
|
function show_error() {
|
|
# Prints the last error (if present) and removes the temporary
|
|
# file
|
|
if [ -f $LAST_MYSQL_ERR ]; then
|
|
cat $LAST_MYSQL_ERR
|
|
rm -f $LAST_MYSQL_ERR
|
|
fi
|
|
}
|
|
|
|
function check_db() {
|
|
# Check a DB to see if it's missing, present, filled with data
|
|
# Returns 0 if it is present with data, 1 if present but no data
|
|
# or 2 if not present (or unable to connect)
|
|
# Usage: check_db PLACEMENT -> 0
|
|
local whichdb="$1"
|
|
|
|
local inv
|
|
local inv_count
|
|
|
|
if ! echo "SELECT DATABASE()" | mysql_command $whichdb >/dev/null 2>&1; then
|
|
echo "Failed to connect to $whichdb database"
|
|
show_error
|
|
return 2
|
|
fi
|
|
|
|
inv=$(echo "SELECT COUNT(id) FROM inventories" |
|
|
mysql_command $whichdb)
|
|
if [ $? -ne 0 ]; then
|
|
# No schema
|
|
return 1
|
|
fi
|
|
|
|
inv_count=$(echo $inv | tail -n1)
|
|
if [ $inv_count -gt 0 ]; then
|
|
# Data found
|
|
return 0
|
|
else
|
|
# No data found, but schema intact
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function check_cli() {
|
|
# Returns 0 if placement cli is installed and configured,
|
|
# 1 if it is not installed, or 2 if the access to the
|
|
# placement database fails
|
|
# Usage: check_cli -> 0
|
|
placement-manage --version > /dev/null 2>&1
|
|
|
|
if [ $? -ne 0 ]; then
|
|
# placement not installed
|
|
return 1
|
|
fi
|
|
|
|
placement-manage db version > /dev/null 2>&1
|
|
|
|
if [ $? -ne 0 ]; then
|
|
# DB connection fails
|
|
return 2
|
|
fi
|
|
}
|
|
|
|
function migrate_data() {
|
|
# Actually migrate data from a source to destination symbolic
|
|
# database. Returns 1 if failure, 0 otherwise.
|
|
# Usage: migrate_data NOVA_API PLACEMENT -> 0
|
|
local source="$1"
|
|
local dest="$2"
|
|
local dump_flags="$3"
|
|
local tmpdir=$(mktemp -d migrate-db.XXXXXXXX)
|
|
local tmpfile="${tmpdir}/from-nova.sql"
|
|
|
|
echo "Dumping from $source to $tmpfile"
|
|
mysql_command $source mysqldump $dump_flags $MIGRATE_TABLES > $tmpfile || {
|
|
echo 'Failed to dump source database:'
|
|
show_error
|
|
return 1
|
|
}
|
|
echo "Loading to $dest from $tmpfile"
|
|
mysql_command $dest < $tmpfile || {
|
|
echo 'Failed to load destination database:'
|
|
show_error
|
|
return 1
|
|
}
|
|
}
|
|
|
|
function sanity_check_env() {
|
|
# Check that we have everything we need to examine the situation
|
|
# and potentially do the migration. Loads values from the rcfile,
|
|
# if present. Returns 1 if a config was not found, 2 if that
|
|
# config is incomplete or 0 if everything is good.
|
|
# Usage: sanity_check_env $rcfile -> 0
|
|
|
|
RCFILE="${1:-migrate-db.rc}"
|
|
if [ "$RCFILE" = '-' ]; then
|
|
# Don't require a file and assume everything is already
|
|
# set in the environment
|
|
true
|
|
elif [ ! -f "$RCFILE" ]; then
|
|
echo -n 'ERROR: Specify an RC file on the command line or create '
|
|
echo 'migrate-db.rc in the current directory'
|
|
echo
|
|
show_help
|
|
else
|
|
source $RCFILE
|
|
fi
|
|
|
|
required="NOVA_API_DB NOVA_API_USER NOVA_API_PASS PLACEMENT_DB PLACEMENT_USER PLACEMENT_PASS"
|
|
for var in $required; do
|
|
value=$(eval echo "\$$var")
|
|
if [ -z "$value" ]; then
|
|
echo "A value for $var was not provided but is required"
|
|
return 2
|
|
fi
|
|
done
|
|
}
|
|
|
|
function make_config() {
|
|
# Create or update a config file with defaults we know. Either use
|
|
# the default migrate-db.rc or the file specified on the command
|
|
# line.
|
|
RCFILE="${1:-migrate-db.rc}"
|
|
if [ -f "$RCFILE" ]; then
|
|
source $RCFILE
|
|
fi
|
|
|
|
vars="NOVA_API_DB NOVA_API_USER NOVA_API_PASS NOVA_API_DB_HOST "
|
|
vars+="PLACEMENT_DB PLACEMENT_USER PLACEMENT_PASS PLACEMENT_DB_HOST "
|
|
vars+="MIGRATE_TABLES"
|
|
|
|
(for var in $vars; do
|
|
val=$(eval echo "\$$var")
|
|
echo "${var}=\"$val\""
|
|
done) > $RCFILE
|
|
|
|
echo Wrote $(readlink -f $RCFILE)
|
|
}
|
|
|
|
function show_help() {
|
|
echo "Usage: $ME [flags] [rcfile]"
|
|
echo
|
|
echo "Flags:"
|
|
echo " --help: this text"
|
|
echo " --migrate: actually do data migration"
|
|
echo " --mkconfig: write/update config to \$rcfile"
|
|
echo " --skip-locks: don't use table locks for data migration"
|
|
echo
|
|
echo "Pass '-' as \$rcfile if all config values are set in"
|
|
echo "the environment."
|
|
echo
|
|
echo "Exit codes:"
|
|
echo " 0: Success"
|
|
echo " 1: Usage error"
|
|
echo " 2: Configuration missing or incomplete"
|
|
echo " 3: Migration already completed"
|
|
echo " 4: No data to migrate from nova (new deployment)"
|
|
echo " 5: Unable to connect to one or both databases"
|
|
echo " 6: Unable to execute placement's CLI commands"
|
|
exit 0
|
|
}
|
|
|
|
parse_argv $*
|
|
|
|
if getflag help; then
|
|
show_help
|
|
fi
|
|
|
|
if getflag mkconfig; then
|
|
make_config $ARGS
|
|
exit 0
|
|
fi
|
|
|
|
#
|
|
# Actual migration logic starts here
|
|
#
|
|
|
|
# Sanity check that we have what we need or bail
|
|
sanity_check_env $ARGS || exit $?
|
|
|
|
# Check the state of each database we care about
|
|
check_db NOVA_API
|
|
nova_present=$?
|
|
check_db PLACEMENT
|
|
placement_present=$?
|
|
check_cli
|
|
placement_cli=$?
|
|
|
|
# Try to come up with a good reason to refuse to migrate
|
|
if [ $nova_present -eq 0 -a $placement_present -eq 0 ]; then
|
|
echo "Migration has already completed. The placement database appears to have data."
|
|
exit 3
|
|
elif [ $nova_present -eq 1 ]; then
|
|
echo "No data present in nova database - nothing to migrate (new deployment?)"
|
|
exit 4
|
|
elif [ $nova_present -eq 2 ]; then
|
|
echo "Unable to proceed without connection to nova database"
|
|
exit 5
|
|
elif [ $placement_present -eq 2 ]; then
|
|
echo "Unable to proceed without connection to placement database"
|
|
exit 5
|
|
elif [ $placement_cli -eq 1 ]; then
|
|
echo "Unable to proceed without placement installed"
|
|
exit 6
|
|
elif [ $placement_cli -eq 2 ]; then
|
|
echo "The 'placement-manage db version' command fails"
|
|
echo "Is placement.conf configured to access the new database?"
|
|
exit 6
|
|
fi
|
|
|
|
# If we get here, we expect to be able to migrate. Require them to opt into
|
|
# actual migration before we do anything.
|
|
|
|
echo Nova database contains data, placement database does not. Okay to proceed with migration
|
|
|
|
if getflag migrate $*; then
|
|
if getflag skip-locks $*; then
|
|
migrate_data NOVA_API PLACEMENT "--skip-lock-tables --skip-add-locks"
|
|
else
|
|
migrate_data NOVA_API PLACEMENT
|
|
fi
|
|
placement-manage db stamp $INITIAL_PLACEMENT_DB_VERSION
|
|
else
|
|
echo "To actually migrate, run me with --migrate"
|
|
fi
|
|
|
|
rm -f $LAST_MYSQL_ERR
|