Add configuration options and support for vlan and flat networking

This commit is contained in:
James Page 2014-11-10 17:11:14 +00:00
parent ed763bd834
commit 4c62002a99
6 changed files with 85 additions and 13 deletions

View File

@ -16,6 +16,12 @@ options:
traffic to the external public network. Valid values are either MAC traffic to the external public network. Valid values are either MAC
addresses (in which case only MAC addresses for interfaces without an IP addresses (in which case only MAC addresses for interfaces without an IP
address already assigned will be used), or interfaces (eth0) address already assigned will be used), or interfaces (eth0)
data-port:
type: string
default:
description: |
The data port will be added to br-data and will allow usage of flat or VLAN
network types with Neutron.
openstack-origin: openstack-origin:
type: string type: string
default: distro default: distro

View File

@ -169,10 +169,10 @@ class L3AgentContext(OSContextGenerator):
return ctxt return ctxt
class ExternalPortContext(OSContextGenerator): class NeutronPortContext(OSContextGenerator):
def __call__(self): def _resolve_port(self, config_key):
if not config('ext-port'): if not config(config_key):
return None return None
hwaddr_to_nic = {} hwaddr_to_nic = {}
hwaddr_to_ip = {} hwaddr_to_ip = {}
@ -183,7 +183,7 @@ class ExternalPortContext(OSContextGenerator):
get_ipv6_addr(iface=nic, fatal=False) get_ipv6_addr(iface=nic, fatal=False)
hwaddr_to_ip[hwaddr] = addresses hwaddr_to_ip[hwaddr] = addresses
mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I) mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I)
for entry in config('ext-port').split(): for entry in config(config_key).split():
entry = entry.strip() entry = entry.strip()
if re.match(mac_regex, entry): if re.match(mac_regex, entry):
if entry in hwaddr_to_nic and len(hwaddr_to_ip[entry]) == 0: if entry in hwaddr_to_nic and len(hwaddr_to_ip[entry]) == 0:
@ -192,12 +192,32 @@ class ExternalPortContext(OSContextGenerator):
continue continue
# Entry is a MAC address for a valid interface that doesn't # Entry is a MAC address for a valid interface that doesn't
# have an IP address assigned yet. # have an IP address assigned yet.
return {"ext_port": hwaddr_to_nic[entry]} return hwaddr_to_nic[entry]
else: else:
# If the passed entry is not a MAC address, assume it's a valid # If the passed entry is not a MAC address, assume it's a valid
# interface, and that the user put it there on purpose (we can # interface, and that the user put it there on purpose (we can
# trust it to be the real external network). # trust it to be the real external network).
return {"ext_port": entry} return entry
return None
class ExternalPortContext(NeutronPortContext):
def __call__(self):
port = self._resolve_port('ext-port')
if port:
return {"ext_port": port}
else:
return None
class DataPortContext(NeutronPortContext):
def __call__(self):
port = self._resolve_port('data-port')
if port:
return {"data_port": port}
else:
return None return None

View File

@ -46,6 +46,7 @@ from quantum_contexts import (
NetworkServiceContext, NetworkServiceContext,
L3AgentContext, L3AgentContext,
ExternalPortContext, ExternalPortContext,
DataPortContext,
remap_plugin remap_plugin
) )
@ -404,6 +405,7 @@ def restart_map():
INT_BRIDGE = "br-int" INT_BRIDGE = "br-int"
EXT_BRIDGE = "br-ex" EXT_BRIDGE = "br-ex"
DATA_BRIDGE = 'br-data'
DHCP_AGENT = "DHCP Agent" DHCP_AGENT = "DHCP Agent"
L3_AGENT = "L3 Agent" L3_AGENT = "L3 Agent"
@ -533,5 +535,11 @@ def configure_ovs():
add_bridge(INT_BRIDGE) add_bridge(INT_BRIDGE)
add_bridge(EXT_BRIDGE) add_bridge(EXT_BRIDGE)
ext_port_ctx = ExternalPortContext()() ext_port_ctx = ExternalPortContext()()
if ext_port_ctx is not None and ext_port_ctx['ext_port']: if ext_port_ctx and ext_port_ctx['ext_port']:
add_bridge_port(EXT_BRIDGE, ext_port_ctx['ext_port']) add_bridge_port(EXT_BRIDGE, ext_port_ctx['ext_port'])
add_bridge(DATA_BRIDGE)
data_port_ctx = DataPortContext()()
if data_port_ctx and data_port_ctx['data_port']:
add_bridge_port(DATA_BRIDGE, data_port_ctx['data_port'],
promisc=True)

View File

