From 78b14f6e899a6b3660690eae3fc5ee717976ac23 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Tue, 24 Mar 2015 13:39:11 +0000 Subject: [PATCH] Update after some contexts moved to charm helpers --- .../charmhelpers/contrib/openstack/context.py | 145 +++++++++++++++++- hooks/neutron_ovs_context.py | 86 +---------- hooks/neutron_ovs_utils.py | 2 +- unit_tests/test_neutron_ovs_context.py | 63 +++++--- 4 files changed, 191 insertions(+), 105 deletions(-) diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index 90ac6d69..45e65790 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -47,6 +47,7 @@ from charmhelpers.core.hookenv import ( ) from charmhelpers.core.sysctl import create as sysctl_create +from charmhelpers.core.strutils import bool_from_string from charmhelpers.core.host import ( list_nics, @@ -67,6 +68,7 @@ from charmhelpers.contrib.hahelpers.apache import ( ) from charmhelpers.contrib.openstack.neutron import ( neutron_plugin_attribute, + parse_data_port_mappings, ) from charmhelpers.contrib.openstack.ip import ( resolve_address, @@ -82,7 +84,6 @@ from charmhelpers.contrib.network.ip import ( is_bridge_member, ) from charmhelpers.contrib.openstack.utils import get_host_ip - CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt' ADDRESS_TYPES = ['admin', 'internal', 'public'] @@ -1162,3 +1163,145 @@ class SysctlContext(OSContextGenerator): sysctl_create(sysctl_dict, '/etc/sysctl.d/50-{0}.conf'.format(charm_name())) return {'sysctl': sysctl_dict} + + +class NeutronAPIContext(OSContextGenerator): + ''' + Inspects current neutron-plugin-api relation for neutron settings. Return + defaults if it is not present. + ''' + interfaces = ['neutron-plugin-api'] + + def __call__(self): + self.neutron_defaults = { + 'l2_population': { + 'rel_key': 'l2-population', + 'default': False, + }, + 'overlay_network_type': { + 'rel_key': 'overlay-network-type', + 'default': 'gre', + }, + 'neutron_security_groups': { + 'rel_key': 'neutron-security-groups', + 'default': False, + }, + 'network_device_mtu': { + 'rel_key': 'network-device-mtu', + 'default': None, + }, + 'enable_dvr': { + 'rel_key': 'enable-dvr', + 'default': False, + }, + 'enable_l3ha': { + 'rel_key': 'enable-l3ha', + 'default': False, + }, + } + ctxt = self.get_neutron_options({}) + for rid in relation_ids('neutron-plugin-api'): + for unit in related_units(rid): + rdata = relation_get(rid=rid, unit=unit) + if 'l2-population' in rdata: + ctxt.update(self.get_neutron_options(rdata)) + + return ctxt + + def get_neutron_options(self, rdata): + settings = {} + for nkey in self.neutron_defaults.keys(): + defv = self.neutron_defaults[nkey]['default'] + rkey = self.neutron_defaults[nkey]['rel_key'] + if rkey in rdata.keys(): + if type(defv) is bool: + settings[nkey] = bool_from_string(rdata[rkey]) + else: + settings[nkey] = rdata[rkey] + else: + settings[nkey] = defv + return settings + + +class ExternalPortContext(NeutronPortContext): + + def __call__(self): + ctxt = {} + ports = config('ext-port') + if ports: + ports = [p.strip() for p in ports.split()] + ports = self.resolve_ports(ports) + if ports: + ctxt = {"ext_port": ports[0]} + napi_settings = NeutronAPIContext()() + mtu = napi_settings.get('network_device_mtu') + if mtu: + ctxt['ext_port_mtu'] = mtu + + return ctxt + + +class DataPortContext(NeutronPortContext): + + 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 {bridge: normalized[port] for bridge, port in + six.iteritems(portmap) if port in normalized.keys()} + + return None + + +class PhyNICMTUContext(DataPortContext): + + def __call__(self): + ctxt = {} + mappings = super(PhyNICMTUContext, self).__call__() + if mappings and mappings.values(): + ports = mappings.values() + napi_settings = NeutronAPIContext()() + mtu = napi_settings.get('network_device_mtu') + if mtu: + ctxt["devs"] = '\\n'.join(ports) + ctxt['mtu'] = mtu + + return ctxt + + +class NetworkServiceContext(OSContextGenerator): + + def __init__(self, rel_name='quantum-network-service'): + self.rel_name = rel_name + self.interfaces = [rel_name] + + def __call__(self): + for rid in relation_ids(self.rel_name): + for unit in related_units(rid): + rdata = relation_get(rid=rid, unit=unit) + ctxt = { + 'keystone_host': rdata.get('keystone_host'), + 'service_port': rdata.get('service_port'), + 'auth_port': rdata.get('auth_port'), + 'service_tenant': rdata.get('service_tenant'), + 'service_username': rdata.get('service_username'), + 'service_password': rdata.get('service_password'), + 'quantum_host': rdata.get('quantum_host'), + 'quantum_port': rdata.get('quantum_port'), + 'quantum_url': rdata.get('quantum_url'), + 'region': rdata.get('region'), + 'service_protocol': + rdata.get('service_protocol') or 'http', + 'auth_protocol': + rdata.get('auth_protocol') or 'http', + } + if context_complete(ctxt): + return ctxt + return {} diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index 4c6febf5..46ae4e7d 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -1,11 +1,7 @@ from charmhelpers.core.hookenv import ( - relation_ids, - related_units, - relation_get, config, unit_get, ) -from charmhelpers.core.strutils import bool_from_string from charmhelpers.contrib.openstack import context from charmhelpers.core.host import ( service_running, @@ -15,68 +11,17 @@ 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 +from charmhelpers.contrib.openstack.context import ( + NeutronAPIContext, + DataPortContext, +) from charmhelpers.contrib.openstack.neutron import ( parse_bridge_mappings, - parse_data_port_mappings, parse_vlan_range_mappings, ) -from charmhelpers.core.host import ( - get_nic_hwaddr, -) OVS_BRIDGE = 'br-int' -def _neutron_api_settings(): - ''' - Inspects current neutron-plugin relation - ''' - neutron_settings = { - 'neutron_security_groups': False, - 'l2_population': True, - 'overlay_network_type': 'gre', - } - - for rid in relation_ids('neutron-plugin-api'): - for unit in related_units(rid): - rdata = relation_get(rid=rid, unit=unit) - 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']) - }) - - # 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 - - return neutron_settings - - -class DataPortContext(context.NeutronPortContext): - - 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 {bridge: normalized[port] for bridge, port in - portmap.iteritems() if port in normalized.keys()} - - return None - - class OVSPluginContext(context.NeutronContext): interfaces = [] @@ -90,7 +35,9 @@ class OVSPluginContext(context.NeutronContext): @property def neutron_security_groups(self): - neutron_api_settings = _neutron_api_settings() + if config('disable-security-groups'): + return False + neutron_api_settings = NeutronAPIContext()() return neutron_api_settings['neutron_security_groups'] def _ensure_bridge(self): @@ -125,7 +72,7 @@ class OVSPluginContext(context.NeutronContext): ovs_ctxt['local_ip'] = \ get_address_in_network(config('os-data-network'), get_host_ip(unit_get('private-address'))) - neutron_api_settings = _neutron_api_settings() + neutron_api_settings = NeutronAPIContext()() ovs_ctxt['neutron_security_groups'] = self.neutron_security_groups ovs_ctxt['l2_population'] = neutron_api_settings['l2_population'] ovs_ctxt['overlay_network_type'] = \ @@ -155,20 +102,3 @@ class OVSPluginContext(context.NeutronContext): ovs_ctxt['vlan_ranges'] = vlan_ranges return ovs_ctxt - - -class PhyNICMTUContext(DataPortContext): - """Context used to apply settings to neutron data-port devices""" - - def __call__(self): - ctxt = {} - 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 diff --git a/hooks/neutron_ovs_utils.py b/hooks/neutron_ovs_utils.py index 5cc9871c..66b8a77b 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -28,7 +28,7 @@ BASE_RESOURCE_MAP = OrderedDict([ }), (PHY_NIC_MTU_CONF, { 'services': ['os-charm-phy-nic-mtu'], - 'contexts': [neutron_ovs_context.PhyNICMTUContext()], + 'contexts': [context.PhyNICMTUContext()], }), ]) diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index a7da378b..5423b5ab 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -4,15 +4,13 @@ from mock import patch import neutron_ovs_context as context import charmhelpers TO_PATCH = [ - 'relation_get', - 'relation_ids', - 'related_units', 'config', 'unit_get', 'add_bridge', 'add_bridge_port', 'service_running', 'service_start', + 'service_restart', 'get_host_ip', ] @@ -21,7 +19,6 @@ class OVSPluginContextTest(CharmTestCase): def setUp(self): super(OVSPluginContextTest, self).setUp(context, TO_PATCH) - self.relation_get.side_effect = self.test_relation.get self.config.side_effect = self.test_config.get self.test_config.set('debug', True) self.test_config.set('verbose', True) @@ -30,39 +27,44 @@ class OVSPluginContextTest(CharmTestCase): def tearDown(self): super(OVSPluginContextTest, self).tearDown() + @patch('charmhelpers.contrib.openstack.context.config') @patch('charmhelpers.contrib.openstack.context.NeutronPortContext.' 'resolve_ports') - def test_data_port_name(self, mock_resolve_ports): + def test_data_port_name(self, mock_resolve_ports, config): self.test_config.set('data-port', 'br-data:em1') + config.side_effect = self.test_config.get mock_resolve_ports.side_effect = lambda ports: ports self.assertEquals(context.DataPortContext()(), {'br-data': 'em1'}) - @patch.object(context, 'get_nic_hwaddr') + @patch('charmhelpers.contrib.openstack.context.config') @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): + def test_data_port_mac(self, list_nics, get_nic_hwaddr, config): 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 = ("br-d1:%s br-d2:%s" % (absent_mac, machine_machs['em1'])) self.test_config.set('data-port', config_macs) + config.side_effect = self.test_config.get list_nics.return_value = machine_machs.keys() get_nic_hwaddr.side_effect = lambda nic: machine_machs[nic] self.assertEquals(context.DataPortContext()(), {'br-d2': 'em1'}) + @patch('charmhelpers.contrib.openstack.context.config') @patch('charmhelpers.contrib.openstack.context.NeutronPortContext.' 'resolve_ports') - def test_ensure_bridge_data_port_present(self, mock_resolve_ports): + def test_ensure_bridge_data_port_present(self, mock_resolve_ports, config): self.test_config.set('data-port', 'br-data:em1') self.test_config.set('bridge-mappings', 'phybr1:br-data') + config.side_effect = self.test_config.get def add_port(bridge, port, promisc): + if bridge == 'br-data' and port == 'em1' and promisc is True: self.bridge_added = True return @@ -73,6 +75,9 @@ class OVSPluginContextTest(CharmTestCase): context.OVSPluginContext()._ensure_bridge() self.assertEquals(self.bridge_added, True) + @patch.object(charmhelpers.contrib.openstack.context, 'relation_get') + @patch.object(charmhelpers.contrib.openstack.context, 'relation_ids') + @patch.object(charmhelpers.contrib.openstack.context, 'related_units') @patch.object(charmhelpers.contrib.openstack.context, 'config') @patch.object(charmhelpers.contrib.openstack.context, 'unit_get') @patch.object(charmhelpers.contrib.openstack.context, 'is_clustered') @@ -84,7 +89,7 @@ class OVSPluginContextTest(CharmTestCase): @patch.object(charmhelpers.contrib.openstack.context, 'unit_private_ip') def test_neutroncc_context_api_rel(self, _unit_priv_ip, _npa, _ens_pkgs, _save_ff, _https, _is_clus, _unit_get, - _config): + _config, _runits, _rids, _rget): def mock_npa(plugin, section, manager): if section == "driver": return "neutron.randomdriver" @@ -95,13 +100,15 @@ class OVSPluginContextTest(CharmTestCase): _unit_get.return_value = '127.0.0.13' _unit_priv_ip.return_value = '127.0.0.14' _is_clus.return_value = False - self.related_units.return_value = ['unit1'] - 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', - }) + _runits.return_value = ['unit1'] + _rids.return_value = ['rid2'] + rdata = { + 'neutron-security-groups': 'True', + 'l2-population': 'True', + 'network-device-mtu': 1500, + 'overlay-network-type': 'gre', + } + _rget.side_effect = lambda *args, **kwargs: rdata self.get_host_ip.return_value = '127.0.0.15' self.service_running.return_value = False napi_ctxt = context.OVSPluginContext() @@ -128,6 +135,9 @@ class OVSPluginContextTest(CharmTestCase): self.assertEquals(expect, napi_ctxt()) self.service_start.assertCalled() + @patch.object(charmhelpers.contrib.openstack.context, 'relation_get') + @patch.object(charmhelpers.contrib.openstack.context, 'relation_ids') + @patch.object(charmhelpers.contrib.openstack.context, 'related_units') @patch.object(charmhelpers.contrib.openstack.context, 'config') @patch.object(charmhelpers.contrib.openstack.context, 'unit_get') @patch.object(charmhelpers.contrib.openstack.context, 'is_clustered') @@ -142,7 +152,8 @@ class OVSPluginContextTest(CharmTestCase): _ens_pkgs, _save_ff, _https, _is_clus, _unit_get, - _config): + _config, _runits, + _rids, _rget): def mock_npa(plugin, section, manager): if section == "driver": return "neutron.randomdriver" @@ -155,13 +166,15 @@ class OVSPluginContextTest(CharmTestCase): _unit_priv_ip.return_value = '127.0.0.14' _is_clus.return_value = False self.test_config.set('disable-security-groups', True) - self.related_units.return_value = ['unit1'] - 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', - }) + _runits.return_value = ['unit1'] + _rids.return_value = ['rid2'] + rdata = { + 'neutron-security-groups': 'True', + 'l2-population': 'True', + 'network-device-mtu': 1500, + 'overlay-network-type': 'gre', + } + _rget.side_effect = lambda *args, **kwargs: rdata self.get_host_ip.return_value = '127.0.0.15' self.service_running.return_value = False napi_ctxt = context.OVSPluginContext()