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
This commit is contained in:
Assaf Muller 2015-06-16 08:56:41 -04:00 committed by Ihar Hrachyshka
parent cd4d889374
commit a885c4075a
7 changed files with 97 additions and 22 deletions

View File

@ -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

View File

@ -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(')', '_')

View File

@ -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):

View File

@ -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,

View File

@ -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")

View File

@ -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):

View File

@ -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):