From 925b2caca73500310df02ded25051570a0d2e42e Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Wed, 25 Sep 2019 17:12:26 +0200 Subject: [PATCH] Support plugin-subordinate request for db_migration Change-Id: Iaefcb81fff5ed8a9441c93ac4c8bac3fa12eef15 --- hooks/neutron_api_hooks.py | 39 +++++++++++++++++++++------- unit_tests/test_neutron_api_hooks.py | 34 +++++++++++++++++++++--- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/hooks/neutron_api_hooks.py b/hooks/neutron_api_hooks.py index ee54c7dd..0de4bc08 100755 --- a/hooks/neutron_api_hooks.py +++ b/hooks/neutron_api_hooks.py @@ -23,21 +23,24 @@ from subprocess import ( ) from charmhelpers.core.hookenv import ( + DEBUG, + ERROR, Hooks, UnregisteredHookError, config, + is_leader, + leader_get, + leader_set, local_unit, log, - DEBUG, - ERROR, + open_port, + related_units, relation_get, + relation_id, relation_ids, relation_set, status_set, - open_port, unit_get, - related_units, - is_leader, ) from charmhelpers.core.host import ( @@ -607,12 +610,28 @@ def ha_changed(): 'neutron-plugin-api-subordinate-relation-changed') @restart_on_change(restart_map(), stopstart=True) def neutron_plugin_api_subordinate_relation_joined(relid=None): - ''' - -changed handles relation data set by a subordinate. - ''' - relation_data = {'neutron-api-ready': 'no'} + relation_data = {} + if is_db_initialised(): + db_migration_key = 'migrate-database-nonce' + if not relid: + relid = relation_id() + leader_key = '{}-{}'.format(db_migration_key, relid) + for unit in related_units(relid): + nonce = relation_get(db_migration_key, rid=relid, unit=unit) + if nonce: + if is_leader() and leader_get(leader_key) != nonce: + migrate_neutron_database(upgrade=True) + # track nonce in leader storage to avoid superfluous + # migrations + leader_set({leader_key: nonce}) + # set nonce back on relation to signal completion to other end + # we do this regardless of leadership status so that + # subordinates connected to non-leader units can proceed. + relation_data[db_migration_key] = nonce + + relation_data['neutron-api-ready'] = 'no' if is_api_ready(CONFIGS): - relation_data['neutron-api-ready'] = "yes" + relation_data['neutron-api-ready'] = 'yes' if not manage_plugin(): neutron_cc_ctxt = NeutronCCContext()() plugin_instance = NeutronApiSDNContext() diff --git a/unit_tests/test_neutron_api_hooks.py b/unit_tests/test_neutron_api_hooks.py index f1edca58..d941dacb 100644 --- a/unit_tests/test_neutron_api_hooks.py +++ b/unit_tests/test_neutron_api_hooks.py @@ -950,15 +950,43 @@ class NeutronAPIHooksTests(CharmTestCase): **{'neutron-api-ready': 'no'}, relation_id=None) self.CONFIGS.write_all.assert_called_once_with() self.relation_set.reset_mock() + self.CONFIGS.reset_mock() _manage_plugin.return_value = False ncc_instance = _NeutronCCContext.return_value ncc_instance.return_value = {'core_plugin': 'aPlugin'} napisdn_instance = _NeutronApiSDNContext.return_value napisdn_instance.is_allowed.return_value = True self._call_hook('neutron-plugin-api-subordinate-relation-changed') - hooks.neutron_plugin_api_subordinate_relation_joined() - self.relation_set.assert_called_with( + self.relation_set.assert_called_once_with( **{'neutron-api-ready': 'no', 'neutron_config_data': json.dumps({'core_plugin': 'aPlugin'})}, relation_id=None) - self.CONFIGS.write_all.assert_called_with() + self.CONFIGS.write_all.assert_called_once_with() + + @patch.object(hooks, 'manage_plugin') + @patch.object(hooks, 'is_api_ready') + @patch.object(hooks, 'leader_set') + @patch.object(hooks, 'migrate_neutron_database') + @patch.object(hooks, 'leader_get') + @patch.object(hooks, 'relation_id') + @patch.object(hooks, 'is_db_initialised') + def test_neutron_plugin_api_subordinate_relation_db_migration( + self, _is_db_initialised, _relation_id, _leader_get, + _migrate_neutron_database, _leader_set, _is_api_ready, + _manage_plugin): + _is_db_initialised.return_value = True + _relation_id.return_value = 'neutron-plugin-api-subordinate:42' + self.related_units.return_value = ['aUnit'] + self.is_leader.return_value = True + self.relation_get.side_effect = None + self.relation_get.return_value = 'fake-uuid' + _leader_get.return_value = ( + 'migrate-database-nonce-neutron-plugin-api-subordinate:42') + _is_api_ready.return_value = True + _manage_plugin.return_value = True + self._call_hook('neutron-plugin-api-subordinate-relation-changed') + _migrate_neutron_database.assert_called_once_with(upgrade=True) + self.relation_set.assert_called_once_with( + relation_id='neutron-plugin-api-subordinate:42', + **{'migrate-database-nonce': 'fake-uuid', + 'neutron-api-ready': 'yes'})