diff --git a/charm-helpers-hooks.yaml b/charm-helpers-hooks.yaml index 84cc6c76..0b5106d1 100644 --- a/charm-helpers-hooks.yaml +++ b/charm-helpers-hooks.yaml @@ -1,4 +1,5 @@ -branch: lp:charm-helpers +#branch: lp:charm-helpers +branch: lp:~gnuoy/charm-helpers/neutron-shuffle destination: hooks/charmhelpers include: - core 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/quantum_contexts.py b/hooks/quantum_contexts.py index 853f178b..b6b1ef19 100644 --- a/hooks/quantum_contexts.py +++ b/hooks/quantum_contexts.py @@ -17,6 +17,7 @@ from charmhelpers.contrib.openstack.context import ( OSContextGenerator, context_complete, NeutronPortContext, + NeutronAPIContext, ) from charmhelpers.contrib.openstack.utils import ( get_os_codename_install_source @@ -106,75 +107,10 @@ def core_plugin(): return CORE_PLUGIN[networking_name()][plugin] -def neutron_api_settings(): - ''' - Inspects current neutron-plugin-api relation for neutron settings. Return - defaults if it is not present - ''' - NEUTRON_DEFAULTS = { - 'l2_population': {'rel_key': 'l2-population', 'default': False}, - 'enable_dvr': {'rel_key': 'enable-dvr', 'default': False}, - 'enable_l3ha': {'rel_key': 'enable-l3ha', 'default': False}, - 'overlay_network_type': {'rel_key': 'overlay-network-type', 'default': 'gre'}, - 'network_device_mtu': {'rel_key': 'network-device-mtu', 'default': None}, - } - - def get_neutron_options(rdata): - settings = {} - for nkey in NEUTRON_DEFAULTS.keys(): - defv = NEUTRON_DEFAULTS[nkey]['default'] - rkey = 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] - elif defv is not None: - settings[nkey] = defv - return settings - - neutron_settings = 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 relation_get(rid=rid, unit=unit): - neutron_settings.update(get_neutron_options(rdata)) - - return neutron_settings - - -class NetworkServiceContext(OSContextGenerator): - interfaces = ['quantum-network-service'] - - def __call__(self): - for rid in relation_ids('quantum-network-service'): - 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 {} - - class L3AgentContext(OSContextGenerator): def __call__(self): - api_settings = neutron_api_settings() + api_settings = NeutronAPIContext()() ctxt = {} if config('run-internal-router') == 'leader': ctxt['handle_internal_only_router'] = eligible_leader(None) @@ -196,63 +132,10 @@ class L3AgentContext(OSContextGenerator): return ctxt -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 = neutron_api_settings() - 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 - portmap.iteritems() 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 = neutron_api_settings() - mtu = napi_settings.get('network_device_mtu') - if mtu: - ctxt["devs"] = '\\n'.join(ports) - ctxt['mtu'] = mtu - - return ctxt - - class QuantumGatewayContext(OSContextGenerator): def __call__(self): - api_settings = neutron_api_settings() + api_settings = NeutronAPIContext()() ctxt = { 'shared_secret': get_shared_secret(), 'local_ip': @@ -281,7 +164,7 @@ class QuantumGatewayContext(OSContextGenerator): ctxt['network_providers'] = ' '.join(providers) ctxt['vlan_ranges'] = vlan_ranges - net_dev_mtu = neutron_api_settings().get('network_device_mtu') + net_dev_mtu = api_settings['network_device_mtu'] if net_dev_mtu: ctxt['network_device_mtu'] = net_dev_mtu ctxt['veth_mtu'] = net_dev_mtu diff --git a/hooks/quantum_utils.py b/hooks/quantum_utils.py index 6583b860..04beae1b 100644 --- a/hooks/quantum_utils.py +++ b/hooks/quantum_utils.py @@ -41,7 +41,12 @@ from charmhelpers.contrib.openstack.neutron import ( import charmhelpers.contrib.openstack.context as context from charmhelpers.contrib.openstack.context import ( - SyslogContext + SyslogContext, + NeutronAPIContext, + ExternalPortContext, + PhyNICMTUContext, + DataPortContext, + NetworkServiceContext, ) import charmhelpers.contrib.openstack.templating as templating from charmhelpers.contrib.openstack.neutron import headers_package @@ -50,13 +55,8 @@ from quantum_contexts import ( NEUTRON, QUANTUM, networking_name, QuantumGatewayContext, - NetworkServiceContext, L3AgentContext, - ExternalPortContext, - PhyNICMTUContext, - DataPortContext, remap_plugin, - neutron_api_settings, ) from charmhelpers.contrib.openstack.neutron import ( parse_bridge_mappings, @@ -221,7 +221,7 @@ def get_common_package(): def use_l3ha(): - return neutron_api_settings()['enable_l3ha'] + return NeutronAPIContext()()['enable_l3ha'] EXT_PORT_CONF = '/etc/init/ext-port.conf' PHY_NIC_MTU_CONF = '/etc/init/os-charm-phy-nic-mtu.conf' diff --git a/unit_tests/test_quantum_utils.py b/unit_tests/test_quantum_utils.py index 6be942a8..7fa472c6 100644 --- a/unit_tests/test_quantum_utils.py +++ b/unit_tests/test_quantum_utils.py @@ -46,7 +46,7 @@ TO_PATCH = [ 'lsb_release', 'mkdir', 'copy2', - 'neutron_api_settings', + 'NeutronAPIContext', ] @@ -144,7 +144,7 @@ class TestQuantumUtils(CharmTestCase): self.get_os_codename_install_source.return_value = 'juno' self.assertTrue('keepalived' in quantum_utils.get_packages()) - @patch('quantum_contexts.config') + @patch('charmhelpers.contrib.openstack.context.config') def test_configure_ovs_starts_service_if_required(self, mock_config): mock_config.side_effect = self.test_config.get self.config.return_value = 'ovs' @@ -157,7 +157,7 @@ class TestQuantumUtils(CharmTestCase): quantum_utils.configure_ovs() self.assertFalse(self.full_restart.called) - @patch('quantum_contexts.config') + @patch('charmhelpers.contrib.openstack.context.config') def test_configure_ovs_ovs_ext_port(self, mock_config): mock_config.side_effect = self.test_config.get self.config.side_effect = self.test_config.get @@ -173,7 +173,7 @@ class TestQuantumUtils(CharmTestCase): ]) self.add_bridge_port.assert_called_with('br-ex', 'eth0') - @patch('quantum_contexts.config') + @patch('charmhelpers.contrib.openstack.context.config') def test_configure_ovs_ovs_data_port(self, mock_config): mock_config.side_effect = self.test_config.get self.config.side_effect = self.test_config.get