From 798824cab0322d9de82594dbbdb6c4ead0e1cb2f Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 2 Jul 2014 00:02:08 +0000 Subject: [PATCH] Allow setting a rootwrap cmd for functional tests Previously, sudo-requiring functional tests hardcoded the use of 'sudo' as the root helper. Devstack gate jobs do not allow password-less invocation of 'sudo', though, so such tests were unable to run in the gate. This patch adds the ability to configure the rootwrap command installed by devstack by setting the OS_ROOTWRAP_CMD environment variable in the test execution environment, allowing sudo-requiring tests to run. Change-Id: I3b8f6b4f14ac1743e08b9401f73951885165350a Partial-bug: #1336172 --- neutron/tests/functional/agent/linux/base.py | 21 +++----- .../agent/linux/test_ovsdb_monitor.py | 31 ++++++----- neutron/tests/functional/base.py | 53 +++++++++++++++++++ .../tests/functional/sanity/test_sanity.py | 11 +--- 4 files changed, 78 insertions(+), 38 deletions(-) create mode 100644 neutron/tests/functional/base.py diff --git a/neutron/tests/functional/agent/linux/base.py b/neutron/tests/functional/agent/linux/base.py index bdd718c85e1..5891c872e9f 100644 --- a/neutron/tests/functional/agent/linux/base.py +++ b/neutron/tests/functional/agent/linux/base.py @@ -12,36 +12,27 @@ # License for the specific language governing permissions and limitations # under the License. -import os import random from neutron.agent.linux import ovs_lib from neutron.agent.linux import utils from neutron.common import constants as n_const -from neutron.tests import base +from neutron.tests.functional import base as functional_base BR_PREFIX = 'test-br' -class BaseLinuxTestCase(base.BaseTestCase): - def setUp(self, root_helper='sudo'): - super(BaseLinuxTestCase, self).setUp() +class BaseLinuxTestCase(functional_base.BaseSudoTestCase): - self.root_helper = root_helper - - def check_command(self, cmd, error_text, skip_msg): + def check_command(self, cmd, error_text, skip_msg, root_helper=None): try: - utils.execute(cmd) + utils.execute(cmd, root_helper=root_helper) except RuntimeError as e: if error_text in str(e): self.skipTest(skip_msg) raise - def check_sudo_enabled(self): - if os.environ.get('OS_SUDO_TESTING') not in base.TRUE_STRING: - self.skipTest('testing with sudo is not enabled') - def get_rand_name(self, max_length, prefix='test'): name = prefix + str(random.randint(1, 0x7fffffff)) return name[:max_length] @@ -64,8 +55,8 @@ class BaseLinuxTestCase(base.BaseTestCase): class BaseOVSLinuxTestCase(BaseLinuxTestCase): - def setUp(self, root_helper='sudo'): - super(BaseOVSLinuxTestCase, self).setUp(root_helper) + def setUp(self): + super(BaseOVSLinuxTestCase, self).setUp() self.ovs = ovs_lib.BaseOVS(self.root_helper) def create_ovs_bridge(self, br_prefix=BR_PREFIX): diff --git a/neutron/tests/functional/agent/linux/test_ovsdb_monitor.py b/neutron/tests/functional/agent/linux/test_ovsdb_monitor.py index 35ad48d1cac..9d8570deda1 100644 --- a/neutron/tests/functional/agent/linux/test_ovsdb_monitor.py +++ b/neutron/tests/functional/agent/linux/test_ovsdb_monitor.py @@ -17,28 +17,30 @@ Tests in this module will be skipped unless: - ovsdb-client is installed - - ovsdb-client can be invoked via password-less sudo + - ovsdb-client can be invoked password-less via the configured root helper - - OS_SUDO_TESTING is set to '1' or 'True' in the test execution - environment - - -The jenkins gate does not allow direct sudo invocation during test -runs, but configuring OS_SUDO_TESTING ensures that developers are -still able to execute tests that require the capability. + - sudo testing is enabled (see neutron.tests.functional.base for details) """ import eventlet from neutron.agent.linux import ovsdb_monitor -from neutron.tests.functional.agent.linux import base as base_agent +from neutron.tests.functional.agent.linux import base as linux_base +from neutron.tests.functional import base as functional_base -class BaseMonitorTest(base_agent.BaseOVSLinuxTestCase): +class BaseMonitorTest(linux_base.BaseOVSLinuxTestCase): def setUp(self): - # Emulate using a rootwrap script with sudo - super(BaseMonitorTest, self).setUp(root_helper='sudo sudo') + super(BaseMonitorTest, self).setUp() + + rootwrap_not_configured = (self.root_helper == + functional_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.root_helper = '%s %s' % (self.root_helper, self.root_helper) self._check_test_requirements() self.bridge = self.create_ovs_bridge() @@ -47,9 +49,10 @@ class BaseMonitorTest(base_agent.BaseOVSLinuxTestCase): self.check_sudo_enabled() self.check_command(['which', 'ovsdb-client'], 'Exit code: 1', 'ovsdb-client is not installed') - self.check_command(['sudo', '-n', 'ovsdb-client', 'list-dbs'], + self.check_command(['ovsdb-client', 'list-dbs'], 'Exit code: 1', - 'password-less sudo not granted for ovsdb-client') + 'password-less sudo not granted for ovsdb-client', + root_helper=self.root_helper) class TestOvsdbMonitor(BaseMonitorTest): diff --git a/neutron/tests/functional/base.py b/neutron/tests/functional/base.py new file mode 100644 index 00000000000..471acaea64c --- /dev/null +++ b/neutron/tests/functional/base.py @@ -0,0 +1,53 @@ +# Copyright (c) 2014 OpenStack Foundation. +# All Rights Reserved. +# +# 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. + +import os + +from neutron.tests import base + + +SUDO_CMD = 'sudo -n' + + +class BaseSudoTestCase(base.BaseTestCase): + """ + Base class for tests requiring invocation of commands via a root helper. + + Inheritors of this class should call check_sudo_enabled() in + setUp() to ensure that tests requiring sudo are skipped unless + OS_SUDO_TESTING is set to '1' or 'True' in the test execution + environment. This is intended to allow developers to run the + functional suite (e.g. tox -e functional) without test failures if + sudo invocations are not allowed. + + Running sudo tests in the upstream gate jobs + (*-neutron-dsvm-functional) requires the additional step of + setting OS_ROOTWRAP_CMD to the rootwrap command configured by + devstack, e.g. + + sudo /usr/local/bin/neutron-rootwrap /etc/neutron/rootwrap.conf + + Gate jobs do not allow invocations of sudo without rootwrap to + ensure that rootwrap configuration gets as much testing as + possible. + """ + + def setUp(self): + super(BaseSudoTestCase, self).setUp() + self.root_helper = os.environ.get('OS_ROOTWRAP_CMD', SUDO_CMD) + + def check_sudo_enabled(self): + if os.environ.get('OS_SUDO_TESTING') not in base.TRUE_STRING: + self.skipTest('testing with sudo is not enabled') diff --git a/neutron/tests/functional/sanity/test_sanity.py b/neutron/tests/functional/sanity/test_sanity.py index be35484cb49..2873dc7a586 100644 --- a/neutron/tests/functional/sanity/test_sanity.py +++ b/neutron/tests/functional/sanity/test_sanity.py @@ -13,10 +13,9 @@ # License for the specific language governing permissions and limitations # under the License. -import os - from neutron.cmd.sanity import checks from neutron.tests import base +from neutron.tests.functional import base as functional_base class SanityTestCase(base.BaseTestCase): @@ -34,7 +33,7 @@ class SanityTestCase(base.BaseTestCase): checks.nova_notify_supported() -class SanityTestCaseRoot(base.BaseTestCase): +class SanityTestCaseRoot(functional_base.BaseSudoTestCase): """Sanity checks that require root access. Tests that just call checks.some_function() are to ensure that @@ -43,14 +42,8 @@ class SanityTestCaseRoot(base.BaseTestCase): """ def setUp(self): super(SanityTestCaseRoot, self).setUp() - - self.root_helper = 'sudo' self.check_sudo_enabled() - def check_sudo_enabled(self): - if os.environ.get('OS_SUDO_TESTING') not in base.TRUE_STRING: - self.skipTest('testing with sudo is not enabled') - def test_ovs_vxlan_support_runs(self): checks.vxlan_supported(self.root_helper)