1
0
mirror of https://github.com/gryf/openstack.git synced 2025-12-17 11:30:24 +01:00

Open-source the OpenStack DB migration scripts and workshop

This commit is contained in:
PTC
2018-11-07 14:11:17 -08:00
parent 002a4a71c7
commit 875239ca08
20 changed files with 1053 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
#!/usr/bin/env bash
# Copyright 2018, Oath Inc.
# Licensed under the terms of the MIT license. See LICENSE file for terms.
set -Eexo pipefail
# Usage:
# ------
# ./clone.sh [option]
#
# option:
# -h, --help: show brief help
# -b, --baremetal: Include the repositories needed for baremetal
#
# Requirements:
# -------------
# 1. Must have access to github.com
# 2. Must be on RHEL6 or RHEL7
# Purpose/Background:
# -------------------
# This script is used to clone down all repositories that are required for the
# DB migration from juno to ocata. It will also build all of the required
# virtualenvs. The output of this script is a tarball called 'build.tar.gz'.
# This script takes around 30-40 (60 for --baremetal) minutes to run. It is
# useful to have this done and the build.tar.gz file available, prior to
# the actual start of a DB migration.
#
# After this script is finished:
# - Copy this tarball to the DB host of the target migration cluster
# before starting the migration (via e.g. the 'cp_build.sh' script).
# - Unzip the tarball with 'tar -xzf build.tar.gz'. Unzipping the
# tarball will create a 'build' directory.
# - Run the migration script 'do_migration.sh' from within the directory
# that holds the build directory.
usage() {
echo "Usage:"
echo "$0 [option]"
echo " option:"
echo " -h, --help: Display this help message"
echo " -b, --baremetal: Include repository for baremetal (ironic)"
}
if ! full_release=$(cat /etc/redhat-release) ; then
echo "This script must be run on a RHEL machine"
exit 1
fi
set -e
baremetal=0
while (( "$#" )); do
case "$1" in
-b|--baremetal)
baremetal=1
shift
;;
-h|--help)
usage
exit 0
;;
-*|--*=) # unsupported flags
echo "Error: Unsupported flag '$1'" >&2
exit 1
;;
*) # unsupported positional arguments
echo "Error: Unsupported positional argument '$1'" >&2
exit 1
;;
esac
done
echo "RHEL release from /etc/redhat-release: $full_release"
case $full_release in
*"release 6"*)
sudo yum install -y mysql-devel;;
*"release 7"*)
sudo yum install -y mariadb-devel;;
esac
sudo yum install -y git libxml2-devel libxslt-devel libffi-devel openssl-devel libvirt-devel
# Make sure python interpreter and virtualenv are available
sudo yum install -y python python-pip
export PIP_REQUIRE_VIRTUALENV=false
sudo pip install virtualenv
export PIP_REQUIRE_VIRTUALENV=true
rm -rf ~/.cache/pip
components="keystone nova glance neutron"
releases="kilo liberty mitaka newton ocata"
if [ ! -e build ]; then
mkdir build
fi
(
cd build
build_dir=$(pwd)
for comp in $components ; do
(
[ -e "${comp}" ] || git clone "https://github.com/openstack/${comp}.git" "${comp}"
for release in ${releases} ; do
dir_name="${comp}-${release}"
cd "$comp";
if git branch -a | grep -q stable/${release} ; then
tag="stable/${release}"
else
tag="${release}-eol"
fi
cd ..
echo "Processing $dir_name..."
(
cd "${comp}"
git checkout "${tag}"
)
cp -r "${comp}" "${dir_name}"
(
venv_name="venv-${dir_name}"
virtualenv "${venv_name}"
source ${venv_name}/bin/activate
cd "${dir_name}"
# Before installing we need to make a couple changes to the upper-constraints file
if [ "${release}" == "newton" ] ; then
up_cons_tag='stable/newton'
else
up_cons_tag="$tag"
fi
up_cons_file=$dir_name-upper-constraints.txt
curl "https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=${up_cons_tag}" | grep -v '^aioeventlet' | grep -v '^cryptography=' | grep -v '^pyOpenSSL=' | grep -v '^cffi=' | grep -v 'SQLAlchemy' | grep -v 'MySQL-python' | grep -v 'PyMySQL' | grep -v 'alembic' > "${up_cons_file}"
echo "aioeventlet===0.5.2" >> "${up_cons_file}"
if [ "${release}" == "kilo" ] ; then
echo "Changing i18n version for kilo release"
grep -v 'oslo.i18n' "${up_cons_file}" | grep -v 'oslo.db' | grep -v '^kombu' > "${up_cons_file}-BAK"
echo "oslo.i18n===1.7.0" >> "${up_cons_file}-BAK"
echo "oslo.db===1.7.0" >> "${up_cons_file}-BAK"
echo "kombu===3.0.30" >> "${up_cons_file}-BAK"
cp "${up_cons_file}-BAK" "${up_cons_file}"
fi
# install package and mysql bindings using modified upper-constraints
pip install . MySQL-python PyMySQL -c "${up_cons_file}"
deactivate
)
done
)
rm -rf "${comp}"
done
if [ "$baremetal" == 1 ]; then
# NOTE(rloo): For the ironic DB migration, we only need the ocata
# version of our modified ironic. Instead of adding a bunch of ifs
# above to handle this case, the relevant bits are copy/pasted,
# because this is a one-off and will not be needed for future
# (post-ocata) migrations.
#
# This adds 'ironic-ocata' and 'venv-ironic-ocata' directories.
comp="ironic"
release="ocata"
git clone "https://github.com/openstack/${comp}.git" "${comp}"
dir_name="${comp}-${release}"
branch="stable/${release}"
echo "Processing $dir_name..."
(
cd "${comp}"
git checkout "${branch}"
)
cp -r "${comp}" "${dir_name}"
(
venv_name="venv-${dir_name}"
virtualenv "${venv_name}"
source ${venv_name}/bin/activate
cd "${dir_name}"
up_cons_file=$dir_name-upper-constraints.txt
cp upper-constraints.txt "${up_cons_file}"
# install package and mysql bindings using upper-constraints
pip install . MySQL-python PyMySQL -c "${up_cons_file}"
deactivate
)
rm -rf "${comp}"
fi
)
echo "Zipping all repos into a single tarball..."
tar -czf build.tar.gz build
echo "Cleaning..."
rm -rf build
echo "Success! You can unpack the tarball with the following command: tar -xzf build.tar.gz"

