From a885c4075ad983b8d68c4843359fa3578c48b575 Mon Sep 17 00:00:00 2001 From: Assaf Muller Date: Tue, 16 Jun 2015 08:56:41 -0400 Subject: [PATCH] Add tunneling support to full stack tests * EnvironmentDescription class now accepts 'network_type'. It sets the ML2 segmentation type, passes it to the OVS agents configuration files, and sets up the host configuration. If tunnelling type is selected, it sets up a veth pair with an IP address from the 240.0.0.1+ range. The addressed end of this pair is configured as the local_ip for tunneling purposes in each of the OVS agents. If network type is not tunnelled, it sets up provider bridges instead and interconnects them. * For now we run the basic L3 HA test with VLANs and tunneling just so we have something to show for. * I started using scenarios in fullstack tests to run the same test with VLANs or tunneling, and because test names are used for log dirs, and testscenarios changes test names to include characters that are not shell friendly (Space, parenthesis), I 'sanitized' some of those characters. Change-Id: Ic45cc27396452111678cf85ab26b07275846ce44 --- doc/source/devref/fullstack_testing.rst | 9 ++-- neutron/tests/base.py | 2 +- neutron/tests/fullstack/resources/config.py | 31 ++++++++++-- .../tests/fullstack/resources/environment.py | 49 ++++++++++++++++--- neutron/tests/fullstack/resources/process.py | 4 +- neutron/tests/fullstack/test_connectivity.py | 14 +++++- neutron/tests/fullstack/test_l3_agent.py | 10 ++-- 7 files changed, 97 insertions(+), 22 deletions(-) diff --git a/doc/source/devref/fullstack_testing.rst b/doc/source/devref/fullstack_testing.rst index f1ff581dc..5467f74f4 100644 --- a/doc/source/devref/fullstack_testing.rst +++ b/doc/source/devref/fullstack_testing.rst @@ -83,6 +83,12 @@ When? stack testing can help here as the full stack infrastructure can restart an agent during the test. +Prerequisites +------------- + +Fullstack test suite assumes 240.0.0.0/3 range in root namespace of the test +machine is available for its usage. + Short Term Goals ---------------- @@ -103,9 +109,6 @@ the fact as there will probably be something to copy/paste from. Long Term Goals --------------- -* Currently we configure the OVS agent with VLANs segmentation (Only because - it's easier). This allows us to validate most functionality, but we might - need to support tunneling somehow. * How will advanced services use the full stack testing infrastructure? Full stack tests infrastructure classes are expected to change quite a bit over the next coming months. This means that other repositories may import these diff --git a/neutron/tests/base.py b/neutron/tests/base.py index 86f08544f..cd79f3eeb 100644 --- a/neutron/tests/base.py +++ b/neutron/tests/base.py @@ -104,7 +104,7 @@ def get_test_timeout(default=0): def sanitize_log_path(path): - # Sanitize the string so that it's log path is shell friendly + # Sanitize the string so that its log path is shell friendly return path.replace(' ', '-').replace('(', '_').replace(')', '_') diff --git a/neutron/tests/fullstack/resources/config.py b/neutron/tests/fullstack/resources/config.py index c4efa8197..215f4909d 100644 --- a/neutron/tests/fullstack/resources/config.py +++ b/neutron/tests/fullstack/resources/config.py @@ -178,16 +178,16 @@ class ML2ConfigFixture(ConfigFixture): class OVSConfigFixture(ConfigFixture): - def __init__(self, env_desc, host_desc, temp_dir): + def __init__(self, env_desc, host_desc, temp_dir, local_ip): super(OVSConfigFixture, self).__init__( env_desc, host_desc, temp_dir, base_filename='openvswitch_agent.ini') + self.tunneling_enabled = self.env_desc.tunneling_enabled self.config.update({ 'ovs': { - 'enable_tunneling': 'False', - 'local_ip': '127.0.0.1', - 'bridge_mappings': self._generate_bridge_mappings(), + 'enable_tunneling': str(self.tunneling_enabled), + 'local_ip': local_ip, 'integration_bridge': self._generate_integration_bridge(), }, 'securitygroup': { @@ -196,18 +196,41 @@ class OVSConfigFixture(ConfigFixture): } }) + if self.tunneling_enabled: + self.config['agent'] = { + 'tunnel_types': self.env_desc.network_type} + self.config['ovs'].update({ + 'tunnel_bridge': self._generate_tunnel_bridge(), + 'int_peer_patch_port': self._generate_int_peer(), + 'tun_peer_patch_port': self._generate_tun_peer()}) + else: + self.config['ovs']['bridge_mappings'] = ( + self._generate_bridge_mappings()) + def _generate_bridge_mappings(self): return 'physnet1:%s' % base.get_rand_device_name(prefix='br-eth') def _generate_integration_bridge(self): return base.get_rand_device_name(prefix='br-int') + def _generate_tunnel_bridge(self): + return base.get_rand_device_name(prefix='br-tun') + + def _generate_int_peer(self): + return base.get_rand_device_name(prefix='patch-tun') + + def _generate_tun_peer(self): + return base.get_rand_device_name(prefix='patch-int') + def get_br_int_name(self): return self.config.ovs.integration_bridge def get_br_phys_name(self): return self.config.ovs.bridge_mappings.split(':')[1] + def get_br_tun_name(self): + return self.config.ovs.tunnel_bridge + class L3ConfigFixture(ConfigFixture): diff --git a/neutron/tests/fullstack/resources/environment.py b/neutron/tests/fullstack/resources/environment.py index 67660f813..7a0d67e6a 100644 --- a/neutron/tests/fullstack/resources/environment.py +++ b/neutron/tests/fullstack/resources/environment.py @@ -12,12 +12,16 @@ # License for the specific language governing permissions and limitations # under the License. +import random + import fixtures +import netaddr from neutronclient.common import exceptions as nc_exc from oslo_config import cfg from oslo_log import log as logging from neutron.agent.linux import utils +from neutron.common import utils as common_utils from neutron.tests.common import net_helpers from neutron.tests.fullstack.resources import config from neutron.tests.fullstack.resources import process @@ -30,7 +34,12 @@ class EnvironmentDescription(object): Does the setup, as a whole, support tunneling? How about l2pop? """ - pass + def __init__(self, network_type='vxlan'): + self.network_type = network_type + + @property + def tunneling_enabled(self): + return self.network_type in ('vxlan', 'gre') class HostDescription(object): @@ -65,19 +74,28 @@ class Host(fixtures.Fixture): self.host_desc = host_desc self.test_name = test_name self.neutron_config = neutron_config + # Use reserved class E addresses + self.local_ip = self.get_random_ip('240.0.0.1', '255.255.255.254') self.central_data_bridge = central_data_bridge self.central_external_bridge = central_external_bridge self.agents = {} def _setUp(self): agent_cfg_fixture = config.OVSConfigFixture( - self.env_desc, self.host_desc, self.neutron_config.temp_dir) + self.env_desc, self.host_desc, self.neutron_config.temp_dir, + self.local_ip) self.useFixture(agent_cfg_fixture) - br_phys = self.useFixture( - net_helpers.OVSBridgeFixture( - agent_cfg_fixture.get_br_phys_name())).bridge - self.connect_to_internal_network_via_vlans(br_phys) + if self.env_desc.tunneling_enabled: + self.useFixture( + net_helpers.OVSBridgeFixture( + agent_cfg_fixture.get_br_tun_name())).bridge + self.connect_to_internal_network_via_tunneling() + else: + br_phys = self.useFixture( + net_helpers.OVSBridgeFixture( + agent_cfg_fixture.get_br_phys_name())).bridge + self.connect_to_internal_network_via_vlans(br_phys) self.ovs_agent = self.useFixture( process.OVSAgentFixture( @@ -101,6 +119,17 @@ class Host(fixtures.Fixture): self.neutron_config, l3_agent_cfg_fixture)) + def connect_to_internal_network_via_tunneling(self): + veth_1, veth_2 = self.useFixture( + net_helpers.VethFixture()).ports + + # NOTE: This sets an IP address on the host's root namespace + # which is cleaned up when the device is deleted. + veth_1.addr.add(common_utils.ip_to_cidr(self.local_ip, 32)) + + veth_1.link.set_up() + veth_2.link.set_up() + def connect_to_internal_network_via_vlans(self, host_data_bridge): # If using VLANs as a segmentation device, it's needed to connect # a provider bridge to a centralized, shared bridge. @@ -111,6 +140,11 @@ class Host(fixtures.Fixture): net_helpers.create_patch_ports( self.central_external_bridge, host_external_bridge) + @staticmethod + def get_random_ip(low, high): + parent_range = netaddr.IPRange(low, high) + return str(random.choice(parent_range)) + @property def hostname(self): return self.neutron_config.config.DEFAULT.host @@ -186,7 +220,8 @@ class Environment(fixtures.Fixture): plugin_cfg_fixture = self.useFixture( config.ML2ConfigFixture( - self.env_desc, None, self.temp_dir, 'vlan')) + self.env_desc, None, self.temp_dir, + self.env_desc.network_type)) neutron_cfg_fixture = self.useFixture( config.NeutronConfigFixture( self.env_desc, None, self.temp_dir, diff --git a/neutron/tests/fullstack/resources/process.py b/neutron/tests/fullstack/resources/process.py index 0d6a8bd73..3c1a4db6c 100644 --- a/neutron/tests/fullstack/resources/process.py +++ b/neutron/tests/fullstack/resources/process.py @@ -47,7 +47,9 @@ class ProcessFixture(fixtures.Fixture): self.addCleanup(self.stop) def start(self): - log_dir = os.path.join(DEFAULT_LOG_DIR, self.test_name) + test_name = base.sanitize_log_path(self.test_name) + + log_dir = os.path.join(DEFAULT_LOG_DIR, test_name) common_utils.ensure_dir(log_dir) timestamp = datetime.datetime.now().strftime("%Y-%m-%d--%H-%M-%S-%f") diff --git a/neutron/tests/fullstack/test_connectivity.py b/neutron/tests/fullstack/test_connectivity.py index b0f546a3e..ed72221b5 100644 --- a/neutron/tests/fullstack/test_connectivity.py +++ b/neutron/tests/fullstack/test_connectivity.py @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +import testscenarios + from oslo_utils import uuidutils from neutron.tests.fullstack import base @@ -19,13 +21,21 @@ from neutron.tests.fullstack.resources import environment from neutron.tests.fullstack.resources import machine +load_tests = testscenarios.load_tests_apply_scenarios + + class TestConnectivitySameNetwork(base.BaseFullStackTestCase): + scenarios = [('VXLAN', {'network_type': 'vxlan'}), + ('VLANs', {'network_type': 'vlan'})] + def setUp(self): host_descriptions = [ environment.HostDescription() for _ in range(2)] - env = environment.Environment(environment.EnvironmentDescription(), - host_descriptions) + env = environment.Environment( + environment.EnvironmentDescription( + network_type=self.network_type), + host_descriptions) super(TestConnectivitySameNetwork, self).setUp(env) def test_connectivity(self): diff --git a/neutron/tests/fullstack/test_l3_agent.py b/neutron/tests/fullstack/test_l3_agent.py index 28f2419b8..2a0814fff 100644 --- a/neutron/tests/fullstack/test_l3_agent.py +++ b/neutron/tests/fullstack/test_l3_agent.py @@ -28,8 +28,9 @@ class TestLegacyL3Agent(base.BaseFullStackTestCase): def setUp(self): host_descriptions = [environment.HostDescription(l3_agent=True)] - env = environment.Environment(environment.EnvironmentDescription(), - host_descriptions) + env = environment.Environment( + environment.EnvironmentDescription(network_type='vlan'), + host_descriptions) super(TestLegacyL3Agent, self).setUp(env) def _get_namespace(self, router_id): @@ -59,8 +60,9 @@ class TestHAL3Agent(base.BaseFullStackTestCase): def setUp(self): host_descriptions = [ environment.HostDescription(l3_agent=True) for _ in range(2)] - env = environment.Environment(environment.EnvironmentDescription(), - host_descriptions) + env = environment.Environment( + environment.EnvironmentDescription(network_type='vxlan'), + host_descriptions) super(TestHAL3Agent, self).setUp(env) def _is_ha_router_active_on_one_agent(self, router_id): -- 2.45.2