From a99897ffb3e3a1247006b21103b54a71123a6b50 Mon Sep 17 00:00:00 2001 From: Ihar Hrachyshka Date: Mon, 5 Jun 2017 18:54:39 +0000 Subject: [PATCH] Use rootwrap for fullstack test runner We plan to switch to devstack-gate for fullstack job, and it revokes direct sudo calls before executing tests, so we can't rely on sudo working anymore. This also moves functional-testing.filters to a more generic filename (testing.filters) because the filters are now deployed and used by fullstack target too. Related-Bug: #1557168 Related-Bug: #1693689 Change-Id: I1718ea51836adbb8ef8dea79822a722dcf111127 --- neutron/tests/base.py | 11 ++++++ ...tional-testing.filters => testing.filters} | 10 +++++ neutron/tests/fullstack/base.py | 4 ++ neutron/tests/fullstack/resources/process.py | 38 +++++++++++++------ .../agent/linux/test_ovsdb_monitor.py | 7 ++-- neutron/tests/functional/base.py | 10 +---- tools/configure_for_func_testing.sh | 8 +++- tools/deploy_rootwrap.sh | 6 ++- 8 files changed, 67 insertions(+), 27 deletions(-) rename neutron/tests/contrib/{functional-testing.filters => testing.filters} (82%) diff --git a/neutron/tests/base.py b/neutron/tests/base.py index a462a261ff7..b2f2850e7ab 100644 --- a/neutron/tests/base.py +++ b/neutron/tests/base.py @@ -45,6 +45,7 @@ from neutron.api.rpc.callbacks.consumer import registry as rpc_consumer_reg from neutron.api.rpc.callbacks.producer import registry as rpc_producer_reg from neutron.common import config from neutron.common import rpc as n_rpc +from neutron.conf.agent import common as agent_config from neutron.db import _model_query as model_query from neutron.db import _resource_extend as resource_extend from neutron.db import agentschedulers_db @@ -63,6 +64,8 @@ CONF.import_opt('state_path', 'neutron.conf.common') ROOTDIR = os.path.dirname(__file__) ETCDIR = os.path.join(ROOTDIR, 'etc') +SUDO_CMD = 'sudo -n' + def etcdir(*p): return os.path.join(ETCDIR, *p) @@ -406,6 +409,14 @@ class BaseTestCase(DietTestCase): notification_driver = [fake_notifier.__name__] cfg.CONF.set_override("notification_driver", notification_driver) + def setup_rootwrap(self): + agent_config.register_root_helper(cfg.CONF) + self.config(group='AGENT', + root_helper=os.environ.get('OS_ROOTWRAP_CMD', SUDO_CMD)) + self.config(group='AGENT', + root_helper_daemon=os.environ.get( + 'OS_ROOTWRAP_DAEMON_CMD')) + class PluginFixture(fixtures.Fixture): diff --git a/neutron/tests/contrib/functional-testing.filters b/neutron/tests/contrib/testing.filters similarity index 82% rename from neutron/tests/contrib/functional-testing.filters rename to neutron/tests/contrib/testing.filters index edc97b15e6e..e345a975e3f 100644 --- a/neutron/tests/contrib/functional-testing.filters +++ b/neutron/tests/contrib/testing.filters @@ -44,3 +44,13 @@ process_spawn: EnvFilter, env, root, PATH=, python ip_exec: IpNetnsExecFilter, ip, root ps: CommandFilter, ps, root pid_kill: RegExpFilter, kill, root, kill, -\d+, .* + +#needed to set up fullstack 'multinode' environment +rabbitmqctl: CommandFilter, rabbitmqctl, root +linuxbridge_agent: CommandFilter, neutron-linuxbridge-agent, root +dhcp_agent: CommandFilter, dhcp_agent.py, root +ovs_agent: CommandFilter, ovs_agent.py, root +l3_agent: CommandFilter, l3_agent.py, root + +#needed to capture and analyze traffic in fullstack tests (f.e. in DSCP scenarios) +tcpdump: CommandFilter, tcpdump, root diff --git a/neutron/tests/fullstack/base.py b/neutron/tests/fullstack/base.py index d950491abae..e66c6e62fe5 100644 --- a/neutron/tests/fullstack/base.py +++ b/neutron/tests/fullstack/base.py @@ -57,6 +57,10 @@ class BaseFullStackTestCase(testlib_api.MySQLTestCaseMixin, # since the latter starts services that may rely on generated port # numbers tools.reset_random_seed() + + # configure test runner to use rootwrap + self.setup_rootwrap() + self.environment = environment self.environment.test_name = self.get_name() self.useFixture(self.environment) diff --git a/neutron/tests/fullstack/resources/process.py b/neutron/tests/fullstack/resources/process.py index 1508eae3257..5ff305507ac 100644 --- a/neutron/tests/fullstack/resources/process.py +++ b/neutron/tests/fullstack/resources/process.py @@ -59,12 +59,13 @@ class ProcessFixture(fixtures.Fixture): timestamp = datetime.datetime.now().strftime("%Y-%m-%d--%H-%M-%S-%f") log_file = "%s--%s.log" % (self.process_name, timestamp) - cmd = [spawn.find_executable(self.exec_name), - '--log-dir', log_dir, - '--log-file', log_file] + run_as_root = bool(self.namespace) + exec_name = (self.exec_name + if run_as_root + else spawn.find_executable(self.exec_name)) + cmd = [exec_name, '--log-dir', log_dir, '--log-file', log_file] for filename in self.config_filenames: cmd += ['--config-file', filename] - run_as_root = bool(self.namespace) self.process = async_process.AsyncProcess( cmd, run_as_root=run_as_root, namespace=self.namespace ) @@ -261,13 +262,21 @@ class L3AgentFixture(ServiceFixture): config_filenames = [self.neutron_cfg_fixture.filename, self.l3_agent_cfg_fixture.filename] + + # if we execute in namespace as root, then allow rootwrap to find the + # executable, otherwise construct full path ourselves + if self.namespace: + exec_name = 'l3_agent.py' + else: + exec_name = spawn.find_executable( + 'l3_agent.py', + path=os.path.join(fullstack_base.ROOTDIR, 'cmd')) + self.process_fixture = self.useFixture( ProcessFixture( test_name=self.test_name, process_name=self.NEUTRON_L3_AGENT, - exec_name=spawn.find_executable( - 'l3_agent.py', - path=os.path.join(fullstack_base.ROOTDIR, 'cmd')), + exec_name=exec_name, config_filenames=config_filenames, namespace=self.namespace ) @@ -296,14 +305,21 @@ class DhcpAgentFixture(fixtures.Fixture): config_filenames = [self.neutron_cfg_fixture.filename, self.agent_cfg_fixture.filename] + + # if we execute in namespace as root, then allow rootwrap to find the + # executable, otherwise construct full path ourselves + if self.namespace: + exec_name = 'dhcp_agent.py' + else: + exec_name = spawn.find_executable( + 'dhcp_agent.py', + path=os.path.join(fullstack_base.ROOTDIR, 'cmd')) + self.process_fixture = self.useFixture( ProcessFixture( test_name=self.test_name, process_name=self.NEUTRON_DHCP_AGENT, - exec_name=spawn.find_executable( - 'dhcp_agent.py', - path=os.path.join( - fullstack_base.ROOTDIR, 'cmd')), + exec_name=exec_name, config_filenames=config_filenames, namespace=self.namespace ) diff --git a/neutron/tests/functional/agent/linux/test_ovsdb_monitor.py b/neutron/tests/functional/agent/linux/test_ovsdb_monitor.py index 6450934436c..e644e68f2d2 100644 --- a/neutron/tests/functional/agent/linux/test_ovsdb_monitor.py +++ b/neutron/tests/functional/agent/linux/test_ovsdb_monitor.py @@ -27,9 +27,9 @@ from oslo_config import cfg from neutron.agent.common import ovs_lib from neutron.agent.linux import ovsdb_monitor from neutron.common import utils +from neutron.tests import base from neutron.tests.common import net_helpers from neutron.tests.functional.agent.linux import base as linux_base -from neutron.tests.functional import base as functional_base class BaseMonitorTest(linux_base.BaseOVSLinuxTestCase): @@ -37,14 +37,13 @@ class BaseMonitorTest(linux_base.BaseOVSLinuxTestCase): def setUp(self): super(BaseMonitorTest, self).setUp() - rootwrap_not_configured = (cfg.CONF.AGENT.root_helper == - functional_base.SUDO_CMD) + rootwrap_not_configured = (cfg.CONF.AGENT.root_helper == base.SUDO_CMD) if rootwrap_not_configured: # The monitor tests require a nested invocation that has # to be emulated by double sudo if rootwrap is not # configured. self.config(group='AGENT', - root_helper=" ".join([functional_base.SUDO_CMD] * 2)) + root_helper=" ".join([base.SUDO_CMD] * 2)) self._check_test_requirements() # ovsdb-client monitor needs to have a bridge to make any output diff --git a/neutron/tests/functional/base.py b/neutron/tests/functional/base.py index 08d5f58f3ca..76a9fe24da4 100644 --- a/neutron/tests/functional/base.py +++ b/neutron/tests/functional/base.py @@ -23,8 +23,6 @@ from neutron.tests import base from neutron.tests.common import base as common_base from neutron.tests.common import helpers -SUDO_CMD = 'sudo -n' - # This is the directory from which infra fetches log files for functional tests DEFAULT_LOG_DIR = os.path.join(helpers.get_test_log_path(), 'dsvm-functional-logs') @@ -62,13 +60,7 @@ class BaseSudoTestCase(BaseLoggingTestCase): super(BaseSudoTestCase, self).setUp() if not base.bool_from_env('OS_SUDO_TESTING'): self.skipTest('Testing with sudo is not enabled') - - config.register_root_helper(cfg.CONF) - self.config(group='AGENT', - root_helper=os.environ.get('OS_ROOTWRAP_CMD', SUDO_CMD)) - self.config(group='AGENT', - root_helper_daemon=os.environ.get( - 'OS_ROOTWRAP_DAEMON_CMD')) + self.setup_rootwrap() config.setup_privsep() @common_base.no_skip_on_missing_deps diff --git a/tools/configure_for_func_testing.sh b/tools/configure_for_func_testing.sh index 10d80d275ae..78d9438d92b 100755 --- a/tools/configure_for_func_testing.sh +++ b/tools/configure_for_func_testing.sh @@ -188,6 +188,12 @@ function _install_rootwrap_sudoers { ROOTWRAP_SUDOER_CMD="$PROJECT_VENV/bin/neutron-rootwrap $PROJECT_VENV/etc/neutron/rootwrap.conf *" ROOTWRAP_DAEMON_SUDOER_CMD="$PROJECT_VENV/bin/neutron-rootwrap-daemon $PROJECT_VENV/etc/neutron/rootwrap.conf" TEMPFILE=$(mktemp) + + SECURE_PATH="$PROJECT_VENV/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + if [[ "$VENV" =~ "dsvm-fullstack" ]]; then + SECURE_PATH="$REPO_BASE/$PROJECT_NAME/neutron/tests/fullstack/cmd:$SECURE_PATH" + fi + cat << EOF > $TEMPFILE # A bug in oslo.rootwrap [1] prevents commands executed with 'ip netns # exec' from being automatically qualified with a prefix from @@ -201,7 +207,7 @@ function _install_rootwrap_sudoers { # # 1: https://bugs.launchpad.net/oslo.rootwrap/+bug/1417331 # -Defaults:$STACK_USER secure_path="$PROJECT_VENV/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +Defaults:$STACK_USER secure_path="$SECURE_PATH" $STACK_USER ALL=(root) NOPASSWD: $ROOTWRAP_SUDOER_CMD $STACK_USER ALL=(root) NOPASSWD: $ROOTWRAP_DAEMON_SUDOER_CMD EOF diff --git a/tools/deploy_rootwrap.sh b/tools/deploy_rootwrap.sh index 9edbf1493eb..91d7d6b0c15 100755 --- a/tools/deploy_rootwrap.sh +++ b/tools/deploy_rootwrap.sh @@ -32,6 +32,8 @@ neutron_path=$1 target_etc_path=$2 target_bin_path=$3 +fullstack_path=$neutron_path/neutron/tests/fullstack/cmd + src_conf_path=${neutron_path}/etc src_conf=${src_conf_path}/rootwrap.conf src_rootwrap_path=${src_conf_path}/neutron/rootwrap.d @@ -48,11 +50,11 @@ 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} +sed -i "s:^\(exec_dirs=.*\)$:\1,${target_bin_path},${fullstack_path}:" ${dst_conf} if [[ "$OS_SUDO_TESTING" = "1" ]]; then sed -i 's/use_syslog=False/use_syslog=True/g' ${dst_conf} sed -i 's/syslog_log_level=ERROR/syslog_log_level=DEBUG/g' ${dst_conf} - cp -p ${neutron_path}/neutron/tests/contrib/functional-testing.filters \ + cp -p ${neutron_path}/neutron/tests/contrib/testing.filters \ ${dst_rootwrap_path}/ fi