View File

@@ -0,0 +1,237 @@
#!/usr/bin/env sh
# Copyright 2018, Oath Inc.
# Licensed under the terms of the MIT license. See LICENSE file for terms.
set -Eexo pipefail
#########################################################
########## RUN THIS SCRIPT IN A SCREEN SESSION ##########
#########################################################
# Requirements:
# 1. This script must be run from an openstack db host
# 2. Must have root privs on the machine
# 3. Must be run alongside a build directory that is generated by clone.sh in
# OpenStack/migration-scripts git repo
# 4. It is highly recommended to run this script in a screen session.
# Usage:
# ./do_migration.sh <db_host> <db_port> <db_host_user> <db_host_password> <transport_url> <nova_connection_url> [option]
#
# ./do_migration.sh <RW_HOSTNAME> 3306 root pw "rabbit://ostk_rabbit_user:<RABBIT_PASSWORD>@<MQ1HOST>:<RABBIT_PORT>/ostk_rabbit_vhost" mysql+pymysql://nova:<NOVA_PASSWORD>@<RW_HOSTNAME>:3306 --baremetal
#
# - <transport_url>:
# - if only using 1 MQ node, then the format for transport URL will be the same as above.
# - if we are using more than one MQ, then the transport URL should look like this:
# "rabbit://ostk_rabbit_user:<RABBIT_PASSWORD>@<MQ1_HOST>:<RABBIT_PORT>,ostk_rabbit_user:<RABBIT_PASSWORD>@<MQ2_HOST>:<RABBIT_PORT>/ostk_rabbit_vhost"
# Notice that rabbit:// comes only once before the list of hosts, and /ostk_rabbit_vhost
# comes only once at the very end.
#
# - <RW_HOSTNAME> is the Brooklyn read/write host for the DB.
# - <RABBIT_PASSWORD> is from nova.conf.
# - <MQ1HOST> is the hostname of the Rabbit MQ 1 node.
# - It can be found in the dashboard. Click on clusters on the left. Find the target
# - cluster and click on it. Expand "Hosts" on the resulting page and find "Queue Hosts".
# - <RABBIT_PORT> is 5671 if you are using SSL, and 5672 if you are not using SSL
# - <NOVA_PASSWORD> is the nova user db password.
# The keyname is db_nova_password.
# - [option]
# -b, --baremetal: also do DB migration for ironic
# -h, --help: show brief help
usage() {
echo "Usage:"
echo "$0 <db_host> <db_port> <db_host_user> <db_host_password> <transport_url> <nova_connection_url> [option]"
echo " option:"
echo " -h, --help: Display this help message"
echo " -b, --baremetal: also do DB migration for ironic"
echo "for more information, see comments in the script file"
}
set -e
set -x
baremetal=0
error() {
echo error_msg="FAIL! $1 directory was not found. Run this script https://git.ouroath.com/OpenStack/ocata-migration-scripts/blob/master/clone.sh from a RHEL jumphost to generate the build directory remotely. Then copy the build directory to this machine."
exit 1
}
PARAMS=""
while (( "$#" )); do
case "$1" in
-b|--baremetal)
baremetal=1
shift
;;
-h|--help)
usage
exit 0
;;
-*|--*=) # unsupported flags
echo "Error: Unsupported flag '$1'" >&2
exit 1
;;
*) # preserve positional arguments
PARAMS="$PARAMS $1"
shift
;;
esac
done
# set positional arguments in their proper place
eval set -- "$PARAMS"
if [ $# -ne 6 ] ; then
usage
exit 1
fi
# Make sure git is installed
sudo yum install -y git mysql
db_host="$1"
db_port="$2"
db_user="$3"
db_pass="$4"
transport_url="$5"
nova_db_url="$6"
# Each release to migrate through (Juno, Ocata]
releases="kilo liberty mitaka newton ocata"
# Which components to migrate
if [ "$baremetal" == 1 ]; then
components="keystone nova glance neutron ironic"
else
components="keystone nova glance neutron"
fi
# Let's make sure we have everything that's required installed
sudo yum install -y python python-pip
sudo pip install virtualenv
sudo yum install -y git libxml2-devel libxslt-devel libffi-devel openssl-devel libvirt-devel
# Back up the db first :-)
sql_dump_file="mysqldump.$db_host.`date +"%s"`"
mysqldump -u $db_user --password=$db_pass -h $db_host --all-databases --result-file=$sql_dump_file
# Some necessary preparations to the DB
mysql -u $db_user --password=$db_pass -h $db_host -e "CREATE DATABASE IF NOT EXISTS nova_api;"
mysql -u $db_user --password=$db_pass -h $db_host -e "USE mysql ; GRANT ALL ON nova_api.* TO 'nova'@'%' with GRANT option; FLUSH PRIVILEGES;"
mysql -u $db_user --password=$db_pass -h $db_host -e "CREATE DATABASE IF NOT EXISTS nova_cell0;"
mysql -u $db_user --password=$db_pass -h $db_host -e "USE mysql ; GRANT ALL ON nova_cell0.* TO 'nova'@'%' with GRANT option; FLUSH PRIVILEGES;"
#mysql -u $db_user --password=$db_pass -h $db_host -e "SET GLOBAL FOREIGN_KEY_CHECKS=0;"
mysql -u $db_user --password=$db_pass -h $db_host -e 'USE glance ; CREATE INDEX ix_images_is_public ON images (is_public);' || true
mysql -u $db_user --password=$db_pass -h $db_host -e 'USE glance ; ALTER TABLE image_properties DROP FOREIGN KEY image_properties_ibfk_1;' || true
# Front load some checks to make sure that the necessary directories are in place
if [ ! -e build ]; then
error "build"
fi
cd build
for comp in $components ; do
for release in $releases ; do
if [ $comp == 'ironic' ] && [ $release != 'ocata' ] ; then
continue
else
dir_name="${comp}-$release"
if [ ! -e $dir_name ]; then
error ${dir_name}
fi
venv_name=venv-$dir_name
if [ ! -e $venv_name ]; then
error ${venv_name}
fi
fi
done
done
# use this script to clean up deleted instances
#if [ ! -e cleaner-venv ]; then
# /opt/python/bin/virtualenv -p /opt/python/bin/python2.7 cleaner-venv
#fi
#source cleaner-venv/bin/activate
#pip install mysql-connector-python-rf
#echo "Removing deleted instances...."
#../remove_deleted_instances.py $db_host $db_user $db_pass
#echo "Done."
#deactivate
for comp in $components ; do
echo "Migrating $comp";
# Component will use this config file to talk to the db
db_conf_file=$comp-db.conf
rm -f $db_conf_file
echo "[database]" >> $db_conf_file
if [ $comp == 'nova' ]; then
echo "connection = $nova_db_url/nova" >> $db_conf_file
else
echo "connection = mysql+pymysql://$db_user:$db_pass@$db_host:$db_port/$comp" >> $db_conf_file
fi
echo "[api_database]" >> $db_conf_file
echo "connection = $nova_db_url/nova_api" >> $db_conf_file
echo "[DEFAULT]" >> $db_conf_file
echo "transport_url = $transport_url" >> $db_conf_file
echo "log_dir = /tmp/logs/$comp" >> $db_conf_file
echo "debug = true" >> $db_conf_file
mkdir -p "/tmp/logs/$comp"
for release in $releases ; do
if [ $comp == 'ironic' ] && [ $release != 'ocata' ] ; then
continue
fi
echo "Migrating to $release";
# A mapping from component -> migration command
declare -A migration_command=(["keystone"]="keystone-manage --config-file $db_conf_file db_sync" \
["glance"]="glance-manage --config-file $db_conf_file db_sync" \
["nova"]="nova-manage --config-file $db_conf_file api_db sync ; nova-manage --config-file $db_conf_file db sync" \
["ironic"]="ironic-dbsync --config-file $db_conf_file upgrade" \
["neutron"]="neutron-db-manage --config-file $db_conf_file upgrade heads" \
["horizon"]=":" )
dir_name="${comp}-$release"
venv_name=venv-$dir_name
source $venv_name/bin/activate
# Create cells for ocata
if [ $release == 'newton' ] && [ $comp == 'nova' ] ; then
nova-manage --verbose --config-file $db_conf_file cell_v2 simple_cell_setup
fi
# One time clean-up of null UUIDs
if [ $release == 'kilo' ] && [ $comp == 'nova' ] ; then
nova-manage --config-file $db_conf_file db null_instance_uuid_scan --delete
fi
# Run migration command in the venv and then exit the venv
eval ${migration_command[$comp]}
# Online data migrations
if [ $release != 'kilo' ] && [ $release != 'liberty' ] && [ $comp == 'nova' ] ; then
nova-manage --config-file $db_conf_file db online_data_migrations
fi
# The great Kilo flavor migration of 1934
if [ $release == 'kilo' ] && [ $comp == 'nova' ] ; then
nova-manage --config-file $db_conf_file db migrate_flavor_data --force
mysql -u $db_user --password=$db_pass -h $db_host -e 'USE nova ; UPDATE compute_nodes SET host=hypervisor_hostname;'
fi
deactivate
done
done
# Remove old endpoints (chef deploy will re-populate these with correct values)
mysql -u $db_user --password=$db_pass -h $db_host -e 'USE keystone; DELETE FROM endpoint;'
mysql -u $db_user --password=$db_pass -h $db_host -e 'USE keystone; DELETE FROM service;'
# Remove invalid role assignments (missing user)
# Change legacy "config_drive" key to what is used upstream "configdrive"
# NOTE(jaypipes): This may take a multiple dozens of seconds on a table with
# tens of thousands of records
if [ "$baremetal" == 1 ]; then
mysql -u $db_user --password=$db_pass -h $db_host -e 'USE ironic; UPDATE nodes SET instance_info = REPLACE(instance_info, "\"config_drive\":", "\"configdrive\":");'
fi

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python
# Copyright 2018, Oath Inc.
# Licensed under the terms of the MIT license. See LICENSE file for terms.
"""
Usage:
./remove_deleted_instances.py <db_host> <db_user> <db_pass>
"""
import mysql.connector
import sys
def tuple_to_dict(cur, tup):
return dict(zip(cur.column_names, tup))
uuids = []
cnx = mysql.connector.connect(host=sys.argv[1], user=sys.argv[2], passwd=sys.argv[3], db="nova")
cur1 = cnx.cursor()
cur = cnx.cursor()
cur.execute("SELECT * FROM `instances` WHERE `deleted_at` IS NOT NULL")
for row in cur.fetchall():
row = tuple_to_dict(cur, row)
uuids.append(row['uuid']);
if len(uuids) <= 1:
sys.exit(0)
cur1.execute("SET FOREIGN_KEY_CHECKS = 0;")
uuids = tuple(str(u) for u in uuids)
cur.execute("DELETE FROM instance_id_mappings where uuid IN {}".format(uuids))
cur.execute("DELETE FROM instance_info_caches where instance_uuid IN {}".format(uuids))
cur.execute("DELETE FROM instance_system_metadata where instance_uuid IN {}".format(uuids))
cur.execute("DELETE FROM security_group_instance_association where instance_uuid IN {}".format(uuids))
cur.execute("DELETE FROM instances where uuid IN {}".format(uuids))
cnx.commit()
cur1.execute("SET FOREIGN_KEY_CHECKS = 1;")
cnx.close()