From 540e4d791ff2573aae38810f4c39f2d6f46d8898 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 9 Jan 2015 15:02:59 +0000 Subject: [PATCH] Automate host configuration for functional testing This change adds a new script, configure_for_func_testing.sh, that automates configuration of a host to support functional testing. The script's functionality is consumed by a refactored version of gate_hook.sh, and both minimizes runtime and removes the previous dependency on the devstack-gate repo. Additionally, the dsvm-functional tox env is no longer dependent on devstack to deploy neutron's rootwrap configuration system-wide. Rootwrap configuration is now deployed to the target tox venv on each tox invocation. Change-Id: Iaf43be458bdf3c4535f95ee5a3a3b47a744020a0 --- TESTING.rst | 18 +- ...rs.template => functional-testing.filters} | 7 - neutron/tests/contrib/gate_hook.sh | 61 ++--- tools/configure_for_func_testing.sh | 249 ++++++++++++++++++ tools/deploy_rootwrap.sh | 56 ++++ tools/misc-sanity-checks.sh | 2 +- tox.ini | 3 +- 7 files changed, 340 insertions(+), 56 deletions(-) rename neutron/tests/contrib/{filters.template => functional-testing.filters} (66%) create mode 100755 tools/configure_for_func_testing.sh create mode 100755 tools/deploy_rootwrap.sh diff --git a/TESTING.rst b/TESTING.rst index d3b7795232f..6c9204d1b0f 100644 --- a/TESTING.rst +++ b/TESTING.rst @@ -119,11 +119,25 @@ specific-system dependencies:: tox -e functional -To run all the functional tests in an environment that has been configured -by devstack to support sudo and system-specific dependencies:: +To run all the functional tests, including those requiring sudo +privileges and system-specific dependencies, the procedure defined by +tools/configure_for_func_testing.sh should be followed. +IMPORTANT: configure_for_func_testing.sh relies on devstack to perform +extensive modification to the underlying host. Execution of the +script requires sudo privileges and it is recommended that the +following commands be invoked only on a clean and disposeable VM. A +VM that has had devstack previously installed on it is also fine. :: + + git clone https://git.openstack.org/openstack-dev/devstack ../devstack + ./tools/configure_for_func_testing.sh ../devstack -i tox -e dsvm-functional +The '-i' option is optional and instructs the script to use devstack +to install and configure all of Neutron's package dependencies. It is +not necessary to provide this option if devstack has already been used +to deploy Neutron to the target host. + For more information on the standard Tox-based test infrastructure used by OpenStack and how to do some common test/debugging procedures with Testr, see this wiki page: diff --git a/neutron/tests/contrib/filters.template b/neutron/tests/contrib/functional-testing.filters similarity index 66% rename from neutron/tests/contrib/filters.template rename to neutron/tests/contrib/functional-testing.filters index 45835118f8f..edfcec07ce4 100644 --- a/neutron/tests/contrib/filters.template +++ b/neutron/tests/contrib/functional-testing.filters @@ -4,13 +4,6 @@ # This file should be owned by (and only-writeable by) the root user [Filters] -# '$BASE_PATH' is intended to be replaced with the expected tox path -# (e.g. /opt/stack/new/neutron/.tox/dsvm-functional) by the neutron -# functional jenkins job. This ensures that tests can kill the -# processes that they launch with their containing tox environment's -# python. -kill_tox_python: KillFilter, root, $BASE_PATH/bin/python, -9 - # enable ping from namespace ping_filter: CommandFilter, ping, root diff --git a/neutron/tests/contrib/gate_hook.sh b/neutron/tests/contrib/gate_hook.sh index 67ec27ccc5b..0f93918a4be 100644 --- a/neutron/tests/contrib/gate_hook.sh +++ b/neutron/tests/contrib/gate_hook.sh @@ -1,58 +1,29 @@ #!/bin/bash + set -ex + venv=${1:-"dsvm-functional"} -CONTRIB_DIR="$BASE/new/neutron/neutron/tests/contrib" - -$BASE/new/devstack-gate/devstack-vm-gate.sh if [ "$venv" == "dsvm-functional" ] then - # Add a rootwrap filter to support test-only - # configuration (e.g. a KillFilter for processes that - # use the python installed in a tox env). - FUNC_FILTER=$CONTRIB_DIR/filters.template - sed -e "s+\$BASE_PATH+$BASE/new/neutron/.tox/dsvm-functional+" \ - $FUNC_FILTER | sudo tee /etc/neutron/rootwrap.d/functional.filters > /dev/null + # The following need to be set before sourcing + # configure_for_func_testing. + GATE_DEST=$BASE/new + GATE_STACK_USER=stack + NEUTRON_PATH=$GATE_DEST/neutron + DEVSTACK_PATH=$GATE_DEST/devstack + IS_GATE=True - # Use devstack functions to install mysql and psql servers - TOP_DIR=$BASE/new/devstack - source $TOP_DIR/functions - source $TOP_DIR/lib/config - source $TOP_DIR/stackrc - source $TOP_DIR/lib/database - source $TOP_DIR/localrc + source $NEUTRON_PATH/tools/configure_for_func_testing.sh - disable_service postgresql - enable_service mysql - initialize_database_backends - install_database + # Make the workspace owned by the stack user + sudo chown -R $STACK_USER:$STACK_USER $BASE - disable_service mysql - enable_service postgresql - initialize_database_backends - install_database - - # Set up the 'openstack_citest' user and database in each backend - tmp_dir=`mktemp -d` - - cat << EOF > $tmp_dir/mysql.sql -CREATE DATABASE openstack_citest; -CREATE USER 'openstack_citest'@'localhost' IDENTIFIED BY 'openstack_citest'; -CREATE USER 'openstack_citest' IDENTIFIED BY 'openstack_citest'; -GRANT ALL PRIVILEGES ON *.* TO 'openstack_citest'@'localhost'; -GRANT ALL PRIVILEGES ON *.* TO 'openstack_citest'; -FLUSH PRIVILEGES; -EOF - /usr/bin/mysql -u root < $tmp_dir/mysql.sql - - cat << EOF > $tmp_dir/postgresql.sql -CREATE USER openstack_citest WITH CREATEDB LOGIN PASSWORD 'openstack_citest'; -CREATE DATABASE openstack_citest WITH OWNER openstack_citest; -EOF - # User/group postgres needs to be given access to tmp_dir - setfacl -m g:postgres:rwx $tmp_dir - sudo -u postgres /usr/bin/psql --file=$tmp_dir/postgresql.sql + configure_host_for_func_testing $STACK_USER +elif [ "$venv" == "api" ] +then + $BASE/new/devstack-gate/devstack-vm-gate.sh fi diff --git a/tools/configure_for_func_testing.sh b/tools/configure_for_func_testing.sh new file mode 100755 index 00000000000..38c1ffe5b24 --- /dev/null +++ b/tools/configure_for_func_testing.sh @@ -0,0 +1,249 @@ +#!/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. + + +set -e + + +# Control variable used to determine whether to execute this script +# directly or allow the gate_hook to import. +IS_GATE=${IS_GATE:-False} + + +if [[ "$IS_GATE" != "True" ]] && [[ "$#" -lt 1 ]]; then + >&2 echo "Usage: $0 /path/to/devstack [-i] +Configure a host to run Neutron's functional test suite. + +-i Install Neutron's package dependencies. By default, it is assumed + that devstack has already been used to deploy neutron to the + target host and that package dependencies need not be installed. + +Warning: This script relies on devstack to perform extensive +modification to the underlying host. It is recommended that it be +invoked only on a throw-away VM." + exit 1 +fi + + +# Skip the first argument +OPTIND=2 +while getopts ":i" opt; do + case $opt in + i) + INSTALL_BASE_DEPENDENCIES=True + ;; + esac + +done + +# Default to environment variables to permit the gate_hook to override +# when sourcing. +DEVSTACK_PATH=${DEVSTACK_PATH:-$1} + # The gate should automatically install dependencies. +INSTALL_BASE_DEPENDENCIES=${INSTALL_BASE_DEPENDENCIES:-$IS_GATE} + + +if [ ! -f "$DEVSTACK_PATH/stack.sh" ]; then + >&2 echo "Unable to find devstack at '$DEVSTACK_PATH'. Please verify that the specified path points to a valid devstack repo." + exit 1 +fi + + +set -x + + +function _init { + NEUTRON_PATH=${NEUTRON_PATH:-$(cd $(dirname "$0")/.. && pwd)} + + # Subsequently-called devstack functions depend on the following variables. + HOST_IP=127.0.0.1 + FILES=$DEVSTACK_PATH/files + TOP_DIR=$DEVSTACK_PATH + + source $DEVSTACK_PATH/stackrc + + # Allow the gate to override values set by stackrc. + DEST=${GATE_DEST:-$DEST} + STACK_USER=${GATE_STACK_USER:-$STACK_USER} +} + + +function _install_base_deps { + echo_summary "Installing base dependencies" + + INSTALL_TESTONLY_PACKAGES=True + PACKAGES=$(get_packages general neutron,q-agt,q-l3) + # Do not install 'python-' prefixed packages other than + # python-dev*. Neutron's functional testing relies on deployment + # to a tox env so there is no point in installing python + # dependencies system-wide. + PACKAGES=$(echo $PACKAGES | perl -pe 's|python-(?!dev)[^ ]*||g') + install_package $PACKAGES +} + + +function _install_rpc_backend { + echo_summary "Installing rabbitmq" + + RABBIT_USERID=${RABBIT_USERID:-stackrabbit} + RABBIT_HOST=${RABBIT_HOST:-$SERVICE_HOST} + RABBIT_PASSWORD=${RABBIT_HOST:-secretrabbit} + + source $DEVSTACK_PATH/lib/rpc_backend + + enable_service rabbit + install_rpc_backend + restart_rpc_backend +} + + +function _install_databases { + echo_summary "Installing databases" + + # Avoid attempting to configure the db if it appears to already + # have run. The setup as currently defined is not idempotent. + if mysql openstack_citest > /dev/null 2>&1 < /dev/null; then + echo_summary "DB config appears to be complete, skipping." + return 0 + fi + + MYSQL_PASSWORD=${MYSQL_PASSWORD:-secretmysql} + DATABASE_PASSWORD=${DATABASE_PASSWORD:-secretdatabase} + + source $DEVSTACK_PATH/lib/database + + disable_service postgresql + enable_service mysql + initialize_database_backends + install_database + configure_database_mysql + + disable_service mysql + enable_service postgresql + initialize_database_backends + install_database + configure_database_postgresql + + # Set up the 'openstack_citest' user and database in each backend + tmp_dir=$(mktemp -d) + trap "rm -rf $tmp_dir" EXIT + + cat << EOF > $tmp_dir/mysql.sql +CREATE DATABASE openstack_citest; +CREATE USER 'openstack_citest'@'localhost' IDENTIFIED BY 'openstack_citest'; +CREATE USER 'openstack_citest' IDENTIFIED BY 'openstack_citest'; +GRANT ALL PRIVILEGES ON *.* TO 'openstack_citest'@'localhost'; +GRANT ALL PRIVILEGES ON *.* TO 'openstack_citest'; +FLUSH PRIVILEGES; +EOF + /usr/bin/mysql -u root < $tmp_dir/mysql.sql + + cat << EOF > $tmp_dir/postgresql.sql +CREATE USER openstack_citest WITH CREATEDB LOGIN PASSWORD 'openstack_citest'; +CREATE DATABASE openstack_citest WITH OWNER openstack_citest; +EOF + + # User/group postgres needs to be given access to tmp_dir + setfacl -m g:postgres:rwx $tmp_dir + sudo -u postgres /usr/bin/psql --file=$tmp_dir/postgresql.sql +} + + +function _install_agent_deps { + echo_summary "Installing agent dependencies" + + source $DEVSTACK_PATH/lib/neutron + + ENABLED_SERVICES=q-agt,q-dhcp,q-l3 + install_neutron_agent_packages +} + + +# Set up the rootwrap sudoers for neutron to target the rootwrap +# configuration deployed in the venv. +function _install_rootwrap_sudoers { + echo_summary "Installing rootwrap sudoers file" + + VENV_NAME=${venv:-dsvm-functional} + VENV_PATH=$NEUTRON_PATH/.tox/$VENV_NAME + ROOTWRAP_SUDOER_CMD="$VENV_PATH/bin/neutron-rootwrap $VENV_PATH/etc/neutron/rootwrap.conf *" + TEMPFILE=$(mktemp) + cat << EOF > $TEMPFILE +# A bug in oslo.rootwrap [1] prevents commands executed with 'ip netns +# exec' from being automatically qualified with a prefix from +# rootwrap's configured exec_dirs. To work around this problem, add +# the venv bin path to a user-specific secure_path. +# +# While it might seem preferable to set a command-specific +# secure_path, this would only ensure the correct path for 'ip netns +# exec' and the command targeted for execution in the namespace would +# not inherit the path. +# +# 1: https://bugs.launchpad.net/oslo.rootwrap/+bug/1417331 +# +Defaults:$STACK_USER secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$VENV_PATH/bin" +$STACK_USER ALL=(root) NOPASSWD: $ROOTWRAP_SUDOER_CMD +EOF + chmod 0440 $TEMPFILE + sudo chown root:root $TEMPFILE + # Name the functional testing rootwrap to ensure that it will be + # loaded after the devstack rootwrap (50_stack_sh if present) so + # that the functional testing secure_path (a superset of what + # devstack expects) will not be overwritten. + sudo mv $TEMPFILE /etc/sudoers.d/60-neutron-func-test-rootwrap +} + + +function _install_post_devstack { + echo_summary "Performing post-devstack installation" + + _install_databases + _install_rootwrap_sudoers + + # Installing python-openvswitch from packages is a stop-gap while + # python-openvswitch remains unavailable from pypi. This also + # requires that sitepackages=True be set in tox.ini to allow the + # venv to use the installed package. Once python-openvswitch + # becomes available on pypi, this will no longer be required. + # + # NOTE: the package name 'python-openvswitch' is common across + # supported distros. + install_package python-openvswitch + + # Configure ovs-vsctl to be reachable via the standard ovsdb port. + sudo ovs-vsctl set-manager ptcp:6640:127.0.0.1 +} + + +function configure_host_for_func_testing { + echo_summary "Configuring host for functional testing" + + if [[ "$INSTALL_BASE_DEPENDENCIES" == "True" ]]; then + # Installing of the following can be achieved via devstack by + # installing neutron, so their installation is conditional to + # minimize the work to do on a devstack-configured host. + _install_base_deps + _install_agent_deps + _install_rpc_backend + fi + _install_post_devstack +} + + +_init + + +if [[ "$IS_GATE" != "True" ]]; then + configure_host_for_func_testing +fi diff --git a/tools/deploy_rootwrap.sh b/tools/deploy_rootwrap.sh new file mode 100755 index 00000000000..dbe8ef705e4 --- /dev/null +++ b/tools/deploy_rootwrap.sh @@ -0,0 +1,56 @@ +#!/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. + +set -eu + +if [ "$#" -ne 3 ]; then + >&2 echo "Usage: $0 /path/to/neutron /path/to/target/etc /path/to/target/bin +Deploy Neutron's rootwrap configuration. + +Warning: Any existing rootwrap files at the specified etc path will be +removed by this script. + +Optional: set OS_SUDO_TESTING=1 to deploy the filters required by +Neutron's functional testing suite." + exit 1 +fi + +OS_SUDO_TESTING=${OS_SUDO_TESTING:-0} + +neutron_path=$1 +target_etc_path=$2 +target_bin_path=$3 + +src_conf_path=${neutron_path}/etc +src_conf=${src_conf_path}/rootwrap.conf +src_rootwrap_path=${src_conf_path}/neutron/rootwrap.d + +dst_conf_path=${target_etc_path}/neutron +dst_conf=${dst_conf_path}/rootwrap.conf +dst_rootwrap_path=${dst_conf_path}/rootwrap.d + +if [[ -d "$dst_rootwrap_path" ]]; then + rm -rf ${dst_rootwrap_path} +fi +mkdir -p -m 755 ${dst_rootwrap_path} + +cp -p ${src_rootwrap_path}/* ${dst_rootwrap_path}/ +cp -p ${src_conf} ${dst_conf} +sed -i "s:^filters_path=.*$:filters_path=${dst_rootwrap_path}:" ${dst_conf} +sed -i "s:^\(exec_dirs=.*\)$:\1,${target_bin_path}:" ${dst_conf} + +if [[ "$OS_SUDO_TESTING" = "1" ]]; then + cp -p ${neutron_path}/neutron/tests/contrib/functional-testing.filters \ + ${dst_rootwrap_path}/ +fi diff --git a/tools/misc-sanity-checks.sh b/tools/misc-sanity-checks.sh index 05480edc9a3..e049449828b 100644 --- a/tools/misc-sanity-checks.sh +++ b/tools/misc-sanity-checks.sh @@ -32,7 +32,7 @@ check_opinionated_shell () { # If you cannot avoid the use of bash, please change the EXPECTED var below. OBSERVED=$(grep -E '^([[:space:]]*[^#[:space:]]|#!).*bash' \ tox.ini tools/* | wc -l) - EXPECTED=4 + EXPECTED=6 if [ ${EXPECTED} -ne ${OBSERVED} ]; then echo "Bash usage has been detected!" >>$FAILURES fi diff --git a/tox.ini b/tox.ini index 3d1f62f44fd..b9590ffb4da 100644 --- a/tox.ini +++ b/tox.ini @@ -14,6 +14,7 @@ deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt whitelist_externals = sh commands = + dsvm-functional: {toxinidir}/tools/deploy_rootwrap.sh {toxinidir} {envdir}/etc {envbindir} sh tools/pretty_tox.sh '{posargs}' # there is also secret magic in pretty_tox.sh which lets you run in a fail only # mode. To do this define the TRACE_FAILONLY environmental variable. @@ -37,7 +38,7 @@ deps = [testenv:dsvm-functional] setenv = OS_TEST_PATH=./neutron/tests/functional OS_SUDO_TESTING=1 - OS_ROOTWRAP_CMD=sudo /usr/local/bin/neutron-rootwrap /etc/neutron/rootwrap.conf + OS_ROOTWRAP_CMD=sudo {envbindir}/neutron-rootwrap {envdir}/etc/neutron/rootwrap.conf OS_FAIL_ON_MISSING_DEPS=1 OS_TEST_TIMEOUT=90 sitepackages=True