Add fullstack resources for linuxbridge agent
This patch adds resources, fixtures and base test_connectivity tests for host with linuxbridge agent. Model of host with linuxbridge agent is made in separate namespace named "host-XXX". It has got connectivity with rabbit via ovs port. Same port is used also to provide connectivity with different "hosts" Co-Authored-By: Mathieu Rohon <mathieu.rohon@gmail.com> Change-Id: I6230d8d09f77bd20674bf6c3be69fbc1627d66f8 Closes-bug: #1518675
This commit is contained in:
parent
21d139d441
commit
2254acef06
@ -225,9 +225,12 @@ neutron/tests/fullstack/test_connectivity.py.
|
||||
|
||||
Full stack testing can simulate multi node testing by starting an agent
|
||||
multiple times. Specifically, each node would have its own copy of the
|
||||
OVS/DHCP/L3 agents, all configured with the same "host" value. Each OVS agent
|
||||
is connected to its own pair of br-int/br-ex, and those bridges are then
|
||||
interconnected.
|
||||
OVS/LinuxBridge/DHCP/L3 agents, all configured with the same "host" value.
|
||||
Each OVS agent is connected to its own pair of br-int/br-ex, and those bridges
|
||||
are then interconnected.
|
||||
For LinuxBridge agent each agent is started in its own namespace, called
|
||||
"host-<some_random_value>". Such namespaces are connected with OVS "central"
|
||||
bridge to eachother.
|
||||
|
||||
.. image:: images/fullstack_multinode_simulation.png
|
||||
|
||||
|
@ -21,3 +21,5 @@ VXLAN_MCAST = 'multicast_flooding'
|
||||
VXLAN_UCAST = 'unicast_flooding'
|
||||
|
||||
EXTENSION_DRIVER_TYPE = 'linuxbridge'
|
||||
|
||||
RESOURCE_ID_LENGTH = 11
|
||||
|
@ -128,11 +128,13 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase):
|
||||
return None
|
||||
return self.bridge_mappings.get(physical_network)
|
||||
|
||||
def get_bridge_name(self, network_id):
|
||||
@staticmethod
|
||||
def get_bridge_name(network_id):
|
||||
if not network_id:
|
||||
LOG.warning(_LW("Invalid Network ID, will lead to incorrect "
|
||||
"bridge name"))
|
||||
bridge_name = BRIDGE_NAME_PREFIX + network_id[0:11]
|
||||
bridge_name = BRIDGE_NAME_PREFIX + \
|
||||
network_id[:lconst.RESOURCE_ID_LENGTH]
|
||||
return bridge_name
|
||||
|
||||
def get_subinterface_name(self, physical_interface, vlan_id):
|
||||
@ -142,11 +144,13 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase):
|
||||
subinterface_name = '%s.%s' % (physical_interface, vlan_id)
|
||||
return subinterface_name
|
||||
|
||||
def get_tap_device_name(self, interface_id):
|
||||
@staticmethod
|
||||
def get_tap_device_name(interface_id):
|
||||
if not interface_id:
|
||||
LOG.warning(_LW("Invalid Interface ID, will lead to incorrect "
|
||||
"tap device name"))
|
||||
tap_device_name = constants.TAP_DEVICE_PREFIX + interface_id[0:11]
|
||||
tap_device_name = constants.TAP_DEVICE_PREFIX + \
|
||||
interface_id[:lconst.RESOURCE_ID_LENGTH]
|
||||
return tap_device_name
|
||||
|
||||
def get_vxlan_device_name(self, segmentation_id):
|
||||
|
@ -39,6 +39,8 @@ from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import utils
|
||||
from neutron.common import constants as n_const
|
||||
from neutron.db import db_base_plugin_common
|
||||
from neutron.plugins.ml2.drivers.linuxbridge.agent import \
|
||||
linuxbridge_neutron_agent as linuxbridge_agent
|
||||
from neutron.tests import base as tests_base
|
||||
from neutron.tests.common import base as common_base
|
||||
from neutron.tests import tools
|
||||
@ -47,11 +49,18 @@ UNDEFINED = object()
|
||||
|
||||
NS_PREFIX = 'test-'
|
||||
BR_PREFIX = 'test-br'
|
||||
PORT_PREFIX = 'test-port'
|
||||
PORT_PREFIX = 'port'
|
||||
VETH0_PREFIX = 'test-veth0'
|
||||
VETH1_PREFIX = 'test-veth1'
|
||||
PATCH_PREFIX = 'patch'
|
||||
|
||||
# port name should be shorter than DEVICE_NAME_MAX_LEN because if this
|
||||
# port is used to provide vlan connection between two linuxbridge
|
||||
# agents then place for vlan ID is also required, Vlan ID can take max 4 digits
|
||||
# and there is also additional "." in device name so it will in overall gives
|
||||
# DEVICE_NAME_MAX_LEN = 15 chars
|
||||
LB_DEVICE_NAME_MAX_LEN = 10
|
||||
|
||||
SS_SOURCE_PORT_PATTERN = re.compile(
|
||||
r'^.*\s+\d+\s+.*:(?P<port>\d+)\s+[0-9:].*')
|
||||
|
||||
@ -473,7 +482,7 @@ class VethFixture(fixtures.Fixture):
|
||||
"""Create a veth.
|
||||
|
||||
:ivar ports: created veth ports
|
||||
:type ports: IPDevice 2-uplet
|
||||
:type ports: tuple of 2 IPDevice
|
||||
"""
|
||||
|
||||
def _setUp(self):
|
||||
@ -508,6 +517,32 @@ class VethFixture(fixtures.Fixture):
|
||||
tools.fail('%s is not a valid VethFixture veth endpoint' % name)
|
||||
|
||||
|
||||
class NamedVethFixture(VethFixture):
|
||||
"""Create a veth with at least one specified name of a device
|
||||
|
||||
:ivar ports: created veth ports
|
||||
:type ports: tuple of 2 IPDevice
|
||||
"""
|
||||
|
||||
def __init__(self, veth0_prefix=VETH0_PREFIX, veth1_prefix=VETH1_PREFIX):
|
||||
super(NamedVethFixture, self).__init__()
|
||||
self.veth0_name = self.get_veth_name(veth0_prefix)
|
||||
self.veth1_name = self.get_veth_name(veth1_prefix)
|
||||
|
||||
def _setUp(self):
|
||||
ip_wrapper = ip_lib.IPWrapper()
|
||||
self.ports = ip_wrapper.add_veth(self.veth0_name, self.veth1_name)
|
||||
self.addCleanup(self.destroy)
|
||||
|
||||
@staticmethod
|
||||
def get_veth_name(name):
|
||||
if name.startswith(VETH0_PREFIX):
|
||||
return tests_base.get_rand_device_name(VETH0_PREFIX)
|
||||
if name.startswith(VETH1_PREFIX):
|
||||
return tests_base.get_rand_device_name(VETH1_PREFIX)
|
||||
return name
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class PortFixture(fixtures.Fixture):
|
||||
"""Create a port.
|
||||
@ -541,7 +576,7 @@ class PortFixture(fixtures.Fixture):
|
||||
if isinstance(bridge, ovs_lib.OVSBridge):
|
||||
return OVSPortFixture(bridge, namespace, mac, port_id)
|
||||
if isinstance(bridge, bridge_lib.BridgeDevice):
|
||||
return LinuxBridgePortFixture(bridge, namespace)
|
||||
return LinuxBridgePortFixture(bridge, namespace, mac, port_id)
|
||||
if isinstance(bridge, VethBridge):
|
||||
return VethPortFixture(bridge, namespace)
|
||||
tools.fail('Unexpected bridge type: %s' % type(bridge))
|
||||
@ -578,7 +613,13 @@ class OVSPortFixture(PortFixture):
|
||||
interface_config.register_opts(interface.OPTS)
|
||||
ovs_interface = interface.OVSInterfaceDriver(interface_config)
|
||||
|
||||
port_name = tests_base.get_rand_device_name(PORT_PREFIX)
|
||||
# because in some tests this port can be used to providing connection
|
||||
# between linuxbridge agents and vlan_id can be also added to this
|
||||
# device name it has to be max LB_DEVICE_NAME_MAX_LEN long
|
||||
port_name = tests_base.get_rand_name(
|
||||
LB_DEVICE_NAME_MAX_LEN,
|
||||
PORT_PREFIX
|
||||
)
|
||||
ovs_interface.plug_new(
|
||||
None,
|
||||
self.port_id,
|
||||
@ -598,22 +639,44 @@ class LinuxBridgeFixture(fixtures.Fixture):
|
||||
:ivar namespace: created bridge namespace
|
||||
:type namespace: str
|
||||
"""
|
||||
|
||||
def __init__(self, prefix=BR_PREFIX, namespace=UNDEFINED):
|
||||
def __init__(self, prefix=BR_PREFIX, namespace=UNDEFINED,
|
||||
prefix_is_full_name=False):
|
||||
super(LinuxBridgeFixture, self).__init__()
|
||||
self.prefix = prefix
|
||||
self.prefix_is_full_name = prefix_is_full_name
|
||||
self.namespace = namespace
|
||||
|
||||
def _setUp(self):
|
||||
if self.namespace is UNDEFINED:
|
||||
self.namespace = self.useFixture(NamespaceFixture()).name
|
||||
self.bridge = common_base.create_resource(
|
||||
self.prefix,
|
||||
bridge_lib.BridgeDevice.addbr,
|
||||
namespace=self.namespace)
|
||||
self.addCleanup(self.bridge.delbr)
|
||||
self.bridge = self._create_bridge()
|
||||
self.addCleanup(self.safe_delete)
|
||||
self.bridge.link.set_up()
|
||||
self.addCleanup(self.bridge.link.set_down)
|
||||
self.addCleanup(self.safe_set_down)
|
||||
|
||||
def safe_set_down(self):
|
||||
try:
|
||||
self.bridge.link.set_down()
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
def safe_delete(self):
|
||||
try:
|
||||
self.bridge.delbr()
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
def _create_bridge(self):
|
||||
if self.prefix_is_full_name:
|
||||
return bridge_lib.BridgeDevice.addbr(
|
||||
name=self.prefix,
|
||||
namespace=self.namespace
|
||||
)
|
||||
else:
|
||||
return common_base.create_resource(
|
||||
self.prefix,
|
||||
bridge_lib.BridgeDevice.addbr,
|
||||
namespace=self.namespace)
|
||||
|
||||
|
||||
class LinuxBridgePortFixture(PortFixture):
|
||||
@ -625,12 +688,29 @@ class LinuxBridgePortFixture(PortFixture):
|
||||
:type br_port: IPDevice
|
||||
"""
|
||||
|
||||
def __init__(self, bridge, namespace=None, mac=None, port_id=None):
|
||||
super(LinuxBridgePortFixture, self).__init__(
|
||||
bridge, namespace, mac, port_id)
|
||||
# we need to override port_id value here because in Port() class it is
|
||||
# always generated as random. In LinuxBridgePortFixture we need to have
|
||||
# it empty if it was not give because then proper veth_pair will be
|
||||
# created (for example in some functional tests)
|
||||
self.port_id = port_id
|
||||
|
||||
def _create_bridge_fixture(self):
|
||||
return LinuxBridgeFixture()
|
||||
|
||||
def _setUp(self):
|
||||
super(LinuxBridgePortFixture, self)._setUp()
|
||||
self.port, self.br_port = self.useFixture(VethFixture()).ports
|
||||
br_port_name = self._get_port_name()
|
||||
if br_port_name:
|
||||
self.br_port, self.port = self.useFixture(
|
||||
NamedVethFixture(veth0_prefix=br_port_name)).ports
|
||||
else:
|
||||
self.br_port, self.port = self.useFixture(VethFixture()).ports
|
||||
|
||||
if self.mac:
|
||||
self.port.link.set_address(self.mac)
|
||||
|
||||
# bridge side
|
||||
br_ip_wrapper = ip_lib.IPWrapper(self.bridge.namespace)
|
||||
@ -643,6 +723,12 @@ class LinuxBridgePortFixture(PortFixture):
|
||||
ns_ip_wrapper.add_device_to_namespace(self.port)
|
||||
self.port.link.set_up()
|
||||
|
||||
def _get_port_name(self):
|
||||
if self.port_id:
|
||||
return linuxbridge_agent.LinuxBridgeManager.get_tap_device_name(
|
||||
self.port_id)
|
||||
return None
|
||||
|
||||
|
||||
class VethBridge(object):
|
||||
|
||||
|
@ -88,7 +88,7 @@ class NeutronConfigFixture(ConfigFixture):
|
||||
'oslo_messaging_rabbit': {
|
||||
'rabbit_userid': rabbitmq_environment.user,
|
||||
'rabbit_password': rabbitmq_environment.password,
|
||||
'rabbit_hosts': '127.0.0.1',
|
||||
'rabbit_hosts': rabbitmq_environment.host,
|
||||
'rabbit_virtual_host': rabbitmq_environment.vhost,
|
||||
}
|
||||
})
|
||||
@ -114,14 +114,10 @@ class ML2ConfigFixture(ConfigFixture):
|
||||
super(ML2ConfigFixture, self).__init__(
|
||||
env_desc, host_desc, temp_dir, base_filename='ml2_conf.ini')
|
||||
|
||||
mechanism_drivers = 'openvswitch'
|
||||
if self.env_desc.l2_pop:
|
||||
mechanism_drivers += ',l2population'
|
||||
|
||||
self.config.update({
|
||||
'ml2': {
|
||||
'tenant_network_types': tenant_network_types,
|
||||
'mechanism_drivers': mechanism_drivers,
|
||||
'mechanism_drivers': self.mechanism_drivers,
|
||||
},
|
||||
'ml2_type_vlan': {
|
||||
'network_vlan_ranges': 'physnet1:1000:2999',
|
||||
@ -138,6 +134,16 @@ class ML2ConfigFixture(ConfigFixture):
|
||||
self.config['ml2']['extension_drivers'] =\
|
||||
qos_ext.QOS_EXT_DRIVER_ALIAS
|
||||
|
||||
@property
|
||||
def mechanism_drivers(self):
|
||||
mechanism_drivers = set(['openvswitch'])
|
||||
for host in self.host_desc:
|
||||
if host.l2_agent_type == constants.AGENT_TYPE_LINUXBRIDGE:
|
||||
mechanism_drivers.add('linuxbridge')
|
||||
if self.env_desc.l2_pop:
|
||||
mechanism_drivers.add('l2population')
|
||||
return ','.join(mechanism_drivers)
|
||||
|
||||
|
||||
class OVSConfigFixture(ConfigFixture):
|
||||
|
||||
@ -205,12 +211,59 @@ class OVSConfigFixture(ConfigFixture):
|
||||
return self.config.ovs.tunnel_bridge
|
||||
|
||||
|
||||
class LinuxBridgeConfigFixture(ConfigFixture):
|
||||
|
||||
def __init__(self, env_desc, host_desc, temp_dir, local_ip,
|
||||
physical_device_name):
|
||||
super(LinuxBridgeConfigFixture, self).__init__(
|
||||
env_desc, host_desc, temp_dir,
|
||||
base_filename="linuxbridge_agent.ini"
|
||||
)
|
||||
self.config.update({
|
||||
'VXLAN': {
|
||||
'enable_vxlan': str(self.env_desc.tunneling_enabled),
|
||||
'local_ip': local_ip,
|
||||
'l2_population': str(self.env_desc.l2_pop),
|
||||
}
|
||||
})
|
||||
if self.env_desc.tunneling_enabled:
|
||||
self.config.update({
|
||||
'LINUX_BRIDGE': {
|
||||
'bridge_mappings': self._generate_bridge_mappings(
|
||||
physical_device_name
|
||||
)
|
||||
}
|
||||
})
|
||||
else:
|
||||
self.config.update({
|
||||
'LINUX_BRIDGE': {
|
||||
'physical_interface_mappings':
|
||||
self._generate_bridge_mappings(
|
||||
physical_device_name
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
def _generate_bridge_mappings(self, device_name):
|
||||
return 'physnet1:%s' % device_name
|
||||
|
||||
|
||||
class L3ConfigFixture(ConfigFixture):
|
||||
|
||||
def __init__(self, env_desc, host_desc, temp_dir, integration_bridge):
|
||||
def __init__(self, env_desc, host_desc, temp_dir, integration_bridge=None):
|
||||
super(L3ConfigFixture, self).__init__(
|
||||
env_desc, host_desc, temp_dir, base_filename='l3_agent.ini')
|
||||
if host_desc.l2_agent_type == constants.AGENT_TYPE_OVS:
|
||||
self._prepare_config_with_ovs_agent(integration_bridge)
|
||||
elif host_desc.l2_agent_type == constants.AGENT_TYPE_LINUXBRIDGE:
|
||||
self._prepare_config_with_linuxbridge_agent()
|
||||
self.config['DEFAULT'].update({
|
||||
'debug': 'True',
|
||||
'verbose': 'True',
|
||||
'test_namespace_suffix': self._generate_namespace_suffix(),
|
||||
})
|
||||
|
||||
def _prepare_config_with_ovs_agent(self, integration_bridge):
|
||||
self.config.update({
|
||||
'DEFAULT': {
|
||||
'l3_agent_manager': ('neutron.agent.l3_agent.'
|
||||
@ -219,9 +272,14 @@ class L3ConfigFixture(ConfigFixture):
|
||||
'OVSInterfaceDriver'),
|
||||
'ovs_integration_bridge': integration_bridge,
|
||||
'external_network_bridge': self._generate_external_bridge(),
|
||||
'debug': 'True',
|
||||
'verbose': 'True',
|
||||
'test_namespace_suffix': self._generate_namespace_suffix(),
|
||||
}
|
||||
})
|
||||
|
||||
def _prepare_config_with_linuxbridge_agent(self):
|
||||
self.config.update({
|
||||
'DEFAULT': {
|
||||
'interface_driver': ('neutron.agent.linux.interface.'
|
||||
'BridgeInterfaceDriver'),
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -19,8 +19,12 @@ import netaddr
|
||||
from neutronclient.common import exceptions as nc_exc
|
||||
from oslo_config import cfg
|
||||
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import utils
|
||||
from neutron.common import constants
|
||||
from neutron.common import utils as common_utils
|
||||
from neutron.plugins.ml2.drivers.linuxbridge.agent import \
|
||||
linuxbridge_neutron_agent as lb_agent
|
||||
from neutron.tests.common import net_helpers
|
||||
from neutron.tests.fullstack.resources import config
|
||||
from neutron.tests.fullstack.resources import process
|
||||
@ -35,6 +39,7 @@ class EnvironmentDescription(object):
|
||||
self.network_type = network_type
|
||||
self.l2_pop = l2_pop
|
||||
self.qos = qos
|
||||
self.network_range = None
|
||||
|
||||
@property
|
||||
def tunneling_enabled(self):
|
||||
@ -47,7 +52,9 @@ class HostDescription(object):
|
||||
What agents should the host spawn? What mode should each agent operate
|
||||
under?
|
||||
"""
|
||||
def __init__(self, l3_agent=False, of_interface='ovs-ofctl'):
|
||||
def __init__(self, l3_agent=False, of_interface='ovs-ofctl',
|
||||
l2_agent_type=constants.AGENT_TYPE_OVS):
|
||||
self.l2_agent_type = l2_agent_type
|
||||
self.l3_agent = l3_agent
|
||||
self.of_interface = of_interface
|
||||
|
||||
@ -75,12 +82,29 @@ class Host(fixtures.Fixture):
|
||||
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.local_ip = self.allocate_local_ip()
|
||||
self.central_data_bridge = central_data_bridge
|
||||
self.central_external_bridge = central_external_bridge
|
||||
self.host_namespace = None
|
||||
self.agents = {}
|
||||
# we need to cache already created "per network" bridges if linuxbridge
|
||||
# agent is used on host:
|
||||
self.network_bridges = {}
|
||||
|
||||
def _setUp(self):
|
||||
if self.host_desc.l2_agent_type == constants.AGENT_TYPE_OVS:
|
||||
self.setup_host_with_ovs_agent()
|
||||
elif self.host_desc.l2_agent_type == constants.AGENT_TYPE_LINUXBRIDGE:
|
||||
self.setup_host_with_linuxbridge_agent()
|
||||
if self.host_desc.l3_agent:
|
||||
self.l3_agent = self.useFixture(
|
||||
process.L3AgentFixture(
|
||||
self.env_desc, self.host_desc,
|
||||
self.test_name,
|
||||
self.neutron_config,
|
||||
self.l3_agent_cfg_fixture))
|
||||
|
||||
def setup_host_with_ovs_agent(self):
|
||||
agent_cfg_fixture = config.OVSConfigFixture(
|
||||
self.env_desc, self.host_desc, self.neutron_config.temp_dir,
|
||||
self.local_ip)
|
||||
@ -103,21 +127,62 @@ class Host(fixtures.Fixture):
|
||||
self.test_name, self.neutron_config, agent_cfg_fixture))
|
||||
|
||||
if self.host_desc.l3_agent:
|
||||
l3_agent_cfg_fixture = self.useFixture(
|
||||
self.l3_agent_cfg_fixture = self.useFixture(
|
||||
config.L3ConfigFixture(
|
||||
self.env_desc, self.host_desc,
|
||||
self.neutron_config.temp_dir,
|
||||
self.ovs_agent.agent_cfg_fixture.get_br_int_name()))
|
||||
br_ex = self.useFixture(
|
||||
net_helpers.OVSBridgeFixture(
|
||||
l3_agent_cfg_fixture.get_external_bridge())).bridge
|
||||
self.l3_agent_cfg_fixture.get_external_bridge())).bridge
|
||||
self.connect_to_external_network(br_ex)
|
||||
self.l3_agent = self.useFixture(
|
||||
process.L3AgentFixture(
|
||||
|
||||
def setup_host_with_linuxbridge_agent(self):
|
||||
#First we need to provide connectivity for agent to prepare proper
|
||||
#bridge mappings in agent's config:
|
||||
self.host_namespace = self.useFixture(
|
||||
net_helpers.NamespaceFixture(prefix="host-")
|
||||
).name
|
||||
|
||||
self.connect_namespace_to_control_network()
|
||||
|
||||
agent_cfg_fixture = config.LinuxBridgeConfigFixture(
|
||||
self.env_desc, self.host_desc,
|
||||
self.neutron_config.temp_dir,
|
||||
self.local_ip,
|
||||
physical_device_name=self.host_port.name
|
||||
)
|
||||
self.useFixture(agent_cfg_fixture)
|
||||
|
||||
self.linuxbridge_agent = self.useFixture(
|
||||
process.LinuxBridgeAgentFixture(
|
||||
self.env_desc, self.host_desc,
|
||||
self.test_name, self.neutron_config, agent_cfg_fixture,
|
||||
namespace=self.host_namespace
|
||||
)
|
||||
)
|
||||
|
||||
if self.host_desc.l3_agent:
|
||||
self.l3_agent_cfg_fixture = self.useFixture(
|
||||
config.L3ConfigFixture(
|
||||
self.env_desc, self.host_desc,
|
||||
self.test_name,
|
||||
self.neutron_config,
|
||||
l3_agent_cfg_fixture))
|
||||
self.neutron_config.temp_dir))
|
||||
|
||||
def _connect_ovs_port(self, cidr_address):
|
||||
ovs_device = self.useFixture(
|
||||
net_helpers.OVSPortFixture(
|
||||
bridge=self.central_data_bridge,
|
||||
namespace=self.host_namespace)).port
|
||||
# NOTE: This sets an IP address on the host's root namespace
|
||||
# which is cleaned up when the device is deleted.
|
||||
ovs_device.addr.add(cidr_address)
|
||||
return ovs_device
|
||||
|
||||
def connect_namespace_to_control_network(self):
|
||||
self.host_port = self._connect_ovs_port(
|
||||
common_utils.ip_to_cidr(self.local_ip, 24)
|
||||
)
|
||||
self.host_port.link.set_up()
|
||||
|
||||
def connect_to_internal_network_via_tunneling(self):
|
||||
veth_1, veth_2 = self.useFixture(
|
||||
@ -140,6 +205,30 @@ class Host(fixtures.Fixture):
|
||||
net_helpers.create_patch_ports(
|
||||
self.central_external_bridge, host_external_bridge)
|
||||
|
||||
def allocate_local_ip(self):
|
||||
if not self.env_desc.network_range:
|
||||
return self.get_random_ip('240.0.0.1', '240.255.255.254')
|
||||
return self.get_random_ip(
|
||||
str(self.env_desc.network_range[2]),
|
||||
str(self.env_desc.network_range[-1])
|
||||
)
|
||||
|
||||
def get_bridge(self, network_id):
|
||||
if "ovs" in self.agents.keys():
|
||||
return self.ovs_agent.br_int
|
||||
elif "linuxbridge" in self.agents.keys():
|
||||
bridge = self.network_bridges.get(network_id, None)
|
||||
if not bridge:
|
||||
br_prefix = lb_agent.LinuxBridgeManager.get_bridge_name(
|
||||
network_id)
|
||||
bridge = self.useFixture(
|
||||
net_helpers.LinuxBridgeFixture(
|
||||
prefix=br_prefix,
|
||||
namespace=self.host_namespace,
|
||||
prefix_is_full_name=True)).bridge
|
||||
self.network_bridges[network_id] = bridge
|
||||
return bridge
|
||||
|
||||
@staticmethod
|
||||
def get_random_ip(low, high):
|
||||
parent_range = netaddr.IPRange(low, high)
|
||||
@ -165,6 +254,14 @@ class Host(fixtures.Fixture):
|
||||
def ovs_agent(self, agent):
|
||||
self.agents['ovs'] = agent
|
||||
|
||||
@property
|
||||
def linuxbridge_agent(self):
|
||||
return self.agents['linuxbridge']
|
||||
|
||||
@linuxbridge_agent.setter
|
||||
def linuxbridge_agent(self, agent):
|
||||
self.agents['linuxbridge'] = agent
|
||||
|
||||
|
||||
class Environment(fixtures.Fixture):
|
||||
"""Represents a deployment topology.
|
||||
@ -215,12 +312,21 @@ class Environment(fixtures.Fixture):
|
||||
def _setUp(self):
|
||||
self.temp_dir = self.useFixture(fixtures.TempDir()).path
|
||||
|
||||
#we need this bridge before rabbit and neutron service will start
|
||||
self.central_data_bridge = self.useFixture(
|
||||
net_helpers.OVSBridgeFixture('cnt-data')).bridge
|
||||
self.central_external_bridge = self.useFixture(
|
||||
net_helpers.OVSBridgeFixture('cnt-ex')).bridge
|
||||
|
||||
#Get rabbitmq address (and cnt-data network)
|
||||
rabbitmq_ip_address = self._configure_port_for_rabbitmq()
|
||||
self.rabbitmq_environment = self.useFixture(
|
||||
process.RabbitmqEnvironmentFixture())
|
||||
process.RabbitmqEnvironmentFixture(host=rabbitmq_ip_address)
|
||||
)
|
||||
|
||||
plugin_cfg_fixture = self.useFixture(
|
||||
config.ML2ConfigFixture(
|
||||
self.env_desc, None, self.temp_dir,
|
||||
self.env_desc, self.hosts_desc, self.temp_dir,
|
||||
self.env_desc.network_type))
|
||||
neutron_cfg_fixture = self.useFixture(
|
||||
config.NeutronConfigFixture(
|
||||
@ -231,11 +337,34 @@ class Environment(fixtures.Fixture):
|
||||
self.env_desc, None,
|
||||
self.test_name, neutron_cfg_fixture, plugin_cfg_fixture))
|
||||
|
||||
self.central_data_bridge = self.useFixture(
|
||||
net_helpers.OVSBridgeFixture('cnt-data')).bridge
|
||||
self.central_external_bridge = self.useFixture(
|
||||
net_helpers.OVSBridgeFixture('cnt-ex')).bridge
|
||||
|
||||
self.hosts = [self._create_host(desc) for desc in self.hosts_desc]
|
||||
|
||||
self.wait_until_env_is_up()
|
||||
|
||||
def _configure_port_for_rabbitmq(self):
|
||||
self.env_desc.network_range = self._get_network_range()
|
||||
if not self.env_desc.network_range:
|
||||
return "127.0.0.1"
|
||||
rabbitmq_ip = str(self.env_desc.network_range[1])
|
||||
rabbitmq_port = ip_lib.IPDevice(self.central_data_bridge.br_name)
|
||||
rabbitmq_port.addr.add(common_utils.ip_to_cidr(rabbitmq_ip, 24))
|
||||
rabbitmq_port.link.set_up()
|
||||
|
||||
return rabbitmq_ip
|
||||
|
||||
def _get_network_range(self):
|
||||
#NOTE(slaweq): We need to choose IP address on which rabbitmq will be
|
||||
# available because LinuxBridge agents are spawned in their own
|
||||
# namespaces and need to know where the rabbitmq server is listening.
|
||||
# For ovs agent it is not necessary because agents are spawned in
|
||||
# globalscope together with rabbitmq server so default localhost
|
||||
# address is fine for them
|
||||
for desc in self.hosts_desc:
|
||||
if desc.l2_agent_type == constants.AGENT_TYPE_LINUXBRIDGE:
|
||||
return self.get_random_network(
|
||||
"240.0.0.0", "240.255.255.255", "24")
|
||||
|
||||
@staticmethod
|
||||
def get_random_network(low, high, netmask):
|
||||
ip = Host.get_random_ip(low, high)
|
||||
return netaddr.IPNetwork("%s/%s" % (ip, netmask))
|
||||
|
@ -20,11 +20,11 @@ from neutron.tests.common import net_helpers
|
||||
|
||||
|
||||
class FakeFullstackMachine(machine_fixtures.FakeMachineBase):
|
||||
|
||||
def __init__(self, host, network_id, tenant_id, safe_client,
|
||||
neutron_port=None):
|
||||
super(FakeFullstackMachine, self).__init__()
|
||||
self.bridge = host.ovs_agent.br_int
|
||||
self.host_binding = host.hostname
|
||||
self.host = host
|
||||
self.tenant_id = tenant_id
|
||||
self.network_id = network_id
|
||||
self.safe_client = safe_client
|
||||
@ -33,18 +33,19 @@ class FakeFullstackMachine(machine_fixtures.FakeMachineBase):
|
||||
def _setUp(self):
|
||||
super(FakeFullstackMachine, self)._setUp()
|
||||
|
||||
self.bridge = self.host.get_bridge(self.network_id)
|
||||
|
||||
if not self.neutron_port:
|
||||
self.neutron_port = self.safe_client.create_port(
|
||||
network_id=self.network_id,
|
||||
tenant_id=self.tenant_id,
|
||||
hostname=self.host_binding)
|
||||
self.neutron_port_id = self.neutron_port['id']
|
||||
hostname=self.host.hostname)
|
||||
mac_address = self.neutron_port['mac_address']
|
||||
|
||||
self.port = self.useFixture(
|
||||
net_helpers.PortFixture.get(
|
||||
self.bridge, self.namespace, mac_address,
|
||||
self.neutron_port_id)).port
|
||||
self.neutron_port['id'])).port
|
||||
|
||||
self._ip = self.neutron_port['fixed_ips'][0]['ip_address']
|
||||
subnet_id = self.neutron_port['fixed_ips'][0]['subnet_id']
|
||||
@ -69,6 +70,6 @@ class FakeFullstackMachine(machine_fixtures.FakeMachineBase):
|
||||
|
||||
def block_until_boot(self):
|
||||
utils.wait_until_true(
|
||||
lambda: (self.safe_client.client.show_port(self.neutron_port_id)
|
||||
lambda: (self.safe_client.client.show_port(self.neutron_port['id'])
|
||||
['port']['status'] == 'ACTIVE'),
|
||||
sleep=3)
|
||||
|
@ -36,7 +36,7 @@ DEFAULT_LOG_DIR = '/tmp/dsvm-fullstack-logs/'
|
||||
|
||||
class ProcessFixture(fixtures.Fixture):
|
||||
def __init__(self, test_name, process_name, exec_name, config_filenames,
|
||||
kill_signal=signal.SIGKILL):
|
||||
namespace=None, kill_signal=signal.SIGKILL):
|
||||
super(ProcessFixture, self).__init__()
|
||||
self.test_name = test_name
|
||||
self.process_name = process_name
|
||||
@ -44,6 +44,7 @@ class ProcessFixture(fixtures.Fixture):
|
||||
self.config_filenames = config_filenames
|
||||
self.process = None
|
||||
self.kill_signal = kill_signal
|
||||
self.namespace = namespace
|
||||
|
||||
def _setUp(self):
|
||||
self.start()
|
||||
@ -62,7 +63,10 @@ class ProcessFixture(fixtures.Fixture):
|
||||
'--log-file', log_file]
|
||||
for filename in self.config_filenames:
|
||||
cmd += ['--config-file', filename]
|
||||
self.process = async_process.AsyncProcess(cmd)
|
||||
run_as_root = bool(self.namespace)
|
||||
self.process = async_process.AsyncProcess(
|
||||
cmd, run_as_root=run_as_root, namespace=self.namespace
|
||||
)
|
||||
self.process.start(block=True)
|
||||
|
||||
def stop(self):
|
||||
@ -71,6 +75,10 @@ class ProcessFixture(fixtures.Fixture):
|
||||
|
||||
class RabbitmqEnvironmentFixture(fixtures.Fixture):
|
||||
|
||||
def __init__(self, host="127.0.0.1"):
|
||||
super(RabbitmqEnvironmentFixture, self).__init__()
|
||||
self.host = host
|
||||
|
||||
def _setUp(self):
|
||||
self.user = base.get_rand_name(prefix='user')
|
||||
self.password = base.get_rand_name(prefix='pass')
|
||||
@ -97,6 +105,7 @@ class NeutronServerFixture(fixtures.Fixture):
|
||||
|
||||
def __init__(self, env_desc, host_desc,
|
||||
test_name, neutron_cfg_fixture, plugin_cfg_fixture):
|
||||
super(NeutronServerFixture, self).__init__()
|
||||
self.env_desc = env_desc
|
||||
self.host_desc = host_desc
|
||||
self.test_name = test_name
|
||||
@ -136,6 +145,7 @@ class OVSAgentFixture(fixtures.Fixture):
|
||||
|
||||
def __init__(self, env_desc, host_desc,
|
||||
test_name, neutron_cfg_fixture, agent_cfg_fixture):
|
||||
super(OVSAgentFixture, self).__init__()
|
||||
self.env_desc = env_desc
|
||||
self.host_desc = host_desc
|
||||
self.test_name = test_name
|
||||
@ -161,31 +171,69 @@ class OVSAgentFixture(fixtures.Fixture):
|
||||
config_filenames=config_filenames))
|
||||
|
||||
|
||||
class LinuxBridgeAgentFixture(fixtures.Fixture):
|
||||
|
||||
NEUTRON_LINUXBRIDGE_AGENT = "neutron-linuxbridge-agent"
|
||||
|
||||
def __init__(self, env_desc, host_desc, test_name,
|
||||
neutron_cfg_fixture, agent_cfg_fixture,
|
||||
namespace=None):
|
||||
super(LinuxBridgeAgentFixture, self).__init__()
|
||||
self.env_desc = env_desc
|
||||
self.host_desc = host_desc
|
||||
self.test_name = test_name
|
||||
self.neutron_cfg_fixture = neutron_cfg_fixture
|
||||
self.neutron_config = self.neutron_cfg_fixture.config
|
||||
self.agent_cfg_fixture = agent_cfg_fixture
|
||||
self.agent_config = agent_cfg_fixture.config
|
||||
self.namespace = namespace
|
||||
|
||||
def _setUp(self):
|
||||
config_filenames = [self.neutron_cfg_fixture.filename,
|
||||
self.agent_cfg_fixture.filename]
|
||||
|
||||
self.process_fixture = self.useFixture(
|
||||
ProcessFixture(
|
||||
test_name=self.test_name,
|
||||
process_name=self.NEUTRON_LINUXBRIDGE_AGENT,
|
||||
exec_name=self.NEUTRON_LINUXBRIDGE_AGENT,
|
||||
config_filenames=config_filenames,
|
||||
namespace=self.namespace
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class L3AgentFixture(fixtures.Fixture):
|
||||
|
||||
NEUTRON_L3_AGENT = "neutron-l3-agent"
|
||||
|
||||
def __init__(self, env_desc, host_desc,
|
||||
test_name, neutron_cfg_fixture, l3_agent_cfg_fixture):
|
||||
def __init__(self, env_desc, host_desc, test_name,
|
||||
neutron_cfg_fixture, l3_agent_cfg_fixture,
|
||||
namespace=None):
|
||||
super(L3AgentFixture, self).__init__()
|
||||
self.env_desc = env_desc
|
||||
self.host_desc = host_desc
|
||||
self.test_name = test_name
|
||||
self.neutron_cfg_fixture = neutron_cfg_fixture
|
||||
self.l3_agent_cfg_fixture = l3_agent_cfg_fixture
|
||||
self.namespace = namespace
|
||||
|
||||
def _setUp(self):
|
||||
self.plugin_config = self.l3_agent_cfg_fixture.config
|
||||
|
||||
config_filenames = [self.neutron_cfg_fixture.filename,
|
||||
self.l3_agent_cfg_fixture.filename]
|
||||
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(base.ROOTDIR, 'common', 'agents')),
|
||||
config_filenames=config_filenames))
|
||||
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(base.ROOTDIR, 'common', 'agents')),
|
||||
config_filenames=config_filenames,
|
||||
namespace=self.namespace
|
||||
)
|
||||
)
|
||||
|
||||
def get_namespace_suffix(self):
|
||||
return self.plugin_config.DEFAULT.test_namespace_suffix
|
||||
|
@ -15,6 +15,7 @@
|
||||
from oslo_utils import uuidutils
|
||||
import testscenarios
|
||||
|
||||
from neutron.common import constants
|
||||
from neutron.tests.fullstack import base
|
||||
from neutron.tests.fullstack.resources import environment
|
||||
from neutron.tests.fullstack.resources import machine
|
||||
@ -23,20 +24,7 @@ from neutron.tests.fullstack.resources import machine
|
||||
load_tests = testscenarios.load_tests_apply_scenarios
|
||||
|
||||
|
||||
class TestConnectivitySameNetwork(base.BaseFullStackTestCase):
|
||||
|
||||
network_scenarios = [
|
||||
('VXLAN', {'network_type': 'vxlan',
|
||||
'l2_pop': False}),
|
||||
('GRE and l2pop', {'network_type': 'gre',
|
||||
'l2_pop': True}),
|
||||
('VLANs', {'network_type': 'vlan',
|
||||
'l2_pop': False})]
|
||||
interface_scenarios = [
|
||||
('Ofctl', {'of_interface': 'ovs-ofctl'}),
|
||||
('Native', {'of_interface': 'native'})]
|
||||
scenarios = testscenarios.multiply_scenarios(
|
||||
network_scenarios, interface_scenarios)
|
||||
class BaseConnectivitySameNetworkTest(base.BaseFullStackTestCase):
|
||||
|
||||
def setUp(self):
|
||||
host_descriptions = [
|
||||
@ -45,15 +33,16 @@ class TestConnectivitySameNetwork(base.BaseFullStackTestCase):
|
||||
# agent types present on machines.
|
||||
environment.HostDescription(
|
||||
l3_agent=self.l2_pop,
|
||||
of_interface=self.of_interface) for _ in range(3)]
|
||||
of_interface=self.of_interface,
|
||||
l2_agent_type=self.l2_agent_type) for _ in range(3)]
|
||||
env = environment.Environment(
|
||||
environment.EnvironmentDescription(
|
||||
network_type=self.network_type,
|
||||
l2_pop=self.l2_pop),
|
||||
host_descriptions)
|
||||
super(TestConnectivitySameNetwork, self).setUp(env)
|
||||
super(BaseConnectivitySameNetworkTest, self).setUp(env)
|
||||
|
||||
def test_connectivity(self):
|
||||
def _test_connectivity(self):
|
||||
tenant_uuid = uuidutils.generate_uuid()
|
||||
|
||||
network = self.safe_client.create_network(tenant_uuid)
|
||||
@ -75,3 +64,40 @@ class TestConnectivitySameNetwork(base.BaseFullStackTestCase):
|
||||
vms[0].block_until_ping(vms[1].ip)
|
||||
vms[0].block_until_ping(vms[2].ip)
|
||||
vms[1].block_until_ping(vms[2].ip)
|
||||
|
||||
|
||||
class TestOvsConnectivitySameNetwork(BaseConnectivitySameNetworkTest):
|
||||
|
||||
l2_agent_type = constants.AGENT_TYPE_OVS
|
||||
network_scenarios = [
|
||||
('VXLAN', {'network_type': 'vxlan',
|
||||
'l2_pop': False}),
|
||||
('GRE and l2pop', {'network_type': 'gre',
|
||||
'l2_pop': True}),
|
||||
('VLANs', {'network_type': 'vlan',
|
||||
'l2_pop': False})]
|
||||
interface_scenarios = [
|
||||
('Ofctl', {'of_interface': 'ovs-ofctl'}),
|
||||
('Native', {'of_interface': 'native'})]
|
||||
scenarios = testscenarios.multiply_scenarios(
|
||||
network_scenarios, interface_scenarios)
|
||||
|
||||
def test_connectivity(self):
|
||||
self._test_connectivity()
|
||||
|
||||
|
||||
class TestLinuxBridgeConnectivitySameNetwork(BaseConnectivitySameNetworkTest):
|
||||
|
||||
l2_agent_type = constants.AGENT_TYPE_LINUXBRIDGE
|
||||
scenarios = [
|
||||
('VXLAN', {'network_type': 'vxlan',
|
||||
'l2_pop': False}),
|
||||
('VLANs', {'network_type': 'vlan',
|
||||
'l2_pop': False}),
|
||||
('VXLAN and l2pop', {'network_type': 'vxlan',
|
||||
'l2_pop': True})
|
||||
]
|
||||
of_interface = None
|
||||
|
||||
def test_connectivity(self):
|
||||
self._test_connectivity()
|
||||
|
@ -245,6 +245,15 @@ function _install_post_devstack {
|
||||
}
|
||||
|
||||
|
||||
function _configure_iptables_rules {
|
||||
# For linuxbridge agent fullstack tests we need to add special rules to
|
||||
# iptables for connection of agents to rabbitmq:
|
||||
CHAIN_NAME="openstack-INPUT"
|
||||
sudo iptables -n --list $CHAIN_NAME 1> /dev/null 2>&1 || CHAIN_NAME="INPUT"
|
||||
sudo iptables -I $CHAIN_NAME -s 240.0.0.0/8 -p tcp -m tcp -d 240.0.0.0/8 --dport 5672 -j ACCEPT
|
||||
}
|
||||
|
||||
|
||||
function configure_host_for_func_testing {
|
||||
echo_summary "Configuring host for functional testing"
|
||||
|
||||
@ -270,3 +279,7 @@ if [[ "$IS_GATE" != "True" ]]; then
|
||||
configure_host_for_func_testing
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$VENV" =~ "dsvm-fullstack" ]]; then
|
||||
_configure_iptables_rules
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user