diff --git a/hooks/charmhelpers/contrib/charmsupport/nrpe.py b/hooks/charmhelpers/contrib/charmsupport/nrpe.py index 424b7f76..80d574dc 100644 --- a/hooks/charmhelpers/contrib/charmsupport/nrpe.py +++ b/hooks/charmhelpers/contrib/charmsupport/nrpe.py @@ -125,7 +125,7 @@ class CheckException(Exception): class Check(object): - shortname_re = '[A-Za-z0-9-_]+$' + shortname_re = '[A-Za-z0-9-_.]+$' service_template = (""" #--------------------------------------------------- # This file is Juju managed diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index 74ceb629..37528c47 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -517,7 +517,9 @@ class CephContext(OSContextGenerator): if not ctxt.get('key'): ctxt['key'] = relation_get('key', rid=rid, unit=unit) if not ctxt.get('rbd_features'): - ctxt['rbd_features'] = relation_get('rbd-features', rid=rid, unit=unit) + default_features = relation_get('rbd-features', rid=rid, unit=unit) + if default_features is not None: + ctxt['rbd_features'] = default_features ceph_addrs = relation_get('ceph-public-address', rid=rid, unit=unit) diff --git a/hooks/charmhelpers/contrib/openstack/utils.py b/hooks/charmhelpers/contrib/openstack/utils.py index d15a6317..5b88b33a 100644 --- a/hooks/charmhelpers/contrib/openstack/utils.py +++ b/hooks/charmhelpers/contrib/openstack/utils.py @@ -2051,7 +2051,7 @@ def snap_install_requested(): If openstack-origin is of the form snap:channel-series-release and channel is in SNAPS_CHANNELS return True. """ - origin = config('openstack-origin') + origin = config('openstack-origin') or "" if not origin.startswith('snap:'): return False diff --git a/hooks/charmhelpers/core/hookenv.py b/hooks/charmhelpers/core/hookenv.py index e44e22bf..fe7fd8c0 100644 --- a/hooks/charmhelpers/core/hookenv.py +++ b/hooks/charmhelpers/core/hookenv.py @@ -202,6 +202,27 @@ def service_name(): return local_unit().split('/')[0] +def principal_unit(): + """Returns the principal unit of this unit, otherwise None""" + # Juju 2.2 and above provides JUJU_PRINCIPAL_UNIT + principal_unit = os.environ.get('JUJU_PRINCIPAL_UNIT', None) + # If it's empty, then this unit is the principal + if principal_unit == '': + return os.environ['JUJU_UNIT_NAME'] + elif principal_unit is not None: + return principal_unit + # For Juju 2.1 and below, let's try work out the principle unit by + # the various charms' metadata.yaml. + for reltype in relation_types(): + for rid in relation_ids(reltype): + for unit in related_units(rid): + md = _metadata_unit(unit) + subordinate = md.pop('subordinate', None) + if not subordinate: + return unit + return None + + @cached def remote_service_name(relid=None): """The remote service name for a given relation-id (or the current relation)""" @@ -478,6 +499,21 @@ def metadata(): return yaml.safe_load(md) +def _metadata_unit(unit): + """Given the name of a unit (e.g. apache2/0), get the unit charm's + metadata.yaml. Very similar to metadata() but allows us to inspect + other units. Unit needs to be co-located, such as a subordinate or + principal/primary. + + :returns: metadata.yaml as a python object. + + """ + basedir = os.sep.join(charm_dir().split(os.sep)[:-2]) + unitdir = 'unit-{}'.format(unit.replace(os.sep, '-')) + with open(os.path.join(basedir, unitdir, 'charm', 'metadata.yaml')) as md: + return yaml.safe_load(md) + + @cached def relation_types(): """Get a list of relation types supported by this charm""" diff --git a/hooks/neutron_contexts.py b/hooks/neutron_contexts.py index cf0abcbf..fc16f88a 100644 --- a/hooks/neutron_contexts.py +++ b/hooks/neutron_contexts.py @@ -74,6 +74,8 @@ class L3AgentContext(OSContextGenerator): ctxt['agent_mode'] = 'dvr_snat' else: ctxt['agent_mode'] = 'legacy' + ctxt['rpc_response_timeout'] = api_settings['rpc_response_timeout'] + ctxt['report_interval'] = api_settings['report_interval'] return ctxt @@ -94,6 +96,8 @@ class NeutronGatewayContext(NeutronAPIContext): 'dns_domain': api_settings['dns_domain'], 'overlay_network_type': api_settings['overlay_network_type'], + 'rpc_response_timeout': api_settings['rpc_response_timeout'], + 'report_interval': api_settings['report_interval'], 'enable_metadata_network': config('enable-metadata-network'), 'enable_isolated_metadata': config('enable-isolated-metadata'), } diff --git a/templates/icehouse/neutron.conf b/templates/icehouse/neutron.conf index 6c14454e..4d5e9094 100644 --- a/templates/icehouse/neutron.conf +++ b/templates/icehouse/neutron.conf @@ -14,6 +14,8 @@ notification_driver = messaging network_device_mtu = {{ network_device_mtu }} {% endif -%} api_workers = {{ workers }} +rpc_response_timeout = {{ rpc_response_timeout }} [agent] root_helper = sudo /usr/bin/neutron-rootwrap /etc/neutron/rootwrap.conf +report_interval = {{ report_interval }} diff --git a/templates/kilo/neutron.conf b/templates/kilo/neutron.conf index 3d4772a4..e5f384f0 100644 --- a/templates/kilo/neutron.conf +++ b/templates/kilo/neutron.conf @@ -13,11 +13,13 @@ notification_driver = messaging network_device_mtu = {{ network_device_mtu }} {% endif -%} api_workers = {{ workers }} +rpc_response_timeout = {{ rpc_response_timeout }} {% include "section-zeromq" %} [agent] root_helper = sudo /usr/bin/neutron-rootwrap /etc/neutron/rootwrap.conf +report_interval = {{ report_interval }} {% include "section-rabbitmq-oslo" %} diff --git a/tests/charmhelpers/contrib/openstack/utils.py b/tests/charmhelpers/contrib/openstack/utils.py index d15a6317..5b88b33a 100644 --- a/tests/charmhelpers/contrib/openstack/utils.py +++ b/tests/charmhelpers/contrib/openstack/utils.py @@ -2051,7 +2051,7 @@ def snap_install_requested(): If openstack-origin is of the form snap:channel-series-release and channel is in SNAPS_CHANNELS return True. """ - origin = config('openstack-origin') + origin = config('openstack-origin') or "" if not origin.startswith('snap:'): return False diff --git a/tests/charmhelpers/core/hookenv.py b/tests/charmhelpers/core/hookenv.py index e44e22bf..fe7fd8c0 100644 --- a/tests/charmhelpers/core/hookenv.py +++ b/tests/charmhelpers/core/hookenv.py @@ -202,6 +202,27 @@ def service_name(): return local_unit().split('/')[0] +def principal_unit(): + """Returns the principal unit of this unit, otherwise None""" + # Juju 2.2 and above provides JUJU_PRINCIPAL_UNIT + principal_unit = os.environ.get('JUJU_PRINCIPAL_UNIT', None) + # If it's empty, then this unit is the principal + if principal_unit == '': + return os.environ['JUJU_UNIT_NAME'] + elif principal_unit is not None: + return principal_unit + # For Juju 2.1 and below, let's try work out the principle unit by + # the various charms' metadata.yaml. + for reltype in relation_types(): + for rid in relation_ids(reltype): + for unit in related_units(rid): + md = _metadata_unit(unit) + subordinate = md.pop('subordinate', None) + if not subordinate: + return unit + return None + + @cached def remote_service_name(relid=None): """The remote service name for a given relation-id (or the current relation)""" @@ -478,6 +499,21 @@ def metadata(): return yaml.safe_load(md) +def _metadata_unit(unit): + """Given the name of a unit (e.g. apache2/0), get the unit charm's + metadata.yaml. Very similar to metadata() but allows us to inspect + other units. Unit needs to be co-located, such as a subordinate or + principal/primary. + + :returns: metadata.yaml as a python object. + + """ + basedir = os.sep.join(charm_dir().split(os.sep)[:-2]) + unitdir = 'unit-{}'.format(unit.replace(os.sep, '-')) + with open(os.path.join(basedir, unitdir, 'charm', 'metadata.yaml')) as md: + return yaml.safe_load(md) + + @cached def relation_types(): """Get a list of relation types supported by this charm""" diff --git a/unit_tests/test_neutron_contexts.py b/unit_tests/test_neutron_contexts.py index d2f73125..5f3e25b3 100644 --- a/unit_tests/test_neutron_contexts.py +++ b/unit_tests/test_neutron_contexts.py @@ -58,12 +58,17 @@ class TestL3AgentContext(CharmTestCase): @patch('neutron_contexts.NeutronAPIContext') def test_new_ext_network(self, _NeutronAPIContext): _NeutronAPIContext.return_value = \ - DummyNeutronAPIContext(return_value={'enable_dvr': False}) + DummyNeutronAPIContext(return_value={'enable_dvr': False, + 'report_interval': 30, + 'rpc_response_timeout': 60, + }) self.test_config.set('run-internal-router', 'none') self.test_config.set('external-network-id', '') self.eligible_leader.return_value = False self.assertEquals(neutron_contexts.L3AgentContext()(), {'agent_mode': 'legacy', + 'report_interval': 30, + 'rpc_response_timeout': 60, 'external_configuration_new': True, 'handle_internal_only_router': False, 'plugin': 'ovs'}) @@ -71,24 +76,34 @@ class TestL3AgentContext(CharmTestCase): @patch('neutron_contexts.NeutronAPIContext') def test_old_ext_network(self, _NeutronAPIContext): _NeutronAPIContext.return_value = \ - DummyNeutronAPIContext(return_value={'enable_dvr': False}) + DummyNeutronAPIContext(return_value={'enable_dvr': False, + 'report_interval': 30, + 'rpc_response_timeout': 60, + }) self.test_config.set('run-internal-router', 'none') self.test_config.set('ext-port', 'eth1') self.eligible_leader.return_value = False self.assertEquals(neutron_contexts.L3AgentContext()(), {'agent_mode': 'legacy', + 'report_interval': 30, + 'rpc_response_timeout': 60, 'handle_internal_only_router': False, 'plugin': 'ovs'}) @patch('neutron_contexts.NeutronAPIContext') def test_hior_leader(self, _NeutronAPIContext): _NeutronAPIContext.return_value = \ - DummyNeutronAPIContext(return_value={'enable_dvr': False}) + DummyNeutronAPIContext(return_value={'enable_dvr': False, + 'report_interval': 30, + 'rpc_response_timeout': 60, + }) self.test_config.set('run-internal-router', 'leader') self.test_config.set('external-network-id', 'netid') self.eligible_leader.return_value = True self.assertEquals(neutron_contexts.L3AgentContext()(), {'agent_mode': 'legacy', + 'report_interval': 30, + 'rpc_response_timeout': 60, 'handle_internal_only_router': True, 'ext_net_id': 'netid', 'plugin': 'ovs'}) @@ -96,12 +111,17 @@ class TestL3AgentContext(CharmTestCase): @patch('neutron_contexts.NeutronAPIContext') def test_hior_all(self, _NeutronAPIContext): _NeutronAPIContext.return_value = \ - DummyNeutronAPIContext(return_value={'enable_dvr': False}) + DummyNeutronAPIContext(return_value={'enable_dvr': False, + 'report_interval': 30, + 'rpc_response_timeout': 60, + }) self.test_config.set('run-internal-router', 'all') self.test_config.set('external-network-id', 'netid') self.eligible_leader.return_value = True self.assertEquals(neutron_contexts.L3AgentContext()(), {'agent_mode': 'legacy', + 'report_interval': 30, + 'rpc_response_timeout': 60, 'handle_internal_only_router': True, 'ext_net_id': 'netid', 'plugin': 'ovs'}) @@ -109,7 +129,10 @@ class TestL3AgentContext(CharmTestCase): @patch('neutron_contexts.NeutronAPIContext') def test_dvr(self, _NeutronAPIContext): _NeutronAPIContext.return_value = \ - DummyNeutronAPIContext(return_value={'enable_dvr': True}) + DummyNeutronAPIContext(return_value={'enable_dvr': True, + 'report_interval': 30, + 'rpc_response_timeout': 60, + }) self.assertEquals(neutron_contexts.L3AgentContext()()['agent_mode'], 'dvr_snat') @@ -163,6 +186,8 @@ class TestNeutronGatewayContext(CharmTestCase): 'verbose': True, 'l2_population': True, 'overlay_network_type': 'gre', + 'report_interval': 30, + 'rpc_response_timeout': 60, 'bridge_mappings': 'physnet1:br-data', 'network_providers': 'physnet3,physnet4', 'vlan_ranges': 'physnet1:1000:2000,physnet2:2001:3000', @@ -217,6 +242,8 @@ class TestNeutronGatewayContext(CharmTestCase): 'verbose': True, 'l2_population': True, 'overlay_network_type': 'gre', + 'report_interval': 30, + 'rpc_response_timeout': 60, 'bridge_mappings': 'physnet1:br-data', 'network_providers': 'physnet3,physnet4', 'vlan_ranges': 'physnet1:1000:2000,physnet2:2001:3000',