diff --git a/.gitignore b/.gitignore index 25d8aecb..58a20d7c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ bin tags *.sw[nop] *.pyc +.unit-state.db diff --git a/hooks/neutron-control-relation-broken b/hooks/neutron-control-relation-broken new file mode 120000 index 00000000..55aa8e52 --- /dev/null +++ b/hooks/neutron-control-relation-broken @@ -0,0 +1 @@ +neutron_ovs_hooks.py \ No newline at end of file diff --git a/hooks/neutron-control-relation-changed b/hooks/neutron-control-relation-changed new file mode 120000 index 00000000..55aa8e52 --- /dev/null +++ b/hooks/neutron-control-relation-changed @@ -0,0 +1 @@ +neutron_ovs_hooks.py \ No newline at end of file diff --git a/hooks/neutron-control-relation-departed b/hooks/neutron-control-relation-departed new file mode 120000 index 00000000..55aa8e52 --- /dev/null +++ b/hooks/neutron-control-relation-departed @@ -0,0 +1 @@ +neutron_ovs_hooks.py \ No newline at end of file diff --git a/hooks/neutron-control-relation-joined b/hooks/neutron-control-relation-joined new file mode 120000 index 00000000..55aa8e52 --- /dev/null +++ b/hooks/neutron-control-relation-joined @@ -0,0 +1 @@ +neutron_ovs_hooks.py \ No newline at end of file diff --git a/hooks/neutron_ovs_context.py b/hooks/neutron_ovs_context.py index b07c0180..f8948a39 100644 --- a/hooks/neutron_ovs_context.py +++ b/hooks/neutron_ovs_context.py @@ -268,16 +268,29 @@ class SharedSecretContext(OSContextGenerator): class RemoteRestartContext(OSContextGenerator): + def __init__(self, interfaces=None): + self.interfaces = interfaces or ['neutron-plugin'] + def __call__(self): - for rid in relation_ids('neutron-plugin'): + rids = [] + for interface in self.interfaces: + rids.extend(relation_ids(interface)) + ctxt = {} + for rid in rids: for unit in related_units(rid): - restart_uuid = relation_get( - attribute='restart-trigger', + remote_data = relation_get( rid=rid, unit=unit) - if restart_uuid: - return {'restart_trigger': restart_uuid} - return {} + for k, v in remote_data.items(): + if k.startswith('restart-trigger'): + restart_key = k.replace('-', '_') + try: + ctxt[restart_key].append(v) + except KeyError: + ctxt[restart_key] = [v] + for restart_key in ctxt.keys(): + ctxt[restart_key] = '-'.join(sorted(ctxt[restart_key])) + return ctxt class APIIdentityServiceContext(context.IdentityServiceContext): diff --git a/hooks/neutron_ovs_hooks.py b/hooks/neutron_ovs_hooks.py index dd407157..d897ff72 100755 --- a/hooks/neutron_ovs_hooks.py +++ b/hooks/neutron_ovs_hooks.py @@ -143,6 +143,12 @@ def zeromq_configuration_relation_changed(): CONFIGS.write_all() +@hooks.hook('neutron-control-relation-changed') +@restart_on_change(restart_map(), stopstart=True) +def restart_check(): + CONFIGS.write_all() + + def main(): try: hooks.execute(sys.argv) diff --git a/hooks/neutron_ovs_utils.py b/hooks/neutron_ovs_utils.py index a631a326..25b0e376 100644 --- a/hooks/neutron_ovs_utils.py +++ b/hooks/neutron_ovs_utils.py @@ -136,7 +136,8 @@ BASE_RESOURCE_MAP = OrderedDict([ (NEUTRON_CONF, { 'services': ['neutron-plugin-openvswitch-agent'], 'contexts': [neutron_ovs_context.OVSPluginContext(), - neutron_ovs_context.RemoteRestartContext(), + neutron_ovs_context.RemoteRestartContext( + ['neutron-plugin', 'neutron-control']), context.AMQPContext(ssl_dir=NEUTRON_CONF_DIR), context.ZeroMQContext(), context.NotificationDriverContext()], diff --git a/metadata.yaml b/metadata.yaml index ded127ca..22875afd 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -22,6 +22,8 @@ provides: neutron-plugin: interface: neutron-plugin scope: container + neutron-control: + interface: service-control requires: amqp: interface: rabbitmq @@ -30,4 +32,3 @@ requires: zeromq-configuration: interface: zeromq-configuration scope: container - diff --git a/templates/icehouse/dhcp_agent.ini b/templates/icehouse/dhcp_agent.ini index 9fe627a5..fe6c7b41 100644 --- a/templates/icehouse/dhcp_agent.ini +++ b/templates/icehouse/dhcp_agent.ini @@ -1,7 +1,9 @@ ############################################################################### # [ WARNING ] # Configuration file maintained by Juju. Local changes may be overwritten. +# {{ restart_trigger_dhcp }} ############################################################################### + [DEFAULT] state_path = /var/lib/neutron interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver diff --git a/templates/icehouse/metadata_agent.ini b/templates/icehouse/metadata_agent.ini index aeee80cc..bddc97f4 100644 --- a/templates/icehouse/metadata_agent.ini +++ b/templates/icehouse/metadata_agent.ini @@ -4,6 +4,7 @@ ############################################################################### # Metadata service seems to cache neutron api url from keystone so trigger # restart if it changes: {{ quantum_url }} +# {{ restart_trigger_metadata }} [DEFAULT] auth_url = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/v2.0 diff --git a/templates/juno/l3_agent.ini b/templates/juno/l3_agent.ini index 9dac0696..a71687c0 100644 --- a/templates/juno/l3_agent.ini +++ b/templates/juno/l3_agent.ini @@ -1,7 +1,9 @@ ############################################################################### # [ WARNING ] # Configuration file maintained by Juju. Local changes may be overwritten. +# {{ restart_trigger_l3agent }} ############################################################################### + [DEFAULT] interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver agent_mode = {{ agent_mode }} diff --git a/templates/juno/metadata_agent.ini b/templates/juno/metadata_agent.ini index aeee80cc..bddc97f4 100644 --- a/templates/juno/metadata_agent.ini +++ b/templates/juno/metadata_agent.ini @@ -4,6 +4,7 @@ ############################################################################### # Metadata service seems to cache neutron api url from keystone so trigger # restart if it changes: {{ quantum_url }} +# {{ restart_trigger_metadata }} [DEFAULT] auth_url = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/v2.0 diff --git a/templates/kilo/neutron.conf b/templates/kilo/neutron.conf index 0f2b398c..19e3af9d 100644 --- a/templates/kilo/neutron.conf +++ b/templates/kilo/neutron.conf @@ -1,9 +1,10 @@ -# icehouse +# kilo ############################################################################### # [ WARNING ] # Configuration file maintained by Juju. Local changes may be overwritten. # Config managed by neutron-openvswitch charm -# Service restart triggered by principle using key: {{ restart_trigger }} +# Service restart triggered by remote application: {{ restart_trigger }} +# {{ restart_trigger_neutron }} ############################################################################### [DEFAULT] verbose = {{ verbose }} diff --git a/unit_tests/test_neutron_ovs_context.py b/unit_tests/test_neutron_ovs_context.py index 7fae9ad6..cfce9c62 100644 --- a/unit_tests/test_neutron_ovs_context.py +++ b/unit_tests/test_neutron_ovs_context.py @@ -491,14 +491,54 @@ class TestRemoteRestartContext(CharmTestCase): def test_restart_trigger_present(self): self.relation_ids.return_value = ['rid1'] self.related_units.return_value = ['nova-compute/0'] - self.relation_get.return_value = '8f73-f3adb96a90d8' + self.relation_get.return_value = { + 'restart-trigger': '8f73-f3adb96a90d8', + } self.assertEquals( context.RemoteRestartContext()(), {'restart_trigger': '8f73-f3adb96a90d8'} ) + self.relation_ids.assert_called_with('neutron-plugin') + + def test_restart_trigger_present_alt_relation(self): + self.relation_ids.return_value = ['rid1'] + self.related_units.return_value = ['nova-compute/0'] + self.relation_get.return_value = { + 'restart-trigger': '8f73-f3adb96a90d8', + } + self.assertEquals( + context.RemoteRestartContext(['neutron-control'])(), + {'restart_trigger': '8f73-f3adb96a90d8'} + ) + self.relation_ids.assert_called_with('neutron-control') + + def test_restart_trigger_present_multi_relation(self): + self.relation_ids.return_value = ['rid1'] + self.related_units.return_value = ['nova-compute/0'] + ids = [ + {'restart-trigger': '8f73'}, + {'restart-trigger': '2ac3'}] + self.relation_get.side_effect = lambda rid, unit: ids.pop() + self.assertEquals( + context.RemoteRestartContext( + ['neutron-plugin', 'neutron-control'])(), + {'restart_trigger': '2ac3-8f73'} + ) + self.relation_ids.assert_called_with('neutron-control') def test_restart_trigger_absent(self): self.relation_ids.return_value = ['rid1'] self.related_units.return_value = ['nova-compute/0'] - self.relation_get.return_value = None + self.relation_get.return_value = {} self.assertEquals(context.RemoteRestartContext()(), {}) + + def test_restart_trigger_service(self): + self.relation_ids.return_value = ['rid1'] + self.related_units.return_value = ['nova-compute/0'] + self.relation_get.return_value = { + 'restart-trigger-neutron': 'neutron-uuid', + } + self.assertEquals( + context.RemoteRestartContext()(), + {'restart_trigger_neutron': 'neutron-uuid'} + )