From 84163f18440a7403a4838d64da4b1ce601d7e1ed Mon Sep 17 00:00:00 2001 From: Zhang Hua Date: Thu, 4 Dec 2014 11:41:12 +0800 Subject: [PATCH 01/43] enable network-device-mtu --- hooks/neutron_ovs_context.py | 2 ++ templates/icehouse/neutron.conf | 3 ++- unit_tests/test_neutron_ovs_context.py | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 7dbf5211..43952c52 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -36,6 +36,7 @@ def _neutron_api_settings(): 'l2_population': rdata['l2-population'], 'neutron_security_groups': rdata['neutron-security-groups'], 'overlay_network_type': rdata['overlay-network-type'], + 'network_device_mtu': rdata['network-device-mtu'], } # Override with configuration if set to true if config('disable-security-groups'): @@ -103,6 +104,7 @@ class OVSPluginContext(context.NeutronContext): neutron_api_settings = _neutron_api_settings() ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups ovs_ctxt['l2_population'] = neutron_api_settings['l2_population'] + ovs_ctxt['network_device_mtu'] = neutron_api_settings['network_device_mtu'] ovs_ctxt['overlay_network_type'] = \ neutron_api_settings['overlay_network_type'] # TODO: We need to sort out the syslog and debug/verbose options as a diff --git a/templates/icehouse/neutron.conf b/templates/icehouse/neutron.conf index 964f6dce..c7af465a 100644 --- a/templates/icehouse/neutron.conf +++ b/templates/icehouse/neutron.conf @@ -1,4 +1,4 @@ -# grizzly +# icehouse ############################################################################### # [ WARNING ] # Configuration file maintained by Juju. Local changes may be overwritten. @@ -12,6 +12,7 @@ state_path = /var/lib/neutron lock_path = $state_path/lock bind_host = 0.0.0.0 bind_port = 9696 +network_device_mtu = {{ network_device_mtu }} {% if core_plugin -%} core_plugin = {{ core_plugin }} diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index 3e2ee906..a94b79ee 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -90,6 +90,7 @@ class OVSPluginContextTest(CharmTestCase): self.relation_ids.return_value = ['rid2'] self.test_relation.set({'neutron-security-groups': True, 'l2-population': True, + 'network-device-mtu': 1500, 'overlay-network-type': 'gre', }) self.get_host_ip.return_value = '127.0.0.15' @@ -100,6 +101,7 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_security_groups': True, 'verbose': True, 'local_ip': '127.0.0.15', + 'network_device_mtu': 1500, 'config': 'neutron.randomconfig', 'use_syslog': True, 'network_manager': 'neutron', @@ -143,6 +145,7 @@ class OVSPluginContextTest(CharmTestCase): self.relation_ids.return_value = ['rid2'] self.test_relation.set({'neutron-security-groups': True, 'l2-population': True, + 'network-device-mtu': 1500, 'overlay-network-type': 'gre', }) self.get_host_ip.return_value = '127.0.0.15' @@ -153,6 +156,7 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_security_groups': False, 'verbose': True, 'local_ip': '127.0.0.15', + 'network_device_mtu': 1500, 'config': 'neutron.randomconfig', 'use_syslog': True, 'network_manager': 'neutron', From 17aac1a67340964b5535d6920d8878c7dc67334d Mon Sep 17 00:00:00 2001 From: Zhang Hua Date: Fri, 5 Dec 2014 13:44:16 +0800 Subject: [PATCH 02/43] add default value for mtu --- hooks/neutron_ovs_context.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 43952c52..33c53bda 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -26,6 +26,7 @@ def _neutron_api_settings(): 'neutron_security_groups': False, 'l2_population': True, 'overlay_network_type': 'gre', + 'network_device_mtu': 1500, } for rid in relation_ids('neutron-plugin-api'): for unit in related_units(rid): From 8f5a9fddeb825f56bb1ba55216168c45942f4e77 Mon Sep 17 00:00:00 2001 From: Zhang Hua Date: Thu, 11 Dec 2014 21:28:31 +0800 Subject: [PATCH 03/43] fix KeyError: network-device-mtu --- hooks/neutron_ovs_context.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 33c53bda..f1ea9662 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -37,7 +37,8 @@ def _neutron_api_settings(): 'l2_population': rdata['l2-population'], 'neutron_security_groups': rdata['neutron-security-groups'], 'overlay_network_type': rdata['overlay-network-type'], - 'network_device_mtu': rdata['network-device-mtu'], + 'network_device_mtu': rdata['network-device-mtu'] + if 'network-device-mtu' in rdata else 1500, } # Override with configuration if set to true if config('disable-security-groups'): From 0a54cf6557bc18a7e6693f7e0485e8f6c28c420c Mon Sep 17 00:00:00 2001 From: Zhang Hua Date: Thu, 11 Dec 2014 21:54:19 +0800 Subject: [PATCH 04/43] fix hanging indent --- hooks/neutron_ovs_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index f1ea9662..add0e2f8 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -38,7 +38,7 @@ def _neutron_api_settings(): 'neutron_security_groups': rdata['neutron-security-groups'], 'overlay_network_type': rdata['overlay-network-type'], 'network_device_mtu': rdata['network-device-mtu'] - if 'network-device-mtu' in rdata else 1500, + if 'network-device-mtu' in rdata else 1500, } # Override with configuration if set to true if config('disable-security-groups'): From a09ac7db32b4b36b75b46a74ed5160cb0411f985 Mon Sep 17 00:00:00 2001 From: Zhang Hua Date: Thu, 11 Dec 2014 21:56:45 +0800 Subject: [PATCH 05/43] E501 line too long --- hooks/neutron_ovs_context.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index add0e2f8..669d3db4 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -106,7 +106,8 @@ class OVSPluginContext(context.NeutronContext): neutron_api_settings = _neutron_api_settings() ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups ovs_ctxt['l2_population'] = neutron_api_settings['l2_population'] - ovs_ctxt['network_device_mtu'] = neutron_api_settings['network_device_mtu'] + ovs_ctxt['network_device_mtu'] = \ + neutron_api_settings['network_device_mtu'] ovs_ctxt['overlay_network_type'] = \ neutron_api_settings['overlay_network_type'] # TODO: We need to sort out the syslog and debug/verbose options as a From 935ce93483b389047d5d36344f028b406772a64b Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Mon, 9 Feb 2015 16:40:27 +0000 Subject: [PATCH 06/43] synced charm-helpers --- hooks/charmhelpers/core/host.py | 8 ++++---- hooks/charmhelpers/core/templating.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hooks/charmhelpers/core/host.py b/hooks/charmhelpers/core/host.py index 2ec26b0a..3c37db5e 100644 --- a/hooks/charmhelpers/core/host.py +++ b/hooks/charmhelpers/core/host.py @@ -191,11 +191,11 @@ def mkdir(path, owner='root', group='root', perms=0o555, force=False): def write_file(path, content, owner='root', group='root', perms=0o444): - """Create or overwrite a file with the contents of a string""" + """Create or overwrite a file with the contents of a byte string.""" log("Writing file {} {}:{} {:o}".format(path, owner, group, perms)) uid = pwd.getpwnam(owner).pw_uid gid = grp.getgrnam(group).gr_gid - with open(path, 'w') as target: + with open(path, 'wb') as target: os.fchown(target.fileno(), uid, gid) os.fchmod(target.fileno(), perms) target.write(content) @@ -305,11 +305,11 @@ def restart_on_change(restart_map, stopstart=False): ceph_client_changed function. """ def wrap(f): - def wrapped_f(*args): + def wrapped_f(*args, **kwargs): checksums = {} for path in restart_map: checksums[path] = file_hash(path) - f(*args) + f(*args, **kwargs) restarts = [] for path in restart_map: if checksums[path] != file_hash(path): diff --git a/hooks/charmhelpers/core/templating.py b/hooks/charmhelpers/core/templating.py index 97669092..45319998 100644 --- a/hooks/charmhelpers/core/templating.py +++ b/hooks/charmhelpers/core/templating.py @@ -21,7 +21,7 @@ from charmhelpers.core import hookenv def render(source, target, context, owner='root', group='root', - perms=0o444, templates_dir=None): + perms=0o444, templates_dir=None, encoding='UTF-8'): """ Render a template. @@ -64,5 +64,5 @@ def render(source, target, context, owner='root', group='root', level=hookenv.ERROR) raise e content = template.render(context) - host.mkdir(os.path.dirname(target), owner, group) - host.write_file(target, content, owner, group, perms) + host.mkdir(os.path.dirname(target), owner, group, perms=0o755) + host.write_file(target, content.encode(encoding), owner, group, perms) From fbb81bf09ea59a624dcf5f2f3c4fe7273ca88339 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Mon, 9 Feb 2015 18:19:51 +0000 Subject: [PATCH 07/43] synced ch --- hooks/charmhelpers/contrib/network/ip.py | 27 +++++--- hooks/charmhelpers/core/host.py | 79 +++++++++++++++++------- 2 files changed, 74 insertions(+), 32 deletions(-) diff --git a/hooks/charmhelpers/contrib/network/ip.py b/hooks/charmhelpers/contrib/network/ip.py index a84beb3d..3431e29f 100644 --- a/hooks/charmhelpers/contrib/network/ip.py +++ b/hooks/charmhelpers/contrib/network/ip.py @@ -374,24 +374,33 @@ def is_bridge_member(nic): return False -def configure_phy_nic_mtu(mng_ip=None): +def configure_phy_nic_mtu(mgmt_ip=None): """Configure mtu for physical nic.""" phy_nic_mtu = config('phy-nic-mtu') if phy_nic_mtu >= 1500: phy_nic = None - if mng_ip is None: - mng_ip = unit_get('private-address') + if mgmt_ip is None: + mgmt_ip = unit_get('private-address') + for nic in list_nics(['eth', 'bond', 'br']): - if mng_ip in get_ipv4_addr(nic, fatal=False): + if config('prefer-ipv6'): + addrs = get_ipv6_addr(iface=nic, fatal=False) + else: + addrs = get_ipv4_addr(iface=nic, fatal=False) + + if mgmt_ip in addrs: phy_nic = nic - # need to find the associated phy nic for bridge + # If bridge iface, find the associated phy nic if nic.startswith('br'): for brnic in get_bridge_nics(nic): if brnic.startswith('eth') or brnic.startswith('bond'): phy_nic = brnic break + + if phy_nic and phy_nic_mtu != get_nic_mtu(phy_nic): + set_nic_mtu(phy_nic, str(phy_nic_mtu), persistence=True) + log('Setting mtu=%s for phy_nic=%s' % (phy_nic_mtu, + phy_nic), + level=INFO) + break - if phy_nic is not None and phy_nic_mtu != get_nic_mtu(phy_nic): - set_nic_mtu(phy_nic, str(phy_nic_mtu), persistence=True) - log('set mtu={} for phy_nic={}' - .format(phy_nic_mtu, phy_nic), level=INFO) diff --git a/hooks/charmhelpers/core/host.py b/hooks/charmhelpers/core/host.py index 3c37db5e..e2d6c655 100644 --- a/hooks/charmhelpers/core/host.py +++ b/hooks/charmhelpers/core/host.py @@ -372,39 +372,72 @@ def list_nics(nic_type): def set_nic_mtu(nic, mtu, persistence=False): - '''Set MTU on a network interface''' + """Set MTU on a network interface.""" cmd = ['ip', 'link', 'set', nic, 'mtu', mtu] subprocess.check_call(cmd) + # persistence mtu configuration if not persistence: return - if os.path.exists("/etc/network/interfaces.d/%s.cfg" % nic): - nic_cfg_file = "/etc/network/interfaces.d/%s.cfg" % nic - else: - nic_cfg_file = "/etc/network/interfaces" - f = open(nic_cfg_file, "r") - lines = f.readlines() + nic_cfg_path = "/etc/network/interfaces" + nicd_cfg_path = "%s.d/%s.cfg" % (nic_cfg_path, nic) + if os.path.exists(nicd_cfg_path): + nic_cfg_path = nicd_cfg_path + + with open(nic_cfg_path, "r") as fd: + lines = fd.readlines() + found = False length = len(lines) - for i in range(len(lines)): - lines[i] = lines[i].replace('\n', '') - if lines[i].startswith("iface %s" % nic): + for i, line in enumerate(lines): + lines[i] = line.strip() + if line.strip().startswith("iface %s" % nic): found = True - lines.insert(i + 1, " up ip link set $IFACE mtu %s" % mtu) - lines.insert(i + 2, " down ip link set $IFACE mtu 1500") - if length > i + 2 and lines[i + 3].startswith(" up ip link set $IFACE mtu"): - del lines[i + 3] - if length > i + 2 and lines[i + 3].startswith(" down ip link set $IFACE mtu"): - del lines[i + 3] + index = i break - if not found: - lines.insert(length + 1, "") - lines.insert(length + 2, "auto %s" % nic) - lines.insert(length + 3, "iface %s inet dhcp" % nic) - lines.insert(length + 4, " up ip link set $IFACE mtu %s" % mtu) - lines.insert(length + 5, " down ip link set $IFACE mtu 1500") - write_file(path=nic_cfg_file, content="\n".join(lines), perms=0o644) + + inserts_cfg_found = """ + up ip link set $IFACE mtu %s + down ip link set $IFACE mtu 1500 + """ % (mtu) + + inserts_cfg_not_found = """ + auto %s + iface %s inet dhcp + up ip link set $IFACE mtu %s + down ip link set $IFACE mtu 1500 + """ % (nic, nic, mtu) + + deletes = """ + up ip link set $IFACE mtu + down ip link set $IFACE mtu + """ + + if found: + for line in inserts_cfg_found.split('\n'): + if not line.strip(): + continue + + index += 1 + lines.insert(index, " %s" % line.strip()) + + for line in deletes.split('\n'): + if not line.strip(): + continue + + if length > index and lines[index + 1].startswith(line): + del lines[index + 1] + else: + index = length + for line in inserts_cfg_not_found.split('\n'): + if not line.strip(): + continue + + index += 1 + lines.insert(index, " %s" % line.strip()) + + write_file(path=nic_cfg_path, content="\n".join(lines), perms=0o644) def get_nic_mtu(nic): From e4baa3876c374aee172084a81a349d5fa8dc78ff Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Mon, 9 Feb 2015 18:27:49 +0000 Subject: [PATCH 08/43] cleanup --- hooks/neutron_ovs_context.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 669d3db4..ae007fab 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -37,8 +37,7 @@ def _neutron_api_settings(): 'l2_population': rdata['l2-population'], 'neutron_security_groups': rdata['neutron-security-groups'], 'overlay_network_type': rdata['overlay-network-type'], - 'network_device_mtu': rdata['network-device-mtu'] - if 'network-device-mtu' in rdata else 1500, + 'network_device_mtu': rdata.get('network-device-mtu', 1500) } # Override with configuration if set to true if config('disable-security-groups'): From cbc15570d89907bbfb0bfe198c03ded6f6926d43 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Mon, 9 Feb 2015 20:28:59 +0000 Subject: [PATCH 09/43] sync ch --- hooks/charmhelpers/contrib/network/ip.py | 41 +----------- .../charmhelpers/contrib/openstack/context.py | 39 +++++++++++ hooks/charmhelpers/core/host.py | 67 +------------------ 3 files changed, 42 insertions(+), 105 deletions(-) diff --git a/hooks/charmhelpers/contrib/network/ip.py b/hooks/charmhelpers/contrib/network/ip.py index 3431e29f..98b17544 100644 --- a/hooks/charmhelpers/contrib/network/ip.py +++ b/hooks/charmhelpers/contrib/network/ip.py @@ -23,14 +23,7 @@ from functools import partial from charmhelpers.core.hookenv import unit_get from charmhelpers.fetch import apt_install from charmhelpers.core.hookenv import ( - config, - log, - INFO -) -from charmhelpers.core.host import ( - list_nics, - get_nic_mtu, - set_nic_mtu + log ) try: @@ -372,35 +365,3 @@ def is_bridge_member(nic): return True return False - - -def configure_phy_nic_mtu(mgmt_ip=None): - """Configure mtu for physical nic.""" - phy_nic_mtu = config('phy-nic-mtu') - if phy_nic_mtu >= 1500: - phy_nic = None - if mgmt_ip is None: - mgmt_ip = unit_get('private-address') - - for nic in list_nics(['eth', 'bond', 'br']): - if config('prefer-ipv6'): - addrs = get_ipv6_addr(iface=nic, fatal=False) - else: - addrs = get_ipv4_addr(iface=nic, fatal=False) - - if mgmt_ip in addrs: - phy_nic = nic - # If bridge iface, find the associated phy nic - if nic.startswith('br'): - for brnic in get_bridge_nics(nic): - if brnic.startswith('eth') or brnic.startswith('bond'): - phy_nic = brnic - break - - if phy_nic and phy_nic_mtu != get_nic_mtu(phy_nic): - set_nic_mtu(phy_nic, str(phy_nic_mtu), persistence=True) - log('Setting mtu=%s for phy_nic=%s' % (phy_nic_mtu, - phy_nic), - level=INFO) - - break diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index c7c4cd4a..612762c6 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -16,6 +16,7 @@ import json import os +import re import time from base64 import b64decode from subprocess import check_call @@ -47,6 +48,8 @@ from charmhelpers.core.hookenv import ( from charmhelpers.core.sysctl import create as sysctl_create from charmhelpers.core.host import ( + list_nics, + get_nic_hwaddr, mkdir, write_file, ) @@ -66,10 +69,12 @@ from charmhelpers.contrib.openstack.neutron import ( ) from charmhelpers.contrib.network.ip import ( get_address_in_network, + get_ipv4_addr, get_ipv6_addr, get_netmask_for_address, format_ipv6_addr, is_address_in_network, + is_bridge_member, ) from charmhelpers.contrib.openstack.utils import get_host_ip @@ -833,6 +838,40 @@ class NeutronContext(OSContextGenerator): return ctxt +class NeutronPortContext(OSContextGenerator): + def resolve_port(self, config_key): + if not config(config_key): + return None + + hwaddr_to_nic = {} + hwaddr_to_ip = {} + for nic in list_nics(['eth', 'bond']): + hwaddr = get_nic_hwaddr(nic) + hwaddr_to_nic[hwaddr] = nic + addresses = get_ipv4_addr(nic, fatal=False) + \ + get_ipv6_addr(iface=nic, fatal=False) + hwaddr_to_ip[hwaddr] = addresses + + mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I) + for entry in config(config_key).split(): + entry = entry.strip() + if re.match(mac_regex, entry): + if entry in hwaddr_to_nic and len(hwaddr_to_ip[entry]) == 0: + # If the nic is part of a bridge then don't use it + if is_bridge_member(hwaddr_to_nic[entry]): + continue + # Entry is a MAC address for a valid interface that doesn't + # have an IP address assigned yet. + return hwaddr_to_nic[entry] + else: + # 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 + # trust it to be the real external network). + return entry + + return None + + class OSConfigFlagContext(OSContextGenerator): """Provides support for user-defined config flags. diff --git a/hooks/charmhelpers/core/host.py b/hooks/charmhelpers/core/host.py index e2d6c655..b771c611 100644 --- a/hooks/charmhelpers/core/host.py +++ b/hooks/charmhelpers/core/host.py @@ -371,74 +371,11 @@ def list_nics(nic_type): return interfaces -def set_nic_mtu(nic, mtu, persistence=False): - """Set MTU on a network interface.""" +def set_nic_mtu(nic, mtu): + '''Set MTU on a network interface''' cmd = ['ip', 'link', 'set', nic, 'mtu', mtu] subprocess.check_call(cmd) - # persistence mtu configuration - if not persistence: - return - - nic_cfg_path = "/etc/network/interfaces" - nicd_cfg_path = "%s.d/%s.cfg" % (nic_cfg_path, nic) - if os.path.exists(nicd_cfg_path): - nic_cfg_path = nicd_cfg_path - - with open(nic_cfg_path, "r") as fd: - lines = fd.readlines() - - found = False - length = len(lines) - for i, line in enumerate(lines): - lines[i] = line.strip() - if line.strip().startswith("iface %s" % nic): - found = True - index = i - break - - inserts_cfg_found = """ - up ip link set $IFACE mtu %s - down ip link set $IFACE mtu 1500 - """ % (mtu) - - inserts_cfg_not_found = """ - auto %s - iface %s inet dhcp - up ip link set $IFACE mtu %s - down ip link set $IFACE mtu 1500 - """ % (nic, nic, mtu) - - deletes = """ - up ip link set $IFACE mtu - down ip link set $IFACE mtu - """ - - if found: - for line in inserts_cfg_found.split('\n'): - if not line.strip(): - continue - - index += 1 - lines.insert(index, " %s" % line.strip()) - - for line in deletes.split('\n'): - if not line.strip(): - continue - - if length > index and lines[index + 1].startswith(line): - del lines[index + 1] - else: - index = length - for line in inserts_cfg_not_found.split('\n'): - if not line.strip(): - continue - - index += 1 - lines.insert(index, " %s" % line.strip()) - - write_file(path=nic_cfg_path, content="\n".join(lines), perms=0o644) - def get_nic_mtu(nic): cmd = ['ip', 'addr', 'show', nic] From 64cc446092896f1290520a3ca75c3bc4c599cb35 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 10 Feb 2015 09:54:40 +0000 Subject: [PATCH 10/43] default to no network-device-mtu --- hooks/neutron_ovs_context.py | 5 ++++- unit_tests/test_neutron_ovs_context.py | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index ae007fab..04625b08 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -37,8 +37,11 @@ def _neutron_api_settings(): 'l2_population': rdata['l2-population'], 'neutron_security_groups': rdata['neutron-security-groups'], 'overlay_network_type': rdata['overlay-network-type'], - 'network_device_mtu': rdata.get('network-device-mtu', 1500) } + mtu = rdata.get('network-device-mtu') + if mtu: + neutron_settings['network_device_mtu'] = mtu + # Override with configuration if set to true if config('disable-security-groups'): neutron_settings['neutron_security_groups'] = False diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index a94b79ee..77e16e42 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -135,6 +135,7 @@ class OVSPluginContextTest(CharmTestCase): return "neutron.randomdriver" if section == "config": return "neutron.randomconfig" + _npa.side_effect = mock_npa _config.return_value = 'ovs' _unit_get.return_value = '127.0.0.13' From 9bf7ed1482a982203a25adf1942fd253f623d326 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 10 Feb 2015 10:51:33 +0000 Subject: [PATCH 11/43] default to no network-device-mtu --- hooks/neutron_ovs_context.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 04625b08..f19979da 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -38,9 +38,9 @@ def _neutron_api_settings(): 'neutron_security_groups': rdata['neutron-security-groups'], 'overlay_network_type': rdata['overlay-network-type'], } - mtu = rdata.get('network-device-mtu') - if mtu: - neutron_settings['network_device_mtu'] = mtu + net_dev_mtu = rdata.get('network-device-mtu') + if net_dev_mtu: + neutron_settings['network_device_mtu'] = net_dev_mtu # Override with configuration if set to true if config('disable-security-groups'): @@ -108,8 +108,11 @@ class OVSPluginContext(context.NeutronContext): neutron_api_settings = _neutron_api_settings() ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups ovs_ctxt['l2_population'] = neutron_api_settings['l2_population'] - ovs_ctxt['network_device_mtu'] = \ - neutron_api_settings['network_device_mtu'] + + net_dev_mtu = neutron_api_settings.get('network_device_mtu') + if net_dev_mtu: + ovs_ctxt['network_device_mtu'] = net_dev_mtu + ovs_ctxt['overlay_network_type'] = \ neutron_api_settings['overlay_network_type'] # TODO: We need to sort out the syslog and debug/verbose options as a From 86dac4c72fcf35ec8c408f7b175e8c53e7d44045 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 10 Feb 2015 13:06:32 +0000 Subject: [PATCH 12/43] add support for ext-port --- config.yaml | 15 +++++++++++++++ hooks/neutron_ovs_context.py | 14 ++++++++++++++ hooks/neutron_ovs_utils.py | 7 ++++++- templates/ext-port.conf | 16 ++++++++++++++++ unit_tests/test_neutron_ovs_utils.py | 6 ++++-- 5 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 templates/ext-port.conf diff --git a/config.yaml b/config.yaml index ea3ed841..cc173a71 100644 --- a/config.yaml +++ b/config.yaml @@ -47,3 +47,18 @@ options: . This network will be used for tenant network traffic in overlay networks. + phy-nic-mtu: + type: int + default: 0 + description: | + To improve network performance of VM, sometimes we should keep VM MTU as + 1500 and use charm to modify MTU of tunnel nic more than 1500 (e.g. 1546 + for GRE). A value of zero means no mtu will be set/modified. + ext-port: + type: string + default: + description: | + A space-separated list of external ports to use for routing of instance + traffic to the external public network. Valid values are either MAC + addresses (in which case only MAC addresses for interfaces without an IP + address already assigned will be used), or interfaces (eth0) \ No newline at end of file diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index f19979da..152c9a8c 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -121,3 +121,17 @@ class OVSPluginContext(context.NeutronContext): ovs_ctxt['verbose'] = conf['verbose'] ovs_ctxt['debug'] = conf['debug'] return ovs_ctxt + + +class ExternalPortContext(context.NeutronPortContext): + + def __call__(self): + ctxt = {} + port = self.resolve_port('ext-port') + if port: + ctxt = {"ext_port": port} + mtu = config('phy-nic-mtu') + if mtu: + ctxt['ext_port_mtu'] = mtu + + return ctxt diff --git a/hooks/neutron_ovs_utils.py b/hooks/neutron_ovs_utils.py index b5d742de..7b0962cf 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -13,6 +13,8 @@ NEUTRON_CONF_DIR = "/etc/neutron" NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR NEUTRON_DEFAULT = '/etc/default/neutron-server' ML2_CONF = '%s/plugins/ml2/ml2_conf.ini' % NEUTRON_CONF_DIR +EXT_PORT_CONF = '/etc/init/ext-port.conf' +TEMPLATES = 'templates/' BASE_RESOURCE_MAP = OrderedDict([ (NEUTRON_CONF, { @@ -24,8 +26,11 @@ BASE_RESOURCE_MAP = OrderedDict([ 'services': ['neutron-plugin-openvswitch-agent'], 'contexts': [neutron_ovs_context.OVSPluginContext()], }), + (EXT_PORT_CONF, { + 'services': ['ext-port'], + 'contexts': [neutron_ovs_context.ExternalPortContext()], + }), ]) -TEMPLATES = 'templates/' def determine_packages(): diff --git a/templates/ext-port.conf b/templates/ext-port.conf new file mode 100644 index 00000000..1d850240 --- /dev/null +++ b/templates/ext-port.conf @@ -0,0 +1,16 @@ +description "Enabling Quantum external networking port" + +start on runlevel [2345] + +task + +script + EXT_PORT="{{ ext_port }}" + MTU="{{ ext_port_mtu }}" + if [ -n "$EXT_PORT" ]; then + ip link set $EXT_PORT up + if [ -n "$MTU" ]; then + ip link set $EXT_PORT mtu $MTU + fi + fi +end script diff --git a/unit_tests/test_neutron_ovs_utils.py b/unit_tests/test_neutron_ovs_utils.py index d5555517..d29001f7 100644 --- a/unit_tests/test_neutron_ovs_utils.py +++ b/unit_tests/test_neutron_ovs_utils.py @@ -71,7 +71,8 @@ class TestNeutronOVSUtils(CharmTestCase): templating.OSConfigRenderer.side_effect = _mock_OSConfigRenderer _regconfs = nutils.register_configs() confs = ['/etc/neutron/neutron.conf', - '/etc/neutron/plugins/ml2/ml2_conf.ini'] + '/etc/neutron/plugins/ml2/ml2_conf.ini', + '/etc/init/ext-port.conf'] self.assertItemsEqual(_regconfs.configs, confs) def test_resource_map(self): @@ -85,8 +86,9 @@ class TestNeutronOVSUtils(CharmTestCase): expect = OrderedDict([ (nutils.NEUTRON_CONF, ['neutron-plugin-openvswitch-agent']), (ML2CONF, ['neutron-plugin-openvswitch-agent']), + (nutils.EXT_PORT_CONF, ['ext-port']) ]) - self.assertTrue(len(expect) == len(_restart_map)) + self.assertEqual(expect, _restart_map) for item in _restart_map: self.assertTrue(item in _restart_map) self.assertTrue(expect[item] == _restart_map[item]) From 6caaca5035c8a3e0a11d3b64d62682bb5d1e04fb Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 10 Feb 2015 14:27:23 +0000 Subject: [PATCH 13/43] allow net_dev_mtu local override --- config.yaml | 8 +++++++- hooks/neutron_ovs_context.py | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index cc173a71..b0669123 100644 --- a/config.yaml +++ b/config.yaml @@ -61,4 +61,10 @@ options: A space-separated list of external ports to use for routing of instance traffic to the external public network. Valid values are either MAC addresses (in which case only MAC addresses for interfaces without an IP - address already assigned will be used), or interfaces (eth0) \ No newline at end of file + address already assigned will be used), or interfaces (eth0) + network-device-mtu: + type: int + default: 0 + description: | + The MTU size for the interfaces managed by neutron. If set to 0, no value + will be applied. diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 152c9a8c..11d057f2 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -46,6 +46,12 @@ def _neutron_api_settings(): if config('disable-security-groups'): neutron_settings['neutron_security_groups'] = False return neutron_settings + + # Override if locally provided + cfg_net_dev_mtu = config('network-device-mtu') + if cfg_net_dev_mtu: + neutron_settings['network_device_mtu'] = config('network-device-mtu') + return neutron_settings From c71fbc275eba7665374ec911e0ff329c92b40651 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 10 Feb 2015 14:38:11 +0000 Subject: [PATCH 14/43] allow net_dev_mtu local override --- hooks/neutron_ovs_context.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 11d057f2..fdfc25a7 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -26,7 +26,6 @@ def _neutron_api_settings(): 'neutron_security_groups': False, 'l2_population': True, 'overlay_network_type': 'gre', - 'network_device_mtu': 1500, } for rid in relation_ids('neutron-plugin-api'): for unit in related_units(rid): From afe5f6d9380167979c80e80c26a3428d87450979 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 10 Feb 2015 15:25:42 +0000 Subject: [PATCH 15/43] more --- hooks/neutron_ovs_context.py | 5 +++++ templates/icehouse/ml2_conf.ini | 3 +++ 2 files changed, 8 insertions(+) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index fdfc25a7..b1cbeb1e 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -125,6 +125,11 @@ class OVSPluginContext(context.NeutronContext): ovs_ctxt['use_syslog'] = conf['use-syslog'] ovs_ctxt['verbose'] = conf['verbose'] ovs_ctxt['debug'] = conf['debug'] + + net_dev_mtu = config('network-device-mtu') + if net_dev_mtu: + ovs_ctxt['veth_mtu'] = net_dev_mtu + return ovs_ctxt diff --git a/templates/icehouse/ml2_conf.ini b/templates/icehouse/ml2_conf.ini index 56be2052..04a1f5ae 100644 --- a/templates/icehouse/ml2_conf.ini +++ b/templates/icehouse/ml2_conf.ini @@ -25,6 +25,9 @@ flat_networks = physnet1 enable_tunneling = True local_ip = {{ local_ip }} bridge_mappings = physnet1:br-data +{% if veth_mtu -%} +veth_mtu = veth_mtu +{% endif -%} [agent] tunnel_types = {{ overlay_network_type }} From 1f13f09b72b36275132c45a117497c7ddc456dfc Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 10 Feb 2015 15:47:21 +0000 Subject: [PATCH 16/43] more --- templates/icehouse/ml2_conf.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/icehouse/ml2_conf.ini b/templates/icehouse/ml2_conf.ini index 04a1f5ae..c8c50dab 100644 --- a/templates/icehouse/ml2_conf.ini +++ b/templates/icehouse/ml2_conf.ini @@ -26,7 +26,7 @@ enable_tunneling = True local_ip = {{ local_ip }} bridge_mappings = physnet1:br-data {% if veth_mtu -%} -veth_mtu = veth_mtu +veth_mtu = {{ veth_mtu }} {% endif -%} [agent] From 9e6c6355a474439e980ff7246ca69b25843caa0f Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 10 Feb 2015 19:09:25 +0000 Subject: [PATCH 17/43] support multiple phy nics for mtu --- config.yaml | 13 +++++-------- hooks/neutron_ovs_context.py | 8 ++++---- hooks/neutron_ovs_utils.py | 8 ++++---- templates/ext-port.conf | 16 ---------------- templates/os-charm-phy-nic-mtu.conf | 19 +++++++++++++++++++ unit_tests/test_neutron_ovs_utils.py | 4 ++-- 6 files changed, 34 insertions(+), 34 deletions(-) delete mode 100644 templates/ext-port.conf create mode 100644 templates/os-charm-phy-nic-mtu.conf diff --git a/config.yaml b/config.yaml index b0669123..f3025494 100644 --- a/config.yaml +++ b/config.yaml @@ -47,6 +47,11 @@ options: . This network will be used for tenant network traffic in overlay networks. + phy-nics: + type: string + default: + description: | + A space-separated list of NICs that we want phy-nic-mtu applied to. phy-nic-mtu: type: int default: 0 @@ -54,14 +59,6 @@ options: To improve network performance of VM, sometimes we should keep VM MTU as 1500 and use charm to modify MTU of tunnel nic more than 1500 (e.g. 1546 for GRE). A value of zero means no mtu will be set/modified. - ext-port: - type: string - default: - description: | - A space-separated list of external ports to use for routing of instance - traffic to the external public network. Valid values are either MAC - addresses (in which case only MAC addresses for interfaces without an IP - address already assigned will be used), or interfaces (eth0) network-device-mtu: type: int default: 0 diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index b1cbeb1e..43391ca4 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -133,15 +133,15 @@ class OVSPluginContext(context.NeutronContext): return ovs_ctxt -class ExternalPortContext(context.NeutronPortContext): +class PhyNICMTUContext(context.NeutronPortContext): def __call__(self): ctxt = {} - port = self.resolve_port('ext-port') + port = config('phy-nics') if port: - ctxt = {"ext_port": port} + ctxt = {"devs": port.replace(' ', '\n')} mtu = config('phy-nic-mtu') if mtu: - ctxt['ext_port_mtu'] = mtu + ctxt['mtu'] = mtu return ctxt diff --git a/hooks/neutron_ovs_utils.py b/hooks/neutron_ovs_utils.py index 7b0962cf..5cc9871c 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -13,7 +13,7 @@ NEUTRON_CONF_DIR = "/etc/neutron" NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR NEUTRON_DEFAULT = '/etc/default/neutron-server' ML2_CONF = '%s/plugins/ml2/ml2_conf.ini' % NEUTRON_CONF_DIR -EXT_PORT_CONF = '/etc/init/ext-port.conf' +PHY_NIC_MTU_CONF = '/etc/init/os-charm-phy-nic-mtu.conf' TEMPLATES = 'templates/' BASE_RESOURCE_MAP = OrderedDict([ @@ -26,9 +26,9 @@ BASE_RESOURCE_MAP = OrderedDict([ 'services': ['neutron-plugin-openvswitch-agent'], 'contexts': [neutron_ovs_context.OVSPluginContext()], }), - (EXT_PORT_CONF, { - 'services': ['ext-port'], - 'contexts': [neutron_ovs_context.ExternalPortContext()], + (PHY_NIC_MTU_CONF, { + 'services': ['os-charm-phy-nic-mtu'], + 'contexts': [neutron_ovs_context.PhyNICMTUContext()], }), ]) diff --git a/templates/ext-port.conf b/templates/ext-port.conf deleted file mode 100644 index 1d850240..00000000 --- a/templates/ext-port.conf +++ /dev/null @@ -1,16 +0,0 @@ -description "Enabling Quantum external networking port" - -start on runlevel [2345] - -task - -script - EXT_PORT="{{ ext_port }}" - MTU="{{ ext_port_mtu }}" - if [ -n "$EXT_PORT" ]; then - ip link set $EXT_PORT up - if [ -n "$MTU" ]; then - ip link set $EXT_PORT mtu $MTU - fi - fi -end script diff --git a/templates/os-charm-phy-nic-mtu.conf b/templates/os-charm-phy-nic-mtu.conf new file mode 100644 index 00000000..09c52aa7 --- /dev/null +++ b/templates/os-charm-phy-nic-mtu.conf @@ -0,0 +1,19 @@ +description "Enabling Quantum external networking port" + +start on runlevel [2345] + +task + +script + devs="{{ devs }}" + mtu="{{ mtu }}" + tmpfile=`mktemp` + echo $devs > $tmpfile + if [ -n "$mtu" ]; then + while read -r dev; do + [ -n "$dev" ] || continue + ip link set $dev mtu $mtu + done < echo $devs; + rm $tmpfile + fi +end script diff --git a/unit_tests/test_neutron_ovs_utils.py b/unit_tests/test_neutron_ovs_utils.py index d29001f7..5d0a304b 100644 --- a/unit_tests/test_neutron_ovs_utils.py +++ b/unit_tests/test_neutron_ovs_utils.py @@ -72,7 +72,7 @@ class TestNeutronOVSUtils(CharmTestCase): _regconfs = nutils.register_configs() confs = ['/etc/neutron/neutron.conf', '/etc/neutron/plugins/ml2/ml2_conf.ini', - '/etc/init/ext-port.conf'] + '/etc/init/os-charm-phy-nic-mtu.conf'] self.assertItemsEqual(_regconfs.configs, confs) def test_resource_map(self): @@ -86,7 +86,7 @@ class TestNeutronOVSUtils(CharmTestCase): expect = OrderedDict([ (nutils.NEUTRON_CONF, ['neutron-plugin-openvswitch-agent']), (ML2CONF, ['neutron-plugin-openvswitch-agent']), - (nutils.EXT_PORT_CONF, ['ext-port']) + (nutils.PHY_NIC_MTU_CONF, ['os-charm-phy-nic-mtu']) ]) self.assertEqual(expect, _restart_map) for item in _restart_map: From a6e11cf33b1120d6c0c210255adc31dab3cca568 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 10 Feb 2015 21:25:03 +0000 Subject: [PATCH 18/43] more --- templates/os-charm-phy-nic-mtu.conf | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/templates/os-charm-phy-nic-mtu.conf b/templates/os-charm-phy-nic-mtu.conf index 09c52aa7..9bf66a78 100644 --- a/templates/os-charm-phy-nic-mtu.conf +++ b/templates/os-charm-phy-nic-mtu.conf @@ -5,15 +5,18 @@ start on runlevel [2345] task script - devs="{{ devs }}" - mtu="{{ mtu }}" + devs="eth1" + mtu="1550" tmpfile=`mktemp` echo $devs > $tmpfile if [ -n "$mtu" ]; then while read -r dev; do [ -n "$dev" ] || continue - ip link set $dev mtu $mtu - done < echo $devs; + rc=0 + ip link set $dev mtu $mtu || rc=$? + [ $rc = 0 ] || break + done < $tmpfile rm $tmpfile + [ $rc = 0 ] || exit $rc fi -end script +end script \ No newline at end of file From 7685b4a349960199a72e05a9fb586309af2567c0 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Wed, 11 Feb 2015 13:43:17 +0000 Subject: [PATCH 19/43] more --- hooks/neutron_ovs_context.py | 23 ++++++++++------------- unit_tests/test_neutron_ovs_context.py | 4 ++-- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 43391ca4..042b409a 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -27,6 +27,12 @@ def _neutron_api_settings(): 'l2_population': True, 'overlay_network_type': 'gre', } + + # Override if provided in local config + cfg_net_dev_mtu = config('network-device-mtu') + if cfg_net_dev_mtu: + neutron_settings['network_device_mtu'] = config('network-device-mtu') + for rid in relation_ids('neutron-plugin-api'): for unit in related_units(rid): rdata = relation_get(rid=rid, unit=unit) @@ -37,20 +43,16 @@ def _neutron_api_settings(): 'neutron_security_groups': rdata['neutron-security-groups'], 'overlay_network_type': rdata['overlay-network-type'], } + + # Don't override locally provided value if there is one. net_dev_mtu = rdata.get('network-device-mtu') - if net_dev_mtu: + if net_dev_mtu and 'network_device_mtu' not in neutron_settings: neutron_settings['network_device_mtu'] = net_dev_mtu # Override with configuration if set to true if config('disable-security-groups'): neutron_settings['neutron_security_groups'] = False return neutron_settings - - # Override if locally provided - cfg_net_dev_mtu = config('network-device-mtu') - if cfg_net_dev_mtu: - neutron_settings['network_device_mtu'] = config('network-device-mtu') - return neutron_settings @@ -113,11 +115,6 @@ class OVSPluginContext(context.NeutronContext): neutron_api_settings = _neutron_api_settings() ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups ovs_ctxt['l2_population'] = neutron_api_settings['l2_population'] - - net_dev_mtu = neutron_api_settings.get('network_device_mtu') - if net_dev_mtu: - ovs_ctxt['network_device_mtu'] = net_dev_mtu - ovs_ctxt['overlay_network_type'] = \ neutron_api_settings['overlay_network_type'] # TODO: We need to sort out the syslog and debug/verbose options as a @@ -126,7 +123,7 @@ class OVSPluginContext(context.NeutronContext): ovs_ctxt['verbose'] = conf['verbose'] ovs_ctxt['debug'] = conf['debug'] - net_dev_mtu = config('network-device-mtu') + net_dev_mtu = neutron_api_settings.get('network_device_mtu') if net_dev_mtu: ovs_ctxt['veth_mtu'] = net_dev_mtu diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index 77e16e42..6aa071a5 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -101,7 +101,7 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_security_groups': True, 'verbose': True, 'local_ip': '127.0.0.15', - 'network_device_mtu': 1500, + 'veth_mtu': 1500, 'config': 'neutron.randomconfig', 'use_syslog': True, 'network_manager': 'neutron', @@ -157,7 +157,7 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_security_groups': False, 'verbose': True, 'local_ip': '127.0.0.15', - 'network_device_mtu': 1500, + 'veth_mtu': 1500, 'config': 'neutron.randomconfig', 'use_syslog': True, 'network_manager': 'neutron', From 063458a1f5aef67d7f6f42ba9ea9af90ac371762 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Wed, 11 Feb 2015 14:24:39 +0000 Subject: [PATCH 20/43] more --- hooks/neutron_ovs_context.py | 5 ++++- unit_tests/test_neutron_ovs_context.py | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 042b409a..7f79802b 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -31,7 +31,7 @@ def _neutron_api_settings(): # Override if provided in local config cfg_net_dev_mtu = config('network-device-mtu') if cfg_net_dev_mtu: - neutron_settings['network_device_mtu'] = config('network-device-mtu') + neutron_settings['network_device_mtu'] = cfg_net_dev_mtu for rid in relation_ids('neutron-plugin-api'): for unit in related_units(rid): @@ -125,6 +125,9 @@ class OVSPluginContext(context.NeutronContext): net_dev_mtu = neutron_api_settings.get('network_device_mtu') if net_dev_mtu: + # neutron.conf + ovs_ctxt['network_device_mtu'] = net_dev_mtu + # ml2 conf ovs_ctxt['veth_mtu'] = net_dev_mtu return ovs_ctxt diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index 6aa071a5..f82e7618 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -101,6 +101,7 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_security_groups': True, 'verbose': True, 'local_ip': '127.0.0.15', + 'network_device_mtu': 1500, 'veth_mtu': 1500, 'config': 'neutron.randomconfig', 'use_syslog': True, @@ -158,6 +159,7 @@ class OVSPluginContextTest(CharmTestCase): 'verbose': True, 'local_ip': '127.0.0.15', 'veth_mtu': 1500, + 'network_device_mtu': 1500, 'config': 'neutron.randomconfig', 'use_syslog': True, 'network_manager': 'neutron', From cade073c3700d1ed3ab8b7a9550ade8ad49d21d9 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Wed, 11 Feb 2015 15:37:25 +0000 Subject: [PATCH 21/43] more --- templates/os-charm-phy-nic-mtu.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/os-charm-phy-nic-mtu.conf b/templates/os-charm-phy-nic-mtu.conf index 9bf66a78..6684aceb 100644 --- a/templates/os-charm-phy-nic-mtu.conf +++ b/templates/os-charm-phy-nic-mtu.conf @@ -5,8 +5,8 @@ start on runlevel [2345] task script - devs="eth1" - mtu="1550" + devs="{{ devs }}" + mtu="{{ mtu }}" tmpfile=`mktemp` echo $devs > $tmpfile if [ -n "$mtu" ]; then From 977581b761cc0f41b59f4e36965b574b2b514e46 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Wed, 11 Feb 2015 15:48:19 +0000 Subject: [PATCH 22/43] more --- hooks/neutron_ovs_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 7f79802b..2fb54af5 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -139,7 +139,7 @@ class PhyNICMTUContext(context.NeutronPortContext): ctxt = {} port = config('phy-nics') if port: - ctxt = {"devs": port.replace(' ', '\n')} + ctxt = {"devs": port.replace(' ', '\\n')} mtu = config('phy-nic-mtu') if mtu: ctxt['mtu'] = mtu From 7d249d8245ba11b1ec6bf1eac23bb8489b119cc1 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Wed, 11 Feb 2015 15:52:22 +0000 Subject: [PATCH 23/43] more --- templates/os-charm-phy-nic-mtu.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/os-charm-phy-nic-mtu.conf b/templates/os-charm-phy-nic-mtu.conf index 6684aceb..06d1967b 100644 --- a/templates/os-charm-phy-nic-mtu.conf +++ b/templates/os-charm-phy-nic-mtu.conf @@ -13,8 +13,8 @@ script while read -r dev; do [ -n "$dev" ] || continue rc=0 + # Try all devices before exiting with error ip link set $dev mtu $mtu || rc=$? - [ $rc = 0 ] || break done < $tmpfile rm $tmpfile [ $rc = 0 ] || exit $rc From 97058d36902e38c72ce56e30414171221f8f8f12 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Wed, 11 Feb 2015 16:31:04 +0000 Subject: [PATCH 24/43] more --- config.yaml | 6 ++++++ hooks/neutron_ovs_context.py | 4 ++++ templates/icehouse/ml2_conf.ini | 2 +- unit_tests/test_neutron_ovs_context.py | 2 ++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index f3025494..ea700e23 100644 --- a/config.yaml +++ b/config.yaml @@ -36,6 +36,12 @@ options: . BE CAREFUL - this option allows you to disable all port level security within an OpenStack cloud. + bridge-mappings: + type: string + default: 'physnet1:br-data' + description: | + Space-separated list of ML2 data bridge mappings with format + :. # Network configuration options # by default all access is over 'private-address' os-data-network: diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 2fb54af5..4a4f23dc 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -130,6 +130,10 @@ class OVSPluginContext(context.NeutronContext): # ml2 conf ovs_ctxt['veth_mtu'] = net_dev_mtu + mappings = config('bridge-mappings') + if mappings: + ovs_ctxt['bridge_mappings'] = mappings + return ovs_ctxt diff --git a/templates/icehouse/ml2_conf.ini b/templates/icehouse/ml2_conf.ini index c8c50dab..f30ada2e 100644 --- a/templates/icehouse/ml2_conf.ini +++ b/templates/icehouse/ml2_conf.ini @@ -24,7 +24,7 @@ flat_networks = physnet1 [ovs] enable_tunneling = True local_ip = {{ local_ip }} -bridge_mappings = physnet1:br-data +bridge_mappings = {{ bridge_mappings }} {% if veth_mtu -%} veth_mtu = {{ veth_mtu }} {% endif -%} diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index f82e7618..85f981e9 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -112,6 +112,7 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_url': 'https://127.0.0.13:9696', 'l2_population': True, 'overlay_network_type': 'gre', + 'bridge_mappings': 'physnet1:br-data' } self.assertEquals(expect, napi_ctxt()) self.service_start.assertCalled() @@ -169,6 +170,7 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_url': 'https://127.0.0.13:9696', 'l2_population': True, 'overlay_network_type': 'gre', + 'bridge_mappings': 'physnet1:br-data' } self.assertEquals(expect, napi_ctxt()) self.service_start.assertCalled() From ecfd1bfb57f4e5c834ddc1b5442430753d6e332d Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Wed, 11 Feb 2015 18:48:41 +0000 Subject: [PATCH 25/43] more --- hooks/neutron_ovs_context.py | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 4a4f23dc..4c4ea707 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -7,7 +7,11 @@ from charmhelpers.core.hookenv import ( ) from charmhelpers.core.host import list_nics, get_nic_hwaddr from charmhelpers.contrib.openstack import context -from charmhelpers.core.host import service_running, service_start +from charmhelpers.core.host import ( + service_running, + service_start, + service_restart, +) from charmhelpers.contrib.network.ovs import add_bridge, add_bridge_port from charmhelpers.contrib.openstack.utils import get_host_ip from charmhelpers.contrib.network.ip import get_address_in_network @@ -15,7 +19,6 @@ from charmhelpers.contrib.network.ip import get_address_in_network import re OVS_BRIDGE = 'br-int' -DATA_BRIDGE = 'br-data' def _neutron_api_settings(): @@ -56,6 +59,23 @@ def _neutron_api_settings(): return neutron_settings +def get_bridges_from_mapping(): + """If a bridge mapping is provided, extract the bridge names. + + Returns list of bridges from mapping. + """ + bridges = [] + mappings = config('bridge-mappings') + if mappings: + mappings = mappings.split(' ') + for m in mappings: + p = m.partition(':') + if p[1] == ':': + bridges.append(p[2]) + + return bridges + + class OVSPluginContext(context.NeutronContext): interfaces = [] @@ -92,11 +112,15 @@ class OVSPluginContext(context.NeutronContext): def _ensure_bridge(self): if not service_running('openvswitch-switch'): service_start('openvswitch-switch') + add_bridge(OVS_BRIDGE) - add_bridge(DATA_BRIDGE) - data_port = self.get_data_port() - if data_port: - add_bridge_port(DATA_BRIDGE, data_port, promisc=True) + for br in get_bridges_from_mapping(): + add_bridge(br) + data_port = self.get_data_port() + if data_port: + add_bridge_port(br, data_port, promisc=True) + + service_restart('os-charm-phy-nic-mtu') def ovs_ctxt(self): # In addition to generating config context, ensure the OVS service From c552b4d7d26231835a80046598624783497ca964 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Thu, 12 Feb 2015 11:17:34 +0000 Subject: [PATCH 26/43] more --- templates/icehouse/ml2_conf.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/icehouse/ml2_conf.ini b/templates/icehouse/ml2_conf.ini index f30ada2e..2c40fcd1 100644 --- a/templates/icehouse/ml2_conf.ini +++ b/templates/icehouse/ml2_conf.ini @@ -27,7 +27,7 @@ local_ip = {{ local_ip }} bridge_mappings = {{ bridge_mappings }} {% if veth_mtu -%} veth_mtu = {{ veth_mtu }} -{% endif -%} +{% endif %} [agent] tunnel_types = {{ overlay_network_type }} From 41c60693e8211fb5a99d7e12d64bdda8d0c7fb4c Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Thu, 12 Feb 2015 12:21:35 +0000 Subject: [PATCH 27/43] more --- hooks/neutron_ovs_utils.py | 6 ++++++ templates/icehouse/ovs_neutron_plugin.ini | 6 ++++++ unit_tests/test_neutron_ovs_utils.py | 6 ++++-- 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 templates/icehouse/ovs_neutron_plugin.ini diff --git a/hooks/neutron_ovs_utils.py b/hooks/neutron_ovs_utils.py index 5cc9871c..2b09b149 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -13,6 +13,8 @@ NEUTRON_CONF_DIR = "/etc/neutron" NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR NEUTRON_DEFAULT = '/etc/default/neutron-server' ML2_CONF = '%s/plugins/ml2/ml2_conf.ini' % NEUTRON_CONF_DIR +ML2_OVS_CONF = ('%s/plugins/openvswitch/ovs_neutron_plugin.ini' % + NEUTRON_CONF_DIR) PHY_NIC_MTU_CONF = '/etc/init/os-charm-phy-nic-mtu.conf' TEMPLATES = 'templates/' @@ -26,6 +28,10 @@ BASE_RESOURCE_MAP = OrderedDict([ 'services': ['neutron-plugin-openvswitch-agent'], 'contexts': [neutron_ovs_context.OVSPluginContext()], }), + (ML2_OVS_CONF, { + 'services': ['neutron-plugin-openvswitch-agent'], + 'contexts': [neutron_ovs_context.OVSPluginContext()], + }), (PHY_NIC_MTU_CONF, { 'services': ['os-charm-phy-nic-mtu'], 'contexts': [neutron_ovs_context.PhyNICMTUContext()], diff --git a/templates/icehouse/ovs_neutron_plugin.ini b/templates/icehouse/ovs_neutron_plugin.ini new file mode 100644 index 00000000..d3cc8c28 --- /dev/null +++ b/templates/icehouse/ovs_neutron_plugin.ini @@ -0,0 +1,6 @@ +[ovs] + +[agent] +{% if veth_mtu -%} +veth_mtu = {{ veth_mtu }} +{% endif %} diff --git a/unit_tests/test_neutron_ovs_utils.py b/unit_tests/test_neutron_ovs_utils.py index 5d0a304b..dd61865b 100644 --- a/unit_tests/test_neutron_ovs_utils.py +++ b/unit_tests/test_neutron_ovs_utils.py @@ -72,7 +72,8 @@ class TestNeutronOVSUtils(CharmTestCase): _regconfs = nutils.register_configs() confs = ['/etc/neutron/neutron.conf', '/etc/neutron/plugins/ml2/ml2_conf.ini', - '/etc/init/os-charm-phy-nic-mtu.conf'] + '/etc/init/os-charm-phy-nic-mtu.conf', + '/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini'] self.assertItemsEqual(_regconfs.configs, confs) def test_resource_map(self): @@ -86,7 +87,8 @@ class TestNeutronOVSUtils(CharmTestCase): expect = OrderedDict([ (nutils.NEUTRON_CONF, ['neutron-plugin-openvswitch-agent']), (ML2CONF, ['neutron-plugin-openvswitch-agent']), - (nutils.PHY_NIC_MTU_CONF, ['os-charm-phy-nic-mtu']) + (nutils.PHY_NIC_MTU_CONF, ['os-charm-phy-nic-mtu']), + (nutils.ML2_OVS_CONF, ['neutron-plugin-openvswitch-agent']) ]) self.assertEqual(expect, _restart_map) for item in _restart_map: From 5f162c20bd8a77e400c1170c96595752135a0a7a Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Thu, 12 Feb 2015 12:31:58 +0000 Subject: [PATCH 28/43] reverted last commit --- hooks/neutron_ovs_utils.py | 6 ------ templates/icehouse/ovs_neutron_plugin.ini | 6 ------ unit_tests/test_neutron_ovs_utils.py | 6 ++---- 3 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 templates/icehouse/ovs_neutron_plugin.ini diff --git a/hooks/neutron_ovs_utils.py b/hooks/neutron_ovs_utils.py index 2b09b149..5cc9871c 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -13,8 +13,6 @@ NEUTRON_CONF_DIR = "/etc/neutron" NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR NEUTRON_DEFAULT = '/etc/default/neutron-server' ML2_CONF = '%s/plugins/ml2/ml2_conf.ini' % NEUTRON_CONF_DIR -ML2_OVS_CONF = ('%s/plugins/openvswitch/ovs_neutron_plugin.ini' % - NEUTRON_CONF_DIR) PHY_NIC_MTU_CONF = '/etc/init/os-charm-phy-nic-mtu.conf' TEMPLATES = 'templates/' @@ -28,10 +26,6 @@ BASE_RESOURCE_MAP = OrderedDict([ 'services': ['neutron-plugin-openvswitch-agent'], 'contexts': [neutron_ovs_context.OVSPluginContext()], }), - (ML2_OVS_CONF, { - 'services': ['neutron-plugin-openvswitch-agent'], - 'contexts': [neutron_ovs_context.OVSPluginContext()], - }), (PHY_NIC_MTU_CONF, { 'services': ['os-charm-phy-nic-mtu'], 'contexts': [neutron_ovs_context.PhyNICMTUContext()], diff --git a/templates/icehouse/ovs_neutron_plugin.ini b/templates/icehouse/ovs_neutron_plugin.ini deleted file mode 100644 index d3cc8c28..00000000 --- a/templates/icehouse/ovs_neutron_plugin.ini +++ /dev/null @@ -1,6 +0,0 @@ -[ovs] - -[agent] -{% if veth_mtu -%} -veth_mtu = {{ veth_mtu }} -{% endif %} diff --git a/unit_tests/test_neutron_ovs_utils.py b/unit_tests/test_neutron_ovs_utils.py index dd61865b..5d0a304b 100644 --- a/unit_tests/test_neutron_ovs_utils.py +++ b/unit_tests/test_neutron_ovs_utils.py @@ -72,8 +72,7 @@ class TestNeutronOVSUtils(CharmTestCase): _regconfs = nutils.register_configs() confs = ['/etc/neutron/neutron.conf', '/etc/neutron/plugins/ml2/ml2_conf.ini', - '/etc/init/os-charm-phy-nic-mtu.conf', - '/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini'] + '/etc/init/os-charm-phy-nic-mtu.conf'] self.assertItemsEqual(_regconfs.configs, confs) def test_resource_map(self): @@ -87,8 +86,7 @@ class TestNeutronOVSUtils(CharmTestCase): expect = OrderedDict([ (nutils.NEUTRON_CONF, ['neutron-plugin-openvswitch-agent']), (ML2CONF, ['neutron-plugin-openvswitch-agent']), - (nutils.PHY_NIC_MTU_CONF, ['os-charm-phy-nic-mtu']), - (nutils.ML2_OVS_CONF, ['neutron-plugin-openvswitch-agent']) + (nutils.PHY_NIC_MTU_CONF, ['os-charm-phy-nic-mtu']) ]) self.assertEqual(expect, _restart_map) for item in _restart_map: From cfb6fc8e81dd61de14855611d92df3de22758db7 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Thu, 12 Feb 2015 13:50:27 +0000 Subject: [PATCH 29/43] move veth_mtu to correct section --- templates/icehouse/ml2_conf.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/icehouse/ml2_conf.ini b/templates/icehouse/ml2_conf.ini index 2c40fcd1..575953d8 100644 --- a/templates/icehouse/ml2_conf.ini +++ b/templates/icehouse/ml2_conf.ini @@ -25,13 +25,13 @@ flat_networks = physnet1 enable_tunneling = True local_ip = {{ local_ip }} bridge_mappings = {{ bridge_mappings }} -{% if veth_mtu -%} -veth_mtu = {{ veth_mtu }} -{% endif %} [agent] tunnel_types = {{ overlay_network_type }} l2_population = {{ l2_population }} +{% if veth_mtu -%} +veth_mtu = {{ veth_mtu }} +{% endif %} [securitygroup] {% if neutron_security_groups -%} From befb2b4f3b3269f668ac5f6727c71f3e15e35322 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Fri, 27 Feb 2015 18:25:49 +0000 Subject: [PATCH 30/43] more --- config.yaml | 6 -- .../charmhelpers/contrib/openstack/context.py | 30 ++++--- .../charmhelpers/contrib/openstack/neutron.py | 33 ++++++++ hooks/neutron_ovs_context.py | 83 ++++++++----------- unit_tests/test_neutron_ovs_context.py | 42 ++++++---- 5 files changed, 113 insertions(+), 81 deletions(-) diff --git a/config.yaml b/config.yaml index ea700e23..133587ca 100644 --- a/config.yaml +++ b/config.yaml @@ -65,9 +65,3 @@ options: To improve network performance of VM, sometimes we should keep VM MTU as 1500 and use charm to modify MTU of tunnel nic more than 1500 (e.g. 1546 for GRE). A value of zero means no mtu will be set/modified. - network-device-mtu: - type: int - default: 0 - description: | - The MTU size for the interfaces managed by neutron. If set to 0, no value - will be applied. diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index 612762c6..6f109864 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -839,37 +839,45 @@ class NeutronContext(OSContextGenerator): class NeutronPortContext(OSContextGenerator): - def resolve_port(self, config_key): - if not config(config_key): + NIC_PREFIXES = ['eth', 'bond'] + + def resolve_ports(self, ports): + """Resolve NICs not yet bound to bridge(s) + + If hwaddress provided then returns resolved hwaddress otherwise NIC. + """ + if not ports: return None hwaddr_to_nic = {} hwaddr_to_ip = {} - for nic in list_nics(['eth', 'bond']): + for nic in list_nics(self.NIC_PREFIXES): hwaddr = get_nic_hwaddr(nic) hwaddr_to_nic[hwaddr] = nic - addresses = get_ipv4_addr(nic, fatal=False) + \ - get_ipv6_addr(iface=nic, fatal=False) + addresses = get_ipv4_addr(nic, fatal=False) + addresses += get_ipv6_addr(iface=nic, fatal=False) hwaddr_to_ip[hwaddr] = addresses + resolved = [] mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I) - for entry in config(config_key).split(): - entry = entry.strip() + for entry in ports: if re.match(mac_regex, entry): - if entry in hwaddr_to_nic and len(hwaddr_to_ip[entry]) == 0: + # NIC is in known NICs and does NOT hace an IP address + if entry in hwaddr_to_nic and not hwaddr_to_ip[entry]: # If the nic is part of a bridge then don't use it if is_bridge_member(hwaddr_to_nic[entry]): continue + # Entry is a MAC address for a valid interface that doesn't # have an IP address assigned yet. - return hwaddr_to_nic[entry] + resolved.append(hwaddr_to_nic[entry]) else: # 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 # trust it to be the real external network). - return entry + resolved.append(entry) - return None + return resolved class OSConfigFlagContext(OSContextGenerator): diff --git a/hooks/charmhelpers/contrib/openstack/neutron.py b/hooks/charmhelpers/contrib/openstack/neutron.py index 902757fe..6d9fdff6 100644 --- a/hooks/charmhelpers/contrib/openstack/neutron.py +++ b/hooks/charmhelpers/contrib/openstack/neutron.py @@ -237,3 +237,36 @@ def network_manager(): else: # ensure accurate naming for all releases post-H return 'neutron' + + +def parse_mappings(mappings): + parsed = {} + if mappings: + mappings = mappings.split(' ') + for m in mappings: + p = m.partition(':') + if p[1] == ':': + parsed[p[0].strip()] = p[2].strip() + + return parsed + + +def parse_bridge_mappings(mappings): + """Parse bridge mappings. + + Mappings must be a space-delimited list of provider:bridge mappings. + + Returns dict of the form {provider:bridge}. + """ + return parse_mappings(mappings) + + +def parse_data_port_mappings(mappings): + """Parse data port mappings. + + Mappings must be a space-delimited list of provider:port mappings. + + Returns dict of the form {provider:port}. + """ + return parse_mappings(mappings) + diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index ab167915..b83dbaf1 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -5,7 +5,6 @@ from charmhelpers.core.hookenv import ( config, unit_get, ) -from charmhelpers.core.host import list_nics, get_nic_hwaddr from charmhelpers.core.strutils import bool_from_string from charmhelpers.contrib.openstack import context from charmhelpers.core.host import ( @@ -16,8 +15,16 @@ from charmhelpers.core.host import ( from charmhelpers.contrib.network.ovs import add_bridge, add_bridge_port from charmhelpers.contrib.openstack.utils import get_host_ip from charmhelpers.contrib.network.ip import get_address_in_network -import re - +from charmhelpers.contrib.openstack.neutron import ( + parse_bridge_mappings, + parse_data_port_mappings, +) +from charmhelpers.contrib.openstack.context import ( + NeutronPortContext, +) +from charmhelpers.core.host import ( + get_nic_hwaddr, +) OVS_BRIDGE = 'br-int' @@ -31,11 +38,6 @@ def _neutron_api_settings(): 'overlay_network_type': 'gre', } - # Override if provided in local config - cfg_net_dev_mtu = config('network-device-mtu') - if cfg_net_dev_mtu: - neutron_settings['network_device_mtu'] = cfg_net_dev_mtu - for rid in relation_ids('neutron-plugin-api'): for unit in related_units(rid): rdata = relation_get(rid=rid, unit=unit) @@ -49,33 +51,31 @@ def _neutron_api_settings(): ), } - # Don't override locally provided value if there is one. net_dev_mtu = rdata.get('network-device-mtu') - if net_dev_mtu and 'network_device_mtu' not in neutron_settings: + if net_dev_mtu: neutron_settings['network_device_mtu'] = net_dev_mtu - # Override with configuration if set to true - if config('disable-security-groups'): - neutron_settings['neutron_security_groups'] = False return neutron_settings return neutron_settings -def get_bridges_from_mapping(): - """If a bridge mapping is provided, extract the bridge names. +class DataPortContext(NeutronPortContext): - Returns list of bridges from mapping. - """ - bridges = [] - mappings = config('bridge-mappings') - if mappings: - mappings = mappings.split(' ') - for m in mappings: - p = m.partition(':') - if p[1] == ':': - bridges.append(p[2]) + def __call__(self): + ports = config('data-port') + if ports: + portmap = parse_data_port_mappings(ports) + ports = portmap.values() + resolved = self.resolve_ports(ports) + normalized = {get_nic_hwaddr(port): port for port in resolved + if port not in ports} + normalized.update({port: port for port in resolved + if port in ports}) + if resolved: + return {provider: normalized[port] for provider, port in + portmap.iteritems() if port in normalized.keys()} - return bridges + return None class OVSPluginContext(context.NeutronContext): @@ -94,33 +94,22 @@ class OVSPluginContext(context.NeutronContext): neutron_api_settings = _neutron_api_settings() return neutron_api_settings['neutron_security_groups'] - def get_data_port(self): - data_ports = config('data-port') - if not data_ports: - return None - hwaddrs = {} - for nic in list_nics(['eth', 'bond']): - hwaddrs[get_nic_hwaddr(nic).lower()] = nic - mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I) - for entry in data_ports.split(): - entry = entry.strip().lower() - if re.match(mac_regex, entry): - if entry in hwaddrs: - return hwaddrs[entry] - else: - return entry - return None - def _ensure_bridge(self): if not service_running('openvswitch-switch'): service_start('openvswitch-switch') add_bridge(OVS_BRIDGE) - for br in get_bridges_from_mapping(): + + portmaps = DataPortContext()() + bridgemaps = parse_bridge_mappings(config('bridge-mappings')) + for provider, br in bridgemaps.iteritems(): add_bridge(br) - data_port = self.get_data_port() - if data_port: - add_bridge_port(br, data_port, promisc=True) + + if not portmaps or provider not in portmaps: + #raise Exception(portmaps) + continue + + add_bridge_port(br, portmaps[provider], promisc=True) service_restart('os-charm-phy-nic-mtu') diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index db2a9a82..c2f73411 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -14,8 +14,6 @@ TO_PATCH = [ 'service_running', 'service_start', 'get_host_ip', - 'get_nic_hwaddr', - 'list_nics', ] @@ -32,34 +30,44 @@ class OVSPluginContextTest(CharmTestCase): def tearDown(self): super(OVSPluginContextTest, self).tearDown() - def test_data_port_name(self): - self.test_config.set('data-port', 'em1') - self.assertEquals(context.OVSPluginContext().get_data_port(), 'em1') + @patch('charmhelpers.contrib.openstack.context.NeutronPortContext.' + 'resolve_ports') + def test_data_port_name(self, mock_resolve_ports): + self.test_config.set('data-port', 'phybr1:em1') + mock_resolve_ports.side_effect = lambda ports: ports + self.assertEquals(context.DataPortContext()(), + {'phybr1': 'em1'}) - def test_data_port_mac(self): + @patch.object(context, 'get_nic_hwaddr') + @patch('charmhelpers.contrib.openstack.context.get_nic_hwaddr') + @patch('charmhelpers.contrib.openstack.context.list_nics') + def test_data_port_mac(self, list_nics, get_nic_hwaddr, get_nic_hwaddr2): machine_machs = { 'em1': 'aa:aa:aa:aa:aa:aa', 'eth0': 'bb:bb:bb:bb:bb:bb', } + get_nic_hwaddr2.side_effect = lambda nic: machine_machs[nic] absent_mac = "cc:cc:cc:cc:cc:cc" - config_macs = "%s %s" % (absent_mac, machine_machs['em1']) + config_macs = ("phybr2:%s phybr1:%s" % + (absent_mac, machine_machs['em1'])) self.test_config.set('data-port', config_macs) + list_nics.return_value = machine_machs.keys() + get_nic_hwaddr.side_effect = lambda nic: machine_machs[nic] + self.assertEquals(context.DataPortContext()(), + {'phybr1': 'em1'}) - def get_hwaddr(eth): - return machine_machs[eth] - self.get_nic_hwaddr.side_effect = get_hwaddr - self.list_nics.return_value = machine_machs.keys() - self.assertEquals(context.OVSPluginContext().get_data_port(), 'em1') - - @patch.object(context.OVSPluginContext, 'get_data_port') - def test_ensure_bridge_data_port_present(self, get_data_port): + @patch('charmhelpers.contrib.openstack.context.NeutronPortContext.' + 'resolve_ports') + def test_ensure_bridge_data_port_present(self, mock_resolve_ports): + self.test_config.set('data-port', 'phybr1:em1') + self.test_config.set('bridge-mappings', 'phybr1:br-data') def add_port(bridge, port, promisc): if bridge == 'br-data' and port == 'em1' and promisc is True: self.bridge_added = True return self.bridge_added = False - get_data_port.return_value = 'em1' + mock_resolve_ports.side_effect = lambda ports: ports self.add_bridge_port.side_effect = add_port context.OVSPluginContext()._ensure_bridge() self.assertEquals(self.bridge_added, True) @@ -156,7 +164,7 @@ class OVSPluginContextTest(CharmTestCase): napi_ctxt = context.OVSPluginContext() expect = { 'neutron_alchemy_flags': {}, - 'neutron_security_groups': False, + 'neutron_security_groups': True, 'verbose': True, 'local_ip': '127.0.0.15', 'veth_mtu': 1500, From 2844b0dc981f3dce387934bd96ad7ca896fb81fc Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Fri, 27 Feb 2015 18:26:42 +0000 Subject: [PATCH 31/43] more --- hooks/neutron_ovs_context.py | 1 - unit_tests/test_neutron_ovs_context.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index b83dbaf1..4be53988 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -106,7 +106,6 @@ class OVSPluginContext(context.NeutronContext): add_bridge(br) if not portmaps or provider not in portmaps: - #raise Exception(portmaps) continue add_bridge_port(br, portmaps[provider], promisc=True) diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index c2f73411..5e93b5e8 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -61,6 +61,7 @@ class OVSPluginContextTest(CharmTestCase): def test_ensure_bridge_data_port_present(self, mock_resolve_ports): self.test_config.set('data-port', 'phybr1:em1') self.test_config.set('bridge-mappings', 'phybr1:br-data') + def add_port(bridge, port, promisc): if bridge == 'br-data' and port == 'em1' and promisc is True: self.bridge_added = True From 1ddfb7b20f93f4121359d5ba241bd56cd284e1d5 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 3 Mar 2015 10:31:16 +0800 Subject: [PATCH 32/43] sync ch --- hooks/charmhelpers/contrib/network/ip.py | 85 ++++++++++++++++++- .../charmhelpers/contrib/openstack/context.py | 41 ++++++--- .../charmhelpers/contrib/openstack/neutron.py | 1 - .../contrib/openstack/templates/zeromq | 14 +++ hooks/charmhelpers/contrib/openstack/utils.py | 78 ++--------------- hooks/charmhelpers/core/services/helpers.py | 16 +++- 6 files changed, 146 insertions(+), 89 deletions(-) create mode 100644 hooks/charmhelpers/contrib/openstack/templates/zeromq diff --git a/hooks/charmhelpers/contrib/network/ip.py b/hooks/charmhelpers/contrib/network/ip.py index 98b17544..fff6d5ca 100644 --- a/hooks/charmhelpers/contrib/network/ip.py +++ b/hooks/charmhelpers/contrib/network/ip.py @@ -17,13 +17,16 @@ import glob import re import subprocess +import six +import socket from functools import partial from charmhelpers.core.hookenv import unit_get from charmhelpers.fetch import apt_install from charmhelpers.core.hookenv import ( - log + log, + WARNING, ) try: @@ -365,3 +368,83 @@ def is_bridge_member(nic): return True return False + + +def is_ip(address): + """ + Returns True if address is a valid IP address. + """ + try: + # Test to see if already an IPv4 address + socket.inet_aton(address) + return True + except socket.error: + return False + + +def ns_query(address): + try: + import dns.resolver + except ImportError: + apt_install('python-dnspython') + import dns.resolver + + if isinstance(address, dns.name.Name): + rtype = 'PTR' + elif isinstance(address, six.string_types): + rtype = 'A' + else: + return None + + answers = dns.resolver.query(address, rtype) + if answers: + return str(answers[0]) + return None + + +def get_host_ip(hostname, fallback=None): + """ + Resolves the IP for a given hostname, or returns + the input if it is already an IP. + """ + if is_ip(hostname): + return hostname + + ip_addr = ns_query(hostname) + if not ip_addr: + try: + ip_addr = socket.gethostbyname(hostname) + except: + log("Failed to resolve hostname '%s'" % (hostname), + level=WARNING) + return fallback + return ip_addr + + +def get_hostname(address, fqdn=True): + """ + Resolves hostname for given IP, or returns the input + if it is already a hostname. + """ + if is_ip(address): + try: + import dns.reversename + except ImportError: + apt_install("python-dnspython") + import dns.reversename + + rev = dns.reversename.from_address(address) + result = ns_query(rev) + if not result: + return None + else: + result = address + + if fqdn: + # strip trailing . + if result.endswith('.'): + return result[:-1] + else: + return result + else: + return result.split('.')[0] diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index 6f109864..21bfde88 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -196,7 +196,7 @@ class SharedDBContext(OSContextGenerator): unit=local_unit()) if set_hostname != access_hostname: relation_set(relation_settings={hostname_key: access_hostname}) - return ctxt # Defer any further hook execution for now.... + return None # Defer any further hook execution for now.... password_setting = 'password' if self.relation_prefix: @@ -284,9 +284,25 @@ def db_ssl(rdata, ctxt, ssl_dir): class IdentityServiceContext(OSContextGenerator): interfaces = ['identity-service'] + def __init__(self, service=None, service_user=None): + self.service = service + self.service_user = service_user + def __call__(self): log('Generating template context for identity-service', level=DEBUG) ctxt = {} + + if self.service and self.service_user: + # This is required for pki token signing if we don't want /tmp to + # be used. + cachedir = '/var/cache/%s' % (self.service) + if not os.path.isdir(cachedir): + log("Creating service cache dir %s" % (cachedir), level=DEBUG) + mkdir(path=cachedir, owner=self.service_user, + group=self.service_user, perms=0o700) + + ctxt['signing_dir'] = cachedir + for rid in relation_ids('identity-service'): for unit in related_units(rid): rdata = relation_get(rid=rid, unit=unit) @@ -296,15 +312,16 @@ class IdentityServiceContext(OSContextGenerator): auth_host = format_ipv6_addr(auth_host) or auth_host svc_protocol = rdata.get('service_protocol') or 'http' auth_protocol = rdata.get('auth_protocol') or 'http' - ctxt = {'service_port': rdata.get('service_port'), - 'service_host': serv_host, - 'auth_host': auth_host, - 'auth_port': rdata.get('auth_port'), - 'admin_tenant_name': rdata.get('service_tenant'), - 'admin_user': rdata.get('service_username'), - 'admin_password': rdata.get('service_password'), - 'service_protocol': svc_protocol, - 'auth_protocol': auth_protocol} + ctxt.update({'service_port': rdata.get('service_port'), + 'service_host': serv_host, + 'auth_host': auth_host, + 'auth_port': rdata.get('auth_port'), + 'admin_tenant_name': rdata.get('service_tenant'), + 'admin_user': rdata.get('service_username'), + 'admin_password': rdata.get('service_password'), + 'service_protocol': svc_protocol, + 'auth_protocol': auth_protocol}) + if context_complete(ctxt): # NOTE(jamespage) this is required for >= icehouse # so a missing value just indicates keystone needs @@ -844,7 +861,7 @@ class NeutronPortContext(OSContextGenerator): def resolve_ports(self, ports): """Resolve NICs not yet bound to bridge(s) - If hwaddress provided then returns resolved hwaddress otherwise NIC. + If hwaddress provided then returns resolved hwaddress otherwise NIC. """ if not ports: return None @@ -1068,6 +1085,8 @@ class ZeroMQContext(OSContextGenerator): for unit in related_units(rid): ctxt['zmq_nonce'] = relation_get('nonce', unit, rid) ctxt['zmq_host'] = relation_get('host', unit, rid) + ctxt['zmq_redis_address'] = relation_get( + 'zmq_redis_address', unit, rid) return ctxt diff --git a/hooks/charmhelpers/contrib/openstack/neutron.py b/hooks/charmhelpers/contrib/openstack/neutron.py index 6d9fdff6..76a90011 100644 --- a/hooks/charmhelpers/contrib/openstack/neutron.py +++ b/hooks/charmhelpers/contrib/openstack/neutron.py @@ -269,4 +269,3 @@ def parse_data_port_mappings(mappings): Returns dict of the form {provider:port}. """ return parse_mappings(mappings) - diff --git a/hooks/charmhelpers/contrib/openstack/templates/zeromq b/hooks/charmhelpers/contrib/openstack/templates/zeromq new file mode 100644 index 00000000..0695eef1 --- /dev/null +++ b/hooks/charmhelpers/contrib/openstack/templates/zeromq @@ -0,0 +1,14 @@ +{% if zmq_host -%} +# ZeroMQ configuration (restart-nonce: {{ zmq_nonce }}) +rpc_backend = zmq +rpc_zmq_host = {{ zmq_host }} +{% if zmq_redis_address -%} +rpc_zmq_matchmaker = oslo.messaging._drivers.matchmaker_redis.MatchMakerRedis +matchmaker_heartbeat_freq = 15 +matchmaker_heartbeat_ttl = 30 +[matchmaker_redis] +host = {{ zmq_redis_address }} +{% else -%} +rpc_zmq_matchmaker = oslo.messaging._drivers.matchmaker_ring.MatchMakerRing +{% endif -%} +{% endif -%} diff --git a/hooks/charmhelpers/contrib/openstack/utils.py b/hooks/charmhelpers/contrib/openstack/utils.py index af2b3596..4f110c63 100644 --- a/hooks/charmhelpers/contrib/openstack/utils.py +++ b/hooks/charmhelpers/contrib/openstack/utils.py @@ -23,12 +23,13 @@ from functools import wraps import subprocess import json import os -import socket import sys import six import yaml +from charmhelpers.contrib.network import ip + from charmhelpers.core.hookenv import ( config, log as juju_log, @@ -421,77 +422,10 @@ def clean_storage(block_device): else: zap_disk(block_device) - -def is_ip(address): - """ - Returns True if address is a valid IP address. - """ - try: - # Test to see if already an IPv4 address - socket.inet_aton(address) - return True - except socket.error: - return False - - -def ns_query(address): - try: - import dns.resolver - except ImportError: - apt_install('python-dnspython') - import dns.resolver - - if isinstance(address, dns.name.Name): - rtype = 'PTR' - elif isinstance(address, six.string_types): - rtype = 'A' - else: - return None - - answers = dns.resolver.query(address, rtype) - if answers: - return str(answers[0]) - return None - - -def get_host_ip(hostname): - """ - Resolves the IP for a given hostname, or returns - the input if it is already an IP. - """ - if is_ip(hostname): - return hostname - - return ns_query(hostname) - - -def get_hostname(address, fqdn=True): - """ - Resolves hostname for given IP, or returns the input - if it is already a hostname. - """ - if is_ip(address): - try: - import dns.reversename - except ImportError: - apt_install('python-dnspython') - import dns.reversename - - rev = dns.reversename.from_address(address) - result = ns_query(rev) - if not result: - return None - else: - result = address - - if fqdn: - # strip trailing . - if result.endswith('.'): - return result[:-1] - else: - return result - else: - return result.split('.')[0] +is_ip = ip.is_ip +ns_query = ip.ns_query +get_host_ip = ip.get_host_ip +get_hostname = ip.get_hostname def get_matchmaker_map(mm_file='/etc/oslo/matchmaker_ring.json'): diff --git a/hooks/charmhelpers/core/services/helpers.py b/hooks/charmhelpers/core/services/helpers.py index 5e3af9da..15b21664 100644 --- a/hooks/charmhelpers/core/services/helpers.py +++ b/hooks/charmhelpers/core/services/helpers.py @@ -45,12 +45,14 @@ class RelationContext(dict): """ name = None interface = None - required_keys = [] def __init__(self, name=None, additional_required_keys=None): + if not hasattr(self, 'required_keys'): + self.required_keys = [] + if name is not None: self.name = name - if additional_required_keys is not None: + if additional_required_keys: self.required_keys.extend(additional_required_keys) self.get_data() @@ -134,7 +136,10 @@ class MysqlRelation(RelationContext): """ name = 'db' interface = 'mysql' - required_keys = ['host', 'user', 'password', 'database'] + + def __init__(self, *args, **kwargs): + self.required_keys = ['host', 'user', 'password', 'database'] + super(HttpRelation).__init__(self, *args, **kwargs) class HttpRelation(RelationContext): @@ -146,7 +151,10 @@ class HttpRelation(RelationContext): """ name = 'website' interface = 'http' - required_keys = ['host', 'port'] + + def __init__(self, *args, **kwargs): + self.required_keys = ['host', 'port'] + super(HttpRelation).__init__(self, *args, **kwargs) def provide_data(self): return { From 4ae7872361ddbb96c11a05fa49a9cf4d5fa25944 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 3 Mar 2015 11:22:18 +0800 Subject: [PATCH 33/43] more --- config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.yaml b/config.yaml index 133587ca..e895ba80 100644 --- a/config.yaml +++ b/config.yaml @@ -60,8 +60,8 @@ options: A space-separated list of NICs that we want phy-nic-mtu applied to. phy-nic-mtu: type: int - default: 0 + default: description: | To improve network performance of VM, sometimes we should keep VM MTU as 1500 and use charm to modify MTU of tunnel nic more than 1500 (e.g. 1546 - for GRE). A value of zero means no mtu will be set/modified. + for GRE). From c1cb8839c438e704ffd54001c23cbf6cba07f81a Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 3 Mar 2015 13:48:05 +0800 Subject: [PATCH 34/43] more --- hooks/charmhelpers/contrib/openstack/neutron.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/hooks/charmhelpers/contrib/openstack/neutron.py b/hooks/charmhelpers/contrib/openstack/neutron.py index 76a90011..818ece57 100644 --- a/hooks/charmhelpers/contrib/openstack/neutron.py +++ b/hooks/charmhelpers/contrib/openstack/neutron.py @@ -264,8 +264,19 @@ def parse_bridge_mappings(mappings): def parse_data_port_mappings(mappings): """Parse data port mappings. - Mappings must be a space-delimited list of provider:port mappings. + Mappings must be a space-delimited list of bridge:port mappings. - Returns dict of the form {provider:port}. + Returns dict of the form {bridge:port}. """ - return parse_mappings(mappings) + mappings = parse_mappings(mappings) + bridges = mappings.keys() + ports = mappings.values() + if len(set(bridges)) != len(bridges): + raise Exception("It is not allowed to have more than one port " + "configured on the same bridge") + + if len(set(ports)) != len(ports): + raise Exception("It is not allowed to have the same port configured " + "on more than one bridge") + + return mappings From 5859ad0d869d79ba2278d74f7a0a10eb3bc96290 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 3 Mar 2015 13:55:30 +0800 Subject: [PATCH 35/43] more --- hooks/neutron_ovs_context.py | 6 +++--- unit_tests/test_neutron_ovs_context.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 4be53988..303003a8 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -72,7 +72,7 @@ class DataPortContext(NeutronPortContext): normalized.update({port: port for port in resolved if port in ports}) if resolved: - return {provider: normalized[port] for provider, port in + return {bridge: normalized[port] for bridge, port in portmap.iteritems() if port in normalized.keys()} return None @@ -105,10 +105,10 @@ class OVSPluginContext(context.NeutronContext): for provider, br in bridgemaps.iteritems(): add_bridge(br) - if not portmaps or provider not in portmaps: + if not portmaps or br not in portmaps: continue - add_bridge_port(br, portmaps[provider], promisc=True) + add_bridge_port(br, portmaps[br], promisc=True) service_restart('os-charm-phy-nic-mtu') diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index 5e93b5e8..1f8723c5 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -33,10 +33,10 @@ class OVSPluginContextTest(CharmTestCase): @patch('charmhelpers.contrib.openstack.context.NeutronPortContext.' 'resolve_ports') def test_data_port_name(self, mock_resolve_ports): - self.test_config.set('data-port', 'phybr1:em1') + self.test_config.set('data-port', 'br-data:em1') mock_resolve_ports.side_effect = lambda ports: ports self.assertEquals(context.DataPortContext()(), - {'phybr1': 'em1'}) + {'br-data': 'em1'}) @patch.object(context, 'get_nic_hwaddr') @patch('charmhelpers.contrib.openstack.context.get_nic_hwaddr') @@ -48,18 +48,18 @@ class OVSPluginContextTest(CharmTestCase): } get_nic_hwaddr2.side_effect = lambda nic: machine_machs[nic] absent_mac = "cc:cc:cc:cc:cc:cc" - config_macs = ("phybr2:%s phybr1:%s" % + config_macs = ("br-d1:%s br-d2:%s" % (absent_mac, machine_machs['em1'])) self.test_config.set('data-port', config_macs) list_nics.return_value = machine_machs.keys() get_nic_hwaddr.side_effect = lambda nic: machine_machs[nic] self.assertEquals(context.DataPortContext()(), - {'phybr1': 'em1'}) + {'br-d2': 'em1'}) @patch('charmhelpers.contrib.openstack.context.NeutronPortContext.' 'resolve_ports') def test_ensure_bridge_data_port_present(self, mock_resolve_ports): - self.test_config.set('data-port', 'phybr1:em1') + self.test_config.set('data-port', 'br-data:em1') self.test_config.set('bridge-mappings', 'phybr1:br-data') def add_port(bridge, port, promisc): From 6c466e2c8736204fc77bb38335108f71973da319 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 3 Mar 2015 14:06:50 +0800 Subject: [PATCH 36/43] more --- .../charmhelpers/contrib/openstack/neutron.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/hooks/charmhelpers/contrib/openstack/neutron.py b/hooks/charmhelpers/contrib/openstack/neutron.py index 818ece57..a0e0d836 100644 --- a/hooks/charmhelpers/contrib/openstack/neutron.py +++ b/hooks/charmhelpers/contrib/openstack/neutron.py @@ -239,10 +239,10 @@ def network_manager(): return 'neutron' -def parse_mappings(mappings): +def parse_mappings(mappings, delimiter=' '): parsed = {} if mappings: - mappings = mappings.split(' ') + mappings = mappings.split(delimiter) for m in mappings: p = m.partition(':') if p[1] == ':': @@ -280,3 +280,18 @@ def parse_data_port_mappings(mappings): "on more than one bridge") return mappings + + +def parse_vlan_range_mappings(mappings): + """Parse vlan range mappings. + + Mappings must be a space-delimited list of provider:start:end mappings. + + Returns dict of the form {provider: (start, end)}. + """ + _mappings = parse_mappings(mappings) + mappings = {} + for p, r in _mappings.iteritems(): + mappings[p] = tuple(r.split(':')) + + return mappings From 53bfb48db393711c932c88c88aeb49e8a16bae4b Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 3 Mar 2015 14:24:10 +0800 Subject: [PATCH 37/43] more --- hooks/neutron_ovs_context.py | 8 ++++++++ templates/icehouse/ml2_conf.ini | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 303003a8..e860c424 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -18,6 +18,7 @@ from charmhelpers.contrib.network.ip import get_address_in_network from charmhelpers.contrib.openstack.neutron import ( parse_bridge_mappings, parse_data_port_mappings, + parse_vlan_range_mappings, ) from charmhelpers.contrib.openstack.context import ( NeutronPortContext, @@ -148,6 +149,13 @@ class OVSPluginContext(context.NeutronContext): if mappings: ovs_ctxt['bridge_mappings'] = mappings + vlan_ranges = config('vlan-ranges') + vlan_range_mappings = parse_vlan_range_mappings(config('vlan-ranges')) + if vlan_ranges: + providers = vlan_range_mappings.keys() + ovs_ctxt['network_providers'] = ' '.join(providers) + ovs_ctxt['vlan_ranges'] = vlan_ranges + return ovs_ctxt diff --git a/templates/icehouse/ml2_conf.ini b/templates/icehouse/ml2_conf.ini index 575953d8..f2aa23e3 100644 --- a/templates/icehouse/ml2_conf.ini +++ b/templates/icehouse/ml2_conf.ini @@ -16,10 +16,10 @@ tunnel_id_ranges = 1:1000 vni_ranges = 1001:2000 [ml2_type_vlan] -network_vlan_ranges = physnet1:1000:2000 +network_vlan_ranges = {{ vlan_ranges }} [ml2_type_flat] -flat_networks = physnet1 +flat_networks = {{ network_providers }} [ovs] enable_tunneling = True From 5a9ed17832bd94f6b6b1e07d23d8a992397402ff Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 3 Mar 2015 15:03:44 +0800 Subject: [PATCH 38/43] more --- config.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/config.yaml b/config.yaml index e895ba80..b057e6d8 100644 --- a/config.yaml +++ b/config.yaml @@ -25,8 +25,10 @@ options: type: string default: description: | - The data port will be added to br-data and will allow usage of flat or VLAN - network types + Space-delimited list of bridge:port mappings. Ports will be added to + their corresponding bridge. The bridges will allow usage of flat or + VLAN network types with Neutron and should match this defined in + bridge-mappings. disable-security-groups: type: boolean default: false @@ -40,7 +42,7 @@ options: type: string default: 'physnet1:br-data' description: | - Space-separated list of ML2 data bridge mappings with format + Space-delimited list of ML2 data bridge mappings with format :. # Network configuration options # by default all access is over 'private-address' From 3c8903f5aecb89503dd10781758b82e88c0864dc Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Tue, 3 Mar 2015 15:21:26 +0800 Subject: [PATCH 39/43] more --- .../charmhelpers/contrib/openstack/neutron.py | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/hooks/charmhelpers/contrib/openstack/neutron.py b/hooks/charmhelpers/contrib/openstack/neutron.py index a0e0d836..89ca435a 100644 --- a/hooks/charmhelpers/contrib/openstack/neutron.py +++ b/hooks/charmhelpers/contrib/openstack/neutron.py @@ -239,10 +239,10 @@ def network_manager(): return 'neutron' -def parse_mappings(mappings, delimiter=' '): +def parse_mappings(mappings): parsed = {} if mappings: - mappings = mappings.split(delimiter) + mappings = mappings.split(' ') for m in mappings: p = m.partition(':') if p[1] == ':': @@ -261,16 +261,24 @@ def parse_bridge_mappings(mappings): return parse_mappings(mappings) -def parse_data_port_mappings(mappings): +def parse_data_port_mappings(mappings, default_bridge='br-data'): """Parse data port mappings. Mappings must be a space-delimited list of bridge:port mappings. Returns dict of the form {bridge:port}. """ - mappings = parse_mappings(mappings) - bridges = mappings.keys() - ports = mappings.values() + _mappings = parse_mappings(mappings) + if not _mappings: + if not mappings: + return {} + + # For backwards-compatibility we need to support port-only provided in + # config. + _mappings = {default_bridge: mappings.split(' ')[0]} + + bridges = _mappings.keys() + ports = _mappings.values() if len(set(bridges)) != len(bridges): raise Exception("It is not allowed to have more than one port " "configured on the same bridge") @@ -279,7 +287,7 @@ def parse_data_port_mappings(mappings): raise Exception("It is not allowed to have the same port configured " "on more than one bridge") - return mappings + return _mappings def parse_vlan_range_mappings(mappings): @@ -290,6 +298,9 @@ def parse_vlan_range_mappings(mappings): Returns dict of the form {provider: (start, end)}. """ _mappings = parse_mappings(mappings) + if not _mappings: + return {} + mappings = {} for p, r in _mappings.iteritems(): mappings[p] = tuple(r.split(':')) From b00416f1c6741610594c14344c3ac48bc92c2a6d Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Thu, 12 Mar 2015 10:32:45 +0000 Subject: [PATCH 40/43] phy-nic* > get value from data-port config param --- config.yaml | 12 ------------ hooks/neutron_ovs_context.py | 17 ++++++++--------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/config.yaml b/config.yaml index b057e6d8..60670e0e 100644 --- a/config.yaml +++ b/config.yaml @@ -55,15 +55,3 @@ options: . This network will be used for tenant network traffic in overlay networks. - phy-nics: - type: string - default: - description: | - A space-separated list of NICs that we want phy-nic-mtu applied to. - phy-nic-mtu: - type: int - default: - description: | - To improve network performance of VM, sometimes we should keep VM MTU as - 1500 and use charm to modify MTU of tunnel nic more than 1500 (e.g. 1546 - for GRE). diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index e860c424..aa66ffb7 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -20,9 +20,6 @@ from charmhelpers.contrib.openstack.neutron import ( parse_data_port_mappings, parse_vlan_range_mappings, ) -from charmhelpers.contrib.openstack.context import ( - NeutronPortContext, -) from charmhelpers.core.host import ( get_nic_hwaddr, ) @@ -60,7 +57,7 @@ def _neutron_api_settings(): return neutron_settings -class DataPortContext(NeutronPortContext): +class DataPortContext(context.NeutronPortContext): def __call__(self): ports = config('data-port') @@ -159,15 +156,17 @@ class OVSPluginContext(context.NeutronContext): return ovs_ctxt -class PhyNICMTUContext(context.NeutronPortContext): +class PhyNICMTUContext(DataPortContext): def __call__(self): ctxt = {} - port = config('phy-nics') - if port: - ctxt = {"devs": port.replace(' ', '\\n')} - mtu = config('phy-nic-mtu') + mappings = super(PhyNICMTUContext, self).__call__() + if mappings and mappings.values(): + ports = mappings.values() + neutron_api_settings = _neutron_api_settings() + mtu = neutron_api_settings.get('network_device_mtu') if mtu: + ctxt['devs'] = '\\n'.join(ports) ctxt['mtu'] = mtu return ctxt From f4ead6d24be82d7b995d677d9b858ee92ab32cf3 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Mon, 16 Mar 2015 16:36:48 +0100 Subject: [PATCH 41/43] cleanup --- charm-helpers-sync.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charm-helpers-sync.yaml b/charm-helpers-sync.yaml index 755e5ae1..9b5e79e9 100644 --- a/charm-helpers-sync.yaml +++ b/charm-helpers-sync.yaml @@ -1,4 +1,4 @@ -branch: lp:~cts-engineering/charm-helpers/neutron-mtu +branch: lp:charm-helpers destination: hooks/charmhelpers include: - core From 869669a926521ef428329ed5ca9e0a1096e9b996 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Mon, 16 Mar 2015 18:43:06 +0000 Subject: [PATCH 42/43] added vlan-ranges config --- config.yaml | 5 +++++ hooks/neutron_ovs_context.py | 18 ++++++++---------- unit_tests/test_neutron_ovs_context.py | 8 ++++++-- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/config.yaml b/config.yaml index 60670e0e..41699d49 100644 --- a/config.yaml +++ b/config.yaml @@ -44,6 +44,11 @@ options: description: | Space-delimited list of ML2 data bridge mappings with format :. + vlan-ranges: + type: string + default: "physnet1:1000:2000" + description: | + Space-delimited list of network provider vlan id ranges. # Network configuration options # by default all access is over 'private-address' os-data-network: diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index aa66ffb7..0474ead5 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -39,21 +39,18 @@ def _neutron_api_settings(): for rid in relation_ids('neutron-plugin-api'): for unit in related_units(rid): rdata = relation_get(rid=rid, unit=unit) - if 'l2-population' not in rdata: - continue - neutron_settings = { - 'l2_population': bool_from_string(rdata['l2-population']), - 'overlay_network_type': rdata['overlay-network-type'], - 'neutron_security_groups': bool_from_string( - rdata['neutron-security-groups'] - ), - } + if 'l2-population' in rdata: + neutron_settings.update({ + 'l2_population': bool_from_string(rdata['l2-population']), + 'overlay_network_type': rdata['overlay-network-type'], + 'neutron_security_groups': + bool_from_string(rdata['neutron-security-groups']) + }) net_dev_mtu = rdata.get('network-device-mtu') if net_dev_mtu: neutron_settings['network_device_mtu'] = net_dev_mtu - return neutron_settings return neutron_settings @@ -157,6 +154,7 @@ class OVSPluginContext(context.NeutronContext): class PhyNICMTUContext(DataPortContext): + """Context used to apply settings to neutron data-port devices""" def __call__(self): ctxt = {} diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index 1f8723c5..515636c2 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -121,7 +121,9 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_url': 'https://127.0.0.13:9696', 'l2_population': True, 'overlay_network_type': 'gre', - 'bridge_mappings': 'physnet1:br-data' + 'network_providers': 'physnet1', + 'bridge_mappings': 'physnet1:br-data', + 'vlan_ranges': 'physnet1:1000:2000', } self.assertEquals(expect, napi_ctxt()) self.service_start.assertCalled() @@ -179,7 +181,9 @@ class OVSPluginContextTest(CharmTestCase): 'neutron_url': 'https://127.0.0.13:9696', 'l2_population': True, 'overlay_network_type': 'gre', - 'bridge_mappings': 'physnet1:br-data' + 'network_providers': 'physnet1', + 'bridge_mappings': 'physnet1:br-data', + 'vlan_ranges': 'physnet1:1000:2000', } self.assertEquals(expect, napi_ctxt()) self.service_start.assertCalled() From dfaded587481f8ed1f8a1c38bb1867a22c2cdd40 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Wed, 18 Mar 2015 18:23:06 +0100 Subject: [PATCH 43/43] fix bad remove sec_group disable --- hooks/neutron_ovs_context.py | 4 ++++ unit_tests/test_neutron_ovs_context.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 0474ead5..4c6febf5 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -47,6 +47,10 @@ def _neutron_api_settings(): bool_from_string(rdata['neutron-security-groups']) }) + # Override with configuration if set to true + if config('disable-security-groups'): + neutron_settings['neutron_security_groups'] = False + net_dev_mtu = rdata.get('network-device-mtu') if net_dev_mtu: neutron_settings['network_device_mtu'] = net_dev_mtu diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index 515636c2..a7da378b 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -167,7 +167,7 @@ class OVSPluginContextTest(CharmTestCase): napi_ctxt = context.OVSPluginContext() expect = { 'neutron_alchemy_flags': {}, - 'neutron_security_groups': True, + 'neutron_security_groups': False, 'verbose': True, 'local_ip': '127.0.0.15', 'veth_mtu': 1500,