diff --git a/doc/source/devref/fullstack_testing.rst b/doc/source/devref/fullstack_testing.rst index f1ff581dc35..5467f74f43e 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 86f08544f9c..cd79f3eebbf 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 c4efa8197f2..215f4909dbd 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 67660f813b7..7a0d67e6a16 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 0d6a8bd73f0..3c1a4db6cbf 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 b0f546a3eb3..ed72221b527 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 28f2419b878..2a0814fff93 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):