@ -3,18 +3,30 @@
# Configuration file maintained by Juju. Local changes may be overwritten. # Configuration file maintained by Juju. Local changes may be overwritten.
############################################################################### ###############################################################################
[ml2] [ml2]
type_drivers = gre,vxlan type_drivers = gre,vxlan,vlan,flat
tenant_network_types = gre,vxlan tenant_network_types = gre,vxlan,vlan,flat
mechanism_drivers = openvswitch,l2population mechanism_drivers = openvswitch,l2population
[ml2_type_gre] [ml2_type_gre]
tunnel_id_ranges = 1:1000 tunnel_id_ranges = 1:1000
[ml2_type_vxlan] [ml2_type_vxlan]
vni_ranges = 1001:2000 vni_ranges = 1001:2000
[ml2_type_vlan]
network_vlan_ranges = physnet1:1000:2000
[ml2_type_flat]
flat_networks = physnet1
[ovs] [ovs]
enable_tunneling = True enable_tunneling = True
local_ip = {{ local_ip }} local_ip = {{ local_ip }}
bridge_mappings = physnet1:br-data
[agent] [agent]
tunnel_types = {{ overlay_network_type }} tunnel_types = {{ overlay_network_type }}
l2_population = {{ l2_population }} l2_population = {{ l2_population }}
[securitygroup] [securitygroup]
firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver

View File

@ -117,10 +117,10 @@ class TestNetworkServiceContext(_TestQuantumContext):
} }
class TestExternalPortContext(CharmTestCase): class TestNeutronPortContext(CharmTestCase):
def setUp(self): def setUp(self):
super(TestExternalPortContext, self).setUp(quantum_contexts, super(TestNeutronPortContext, self).setUp(quantum_contexts,
TO_PATCH) TO_PATCH)
self.machine_macs = { self.machine_macs = {
'eth0': 'fe:c5:ce:8e:2b:00', 'eth0': 'fe:c5:ce:8e:2b:00',
@ -174,6 +174,11 @@ class TestExternalPortContext(CharmTestCase):
self.assertEquals(quantum_contexts.ExternalPortContext()(), self.assertEquals(quantum_contexts.ExternalPortContext()(),
{'ext_port': 'eth2'}) {'ext_port': 'eth2'})
def test_data_port_eth(self):
self.config.return_value = 'eth1010'
self.assertEquals(quantum_contexts.DataPortContext()(),
{'data_port': 'eth1010'})
class TestL3AgentContext(CharmTestCase): class TestL3AgentContext(CharmTestCase):

View File

@ -36,6 +36,7 @@ TO_PATCH = [
'service_running', 'service_running',
'NetworkServiceContext', 'NetworkServiceContext',
'ExternalPortContext', 'ExternalPortContext',
'DataPortContext',
'unit_private_ip', 'unit_private_ip',
'relations_of_type', 'relations_of_type',
'service_stop', 'service_stop',
@ -148,13 +149,33 @@ class TestQuantumUtils(CharmTestCase):
self.test_config.set('ext-port', 'eth0') self.test_config.set('ext-port', 'eth0')
self.ExternalPortContext.return_value = \ self.ExternalPortContext.return_value = \
DummyExternalPortContext(return_value={'ext_port': 'eth0'}) DummyExternalPortContext(return_value={'ext_port': 'eth0'})
self.DataPortContext.return_value = \
DummyExternalPortContext(return_value=None)
quantum_utils.configure_ovs() quantum_utils.configure_ovs()
self.add_bridge.assert_has_calls([ self.add_bridge.assert_has_calls([
call('br-int'), call('br-int'),
call('br-ex') call('br-ex'),
call('br-data')
]) ])
self.add_bridge_port.assert_called_with('br-ex', 'eth0') self.add_bridge_port.assert_called_with('br-ex', 'eth0')
def test_configure_ovs_ovs_data_port(self):
self.config.side_effect = self.test_config.get
self.test_config.set('plugin', 'ovs')
self.test_config.set('data-port', 'eth0')
self.ExternalPortContext.return_value = \
DummyExternalPortContext(return_value=None)
self.DataPortContext.return_value = \
DummyExternalPortContext(return_value={'data_port': 'eth0'})
quantum_utils.configure_ovs()
self.add_bridge.assert_has_calls([
call('br-int'),
call('br-ex'),
call('br-data')
])
self.add_bridge_port.assert_called_with('br-data', 'eth0',
promisc=True)
def test_do_openstack_upgrade(self): def test_do_openstack_upgrade(self):
self.config.side_effect = self.test_config.get self.config.side_effect = self.test_config.get
self.is_relation_made.return_value = False self.is_relation_made.return_value = False