grenade/grenade.sh

391 lines
13 KiB
Bash
Executable File

#!/usr/bin/env bash
# ``grenade.sh`` is an OpenStack upgrade test harness to exercise the
# OpenStack upgrade process. It uses DevStack to perform the initial
# OpenStack install.
# Grenade assumes it is running on the system that will be hosting the
# upgrade processes
# ``grenade.sh [-b] [-t] [-s stop-label] [-q]``
#
# ``-b`` Run only the base part
# ``-t`` Run only the target part (assumes a base run is in place)
# ``-q`` Quiet mode
# ``-s stop-label`` is the name of the step after which the script will stop.
# This is useful for debugging upgrades.
# ``GRENADE_DIR`` is set once by the top level grenade.sh and exported
# so that all subsequent scripts can find their way back to the
# grenade root directory. No other scripts should set this variable
export GRENADE_DIR=$(cd $(dirname "$0") && pwd)
# Source the bootstrapping facilities
#
# Grenade attempts to reuse as much content from devstack on the
# target side as possible, but we need enough of our own code to get
# there.
#
# ``grenaderc`` is a set of X=Y declarations that don't need *any* of
# the devstack functions to work
#
# ``inc/bootstrap`` is the most minimal amount of functions that
# grenade needs to get going. This includes things like echo
# functions, trueorfalse, and the functions related to git cloning, so
# that we can get our devstack trees.
export DSTOOLS_VERSION=${DSTOOLS_VERSION:-0.4.0}
source $GRENADE_DIR/grenaderc
source $GRENADE_DIR/inc/bootstrap
while getopts bqs:t c; do
case $c in
b)
RUN_TARGET=False
;;
q)
VERBOSE=False
;;
s)
STOP=$2
;;
t)
RUN_BASE=False
;;
esac
done
shift `expr $OPTIND - 1`
# Create all the base directory structures needed for the rest of the
# environment to run.
#
# This will give you an STACK_ROOT tree that you expect, and that your
# normal user owns for follow on activities.
sudo mkdir -p $BASE_RELEASE_DIR $TARGET_RELEASE_DIR
sudo chown -R `whoami` $STACK_ROOT
# Logging
# =======
# TODO(sdague): should this extract into ``inc/bootstrap``?
#
# Set up logging
# Set ``LOGFILE`` to turn on logging
# Append '.xxxxxxxx' to the given name to maintain history
# where 'xxxxxxxx' is a representation of the date the file was created
if [[ -n "$LOGFILE" ]]; then
LOGDAYS=${LOGDAYS:-7}
TIMESTAMP_FORMAT=${TIMESTAMP_FORMAT:-"%F-%H%M%S"}
CURRENT_LOG_TIME=$(date "+$TIMESTAMP_FORMAT")
# First clean up old log files. Use the user-specified ``LOGFILE``
# as the template to search for, appending '.*' to match the date
# we added on earlier runs.
LOGDIR=$(dirname "$LOGFILE")
LOGNAME=$(basename "$LOGFILE")
echo "Creating $LOGDIR...."
sudo mkdir -p $LOGDIR
sudo chown -R `whoami` $LOGDIR
find $LOGDIR -maxdepth 1 -name $LOGNAME.\* -mtime +$LOGDAYS -exec rm {} \;
LOGFILE=$LOGFILE.${CURRENT_LOG_TIME}
SUMFILE=$LOGFILE.${CURRENT_LOG_TIME}.summary
# Redirect output according to config
# Copy stdout to fd 3
exec 3>&1
if [[ "$VERBOSE" == "True" ]]; then
echo "Running in verbose mode:"
echo " Full logs found at => ${LOGFILE}"
echo " Summary logs at => ${SUMFILE}"
# Redirect stdout/stderr to tee to write the log file
exec 1> >( ./tools/outfilter.py -v -o "${LOGFILE}" ) 2>&1
# Set up a second fd for output
exec 6> >( ./tools/outfilter.py -o "${SUMFILE}" )
else
echo "Running in summary mode:"
echo " Full logs found at => ${LOGFILE}"
echo " Summary logs at => ${SUMFILE}"
# Set fd 1 and 2 to primary logfile
exec 1> >( ./tools/outfilter.py -o "${LOGFILE}") 2>&1
# Set fd 6 to summary logfile and stdout
exec 6> >( ./tools/outfilter.py -v -o "${SUMFILE}" >&3)
fi
echo_summary "grenade.sh log $LOGFILE"
# Specified logfile name always links to the most recent log
ln -sf $LOGFILE $LOGDIR/$LOGNAME
ln -sf $SUMFILE $LOGDIR/$LOGNAME.summary
else
# Set up output redirection without log files
# Copy stdout to fd 3
exec 3>&1
if [[ "$VERBOSE" != "yes" ]]; then
# Throw away stdout and stderr
exec 1>/dev/null 2>&1
fi
# Always send summary fd to original stdout
exec 6> >( ./tools/outfilter.py -v -o "${SUMFILE}" >&3)
fi
# Set up logging of screen windows
# Set ``SCREEN_LOGDIR`` to turn on logging of screen windows to the
# directory specified in ``SCREEN_LOGDIR``, we will log to the file
# ``screen-$SERVICE_NAME-$TIMESTAMP.log`` in that dir and have a link
# ``screen-$SERVICE_NAME.log`` to the latest log file.
# Logs are kept for as long specified in ``LOGDAYS``.
if [[ -n "$SCREEN_LOGDIR" ]]; then
# We make sure the directory is created.
if [[ -d "$SCREEN_LOGDIR" ]]; then
# We cleanup the old logs
find $SCREEN_LOGDIR -maxdepth 1 -name screen-\*.log -mtime +$LOGDAYS -exec rm {} \;
else
sudo mkdir -p $SCREEN_LOGDIR
sudo chown -R `whoami` $SCREEN_LOGDIR
fi
fi
# This script exits on an error so that errors don't compound and you see
# only the first error that occurred.
set -o errexit
# Print the commands being run so that we can see the command that triggers
# an error. It is also useful for following allowing as the install occurs.
set -o xtrace
# Devstack Phase 2 initialization
# ===============================
#
# We now have enough infrastructure in grenade.sh to go and get *both*
# SOURCE and TARGET devstack trees. After which point we 'pivot' onto
# the TARGET devstack functions file, then source the rest of the
# grenade settings. This should let us run the bulk of grenade.
if [ "${GRENADE_USE_EXTERNAL_DEVSTACK}" != "True" ]; then
# Get both devstack trees, so that BASE_DEVSTACK_DIR, and
# TARGET_DEVSTACK_DIR are now fully populated.
fetch_devstacks
else
devstacks_setup_environment
fi
# Source the rest of the Grenade functions. For convenience
# ``$GRENADE_DIR/functions`` implicitly sources
# ``$TARGET_DEVSTACK_DIR/functions``. So this line can't happen until
# we have the devstacks pulled down.
source $GRENADE_DIR/functions
# We now have the 'short_source' function available, so setup our PS4 variable
export PS4='+ $(short_source): '
# Many calls inside of devstack functions reference $TOP_DIR, which is
# the root of devstack. We export $TOP_DIR to all child processes here
# to be the TARGET_DEVSTACK_DIR.
#
# If you want a script to use functions off of BASE_DEVSTACK_DIR (like
# the shutdown phase) you *must* explicitly reset TOP_DIR in those
# scripts.
export TOP_DIR=$TARGET_DEVSTACK_DIR
# Install 'Base' Build of OpenStack
# =================================
source $TARGET_DEVSTACK_DIR/inc/meta-config
# Oh the complexity of bootstrapping. We need to populate enabled
# services from what devstack-gate might have set it as.
extract_localrc_section $BASE_DEVSTACK_DIR/local.conf \
$BASE_DEVSTACK_DIR/localrc \
$BASE_DEVSTACK_DIR/.localrc.auto
# Collect the ENABLED_SERVICES from the base directory, this is what
# we are starting with.
ENABLED_SERVICES=$(set +o xtrace &&
source $BASE_DEVSTACK_DIR/stackrc &&
echo $ENABLED_SERVICES)
# Fetch all the grenade plugins which were registered in ``pluginrc``
# via the ``enable_grenade_plugin`` stanza. This must be done before
# settings are loaded, but has to be this late to give access to all
# the devstack functions.
fetch_grenade_plugins
# Load the ``settings`` files for all the in tree ``projects/``. This
# registers all the projects in order that we're going to be upgrading
# when the time is right.
load_settings
if [ "${GRENADE_USE_EXTERNAL_DEVSTACK}" != "True" ]; then
# Nova should use singleconductor as Grenade doesn't
# setup multi-cell rabbit for now
devstack_localrc base "CELLSV2_SETUP=singleconductor"
devstack_localrc target "CELLSV2_SETUP=singleconductor"
fi
# And ensure that we setup the target localrc.auto, because stack.sh
# isn't run there. This has to be run after load_settings because
# plugins might change the service list during this phase.
extract_localrc_section $TARGET_DEVSTACK_DIR/local.conf \
$TARGET_DEVSTACK_DIR/localrc \
$TARGET_DEVSTACK_DIR/.localrc.auto
# Run the base install of the environment
if [[ "$RUN_BASE" == "True" ]]; then
# Initialize grenade_db local storage, used for resource tracking
init_grenade_db
if [ "${GRENADE_USE_EXTERNAL_DEVSTACK}" != "True" ]; then
echo_summary "Running base stack.sh"
cd $BASE_DEVSTACK_DIR
GIT_BASE=$GIT_BASE ./stack.sh
stop $STOP stack.sh 10
echo_summary "Running post-stack.sh"
if [[ -e $GRENADE_DIR/post-stack.sh ]]; then
cd $GRENADE_DIR
# By the time we get here the sub nodes are already setup with localrc files
# as those are transferred in devstack-gate even before grenade.sh is called
# We hack the ./post-stack.sh to inject what we need. if we don't set
# CELLSV2_SETUP, the default devstack assumes "superconductor" and fails.
export SUB_NODE_ENV_VARS="CELLSV2_SETUP=singleconductor"
sed -i 's/stdbuf/$SUB_NODE_ENV_VARS stdbuf/' ./post-stack.sh
cat ./post-stack.sh
./post-stack.sh
stop $STOP post-stack.sh 15
echo_summary "Completed post-stack.sh"
fi
fi
# Cache downloaded instances
# --------------------------
echo_summary "Caching downloaded images"
mkdir -p $BASE_RELEASE_DIR/images
echo "Images: $IMAGE_URLS"
for image_url in ${IMAGE_URLS//,/ }; do
IMAGE_FNAME=`basename "$image_url"`
if [[ -r $BASE_DEVSTACK_DIR/files/$IMAGE_FNAME ]]; then
rsync -a $BASE_DEVSTACK_DIR/files/$IMAGE_FNAME $BASE_RELEASE_DIR/images
fi
done
# NOTE(sileht): If glance is not enabled the directory cannot exists.
if [[ -d $BASE_DEVSTACK_DIR/files/images ]] ; then
rsync -a $BASE_DEVSTACK_DIR/files/images/ $BASE_RELEASE_DIR/images
fi
stop $STOP image-cache 20
# Operation
# ---------
# Validate the install
if [[ "$BASE_RUN_SMOKE" == "True" ]]; then
echo_summary "Running base smoke test"
run_tempest $BASE_RELEASE_DIR
if [ "${GRENADE_USE_EXTERNAL_DEVSTACK}" != "True" ]; then
# once we are done, copy our created artifacts to the target
if [[ -e $TARGET_RELEASE_DIR/tempest ]]; then
rsync -a $BASE_RELEASE_DIR/tempest/.tox/ $TARGET_RELEASE_DIR/tempest/.tox/
if [[ -d $BASE_RELEASE_DIR/tempest/.testrepository ]]; then
rsync -a $BASE_RELEASE_DIR/tempest/.testrepository/ $TARGET_RELEASE_DIR/tempest/.testrepository/
elif [[ -d $BASE_RELEASE_DIR/tempest/.stestr ]]; then
rsync -a $BASE_RELEASE_DIR/tempest/.stestr/ $TARGET_RELEASE_DIR/tempest/.stestr/
fi
fi
fi
fi
stop $STOP base-smoke 110
# Early Create resources, used largely for network setup
resources early_create
# Create resources
resources create
# Verify the resources were created
resources verify pre-upgrade
# Save some stuff before we shut that whole thing down
echo_summary "Saving current state information"
$GRENADE_DIR/save-state
stop $STOP save-state 130
# Shut down running code
echo_summary "Shutting down all services on base devstack..."
shutdown_services
# Verify the resources still exist after the shutdown
resources verify_noapi pre-upgrade
fi
# Upgrades
# ========
if [[ "$RUN_TARGET" == "True" ]]; then
# Clone all devstack plugins on the new side, because we're not
# running a full stack.sh
fetch_plugins
# Get target devstack tree ready for services to be run from it,
# including trying to reuse any existing files we pulled during
# the base run.
echo_summary "Preparing the target devstack environment"
$GRENADE_DIR/prep-target
# upgrade all the projects in order
echo "Upgrade projects: $UPGRADE_PROJECTS"
for project in $UPGRADE_PROJECTS; do
echo "Upgrading project: $project"
upgrade_service $project
done
# Upgrade Tempest
if [[ "$ENABLE_TEMPEST" == "True" ]]; then
echo_summary "Running upgrade-tempest"
$GRENADE_DIR/upgrade-tempest || die $LINENO "Failure in upgrade-tempest"
stop $STOP upgrade-tempest 290
fi
# Upgrade Tests
# =============
# Verify the resources still exist after the upgrade
resources verify post-upgrade
# Validate the upgrade
# This is used for testing grenade locally, and should not be used in the
# gate. Instead, grenade.sh runs smoke tests on the old cloud above, but
# smoke tests are run on the upgraded cloud by the gate script after
# grenade.sh has finished. If this option is enabled in the gate, tempest
# will be run twice against the new cloud.
if [[ "$TARGET_RUN_SMOKE" == "True" ]]; then
echo_summary "Running tempest smoke tests"
run_tempest $TARGET_RELEASE_DIR
stop $STOP run-smoke 330
fi
# Save databases
# --------------
save_data $TARGET_RELEASE $TARGET_DEVSTACK_DIR
# Cleanup the resources
resources destroy
fi
# Fin
# ===
echo_summary "Grenade has completed the pre-programmed upgrade scripts."
# Indicate how long this took to run (bash maintained variable ``SECONDS``)
echo_summary "grenade.sh completed in $SECONDS seconds."