From 341eb0fcc4afc7b09fa177c18fee356f8752a4f6 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Tue, 11 Feb 2020 13:55:17 +0000 Subject: [PATCH] Notify clients of series upgrade When the percona cluster is undergoing a series upgrade, clients should suspend db activity in their hooks (like db migrations). This change sents a notification of upgrade Change-Id: I9d02180fcb0fec6bd017c6150bfca5963896fd2f --- actions/actions.py | 10 ++++++ charmhelpers/contrib/openstack/utils.py | 4 +++ hooks/percona_hooks.py | 10 ++++++ test-requirements.txt | 20 ++++++++++++ unit_tests/test_actions.py | 12 ++++++- unit_tests/test_percona_hooks.py | 42 +++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 1 deletion(-) diff --git a/actions/actions.py b/actions/actions.py index cd65c3f..32ab4e6 100755 --- a/actions/actions.py +++ b/actions/actions.py @@ -12,6 +12,8 @@ from charmhelpers.core.hookenv import ( action_get, action_set, action_fail, + relation_ids, + relation_set, leader_set, is_leader, ) @@ -21,6 +23,10 @@ from charmhelpers.core.host import ( lsb_release, ) +from charmhelpers.contrib.openstack.utils import ( + DB_SERIES_UPGRADING_KEY, +) + from percona_utils import ( pause_unit_helper, resume_unit_helper, @@ -60,6 +66,10 @@ def complete_cluster_series_upgrade(args): # Unset cluster_series_upgrading leader_set(cluster_series_upgrading="") leader_set(cluster_series_upgrade_leader="") + for r_id in relation_ids('shared-db'): + relation_set( + relation_id=r_id, + relation_settings={DB_SERIES_UPGRADING_KEY: None}) config_changed() diff --git a/charmhelpers/contrib/openstack/utils.py b/charmhelpers/contrib/openstack/utils.py index e5e2536..f7a9b30 100644 --- a/charmhelpers/contrib/openstack/utils.py +++ b/charmhelpers/contrib/openstack/utils.py @@ -293,6 +293,10 @@ PACKAGE_CODENAMES = { DEFAULT_LOOPBACK_SIZE = '5G' +DB_SERIES_UPGRADING_KEY = 'cluster-series-upgrading' + +DB_MAINTENANCE_KEYS = [DB_SERIES_UPGRADING_KEY] + class CompareOpenStackReleases(BasicStringComparator): """Provide comparisons of OpenStack releases. diff --git a/hooks/percona_hooks.py b/hooks/percona_hooks.py index cbca469..23f4314 100755 --- a/hooks/percona_hooks.py +++ b/hooks/percona_hooks.py @@ -67,6 +67,7 @@ from charmhelpers.contrib.charmsupport import nrpe from charmhelpers.contrib.hardening.harden import harden from charmhelpers.contrib.hardening.mysql.checks import run_mysql_checks from charmhelpers.contrib.openstack.utils import ( + DB_SERIES_UPGRADING_KEY, is_unit_paused_set, is_unit_upgrading_set, set_unit_upgrading, @@ -356,6 +357,10 @@ def prepare(): leader_set(cluster_series_upgrading=True) leader_set( cluster_series_upgrade_leader=get_relation_ip('cluster')) + for r_id in relation_ids('shared-db'): + relation_set( + relation_id=r_id, + relation_settings={DB_SERIES_UPGRADING_KEY: True}) else: hosts = [leader_get('cluster_series_upgrade_leader')] @@ -945,6 +950,11 @@ def leader_settings_changed(): # NOTE(tkurek): deconfigure old leader if relation_ids('slave'): deconfigure_slave() + if not leader_get('cluster_series_upgrading'): + for r_id in relation_ids('shared-db'): + relation_set( + relation_id=r_id, + relation_settings={DB_SERIES_UPGRADING_KEY: None}) @hooks.hook('leader-elected') diff --git a/test-requirements.txt b/test-requirements.txt index 86d5e51..2f51746 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -15,3 +15,23 @@ stestr>=2.2.0 coverage>=4.5.2 keyring==18.0.1 setuptools<=40.0.0 +# BEGIN: Amulet OpenStack Charm Helper Requirements +# Liberty client lower constraints +amulet>=1.14.3,<2.0;python_version=='2.7' +bundletester>=0.6.1,<1.0;python_version=='2.7' +python-ceilometerclient>=1.5.0 +python-cinderclient>=1.4.0,<5.0.0 +python-glanceclient>=1.1.0 +python-heatclient>=0.8.0 +python-keystoneclient>=1.7.1 +python-neutronclient>=3.1.0 +python-novaclient>=2.30.1 +python-openstackclient>=1.7.0 +python-swiftclient>=2.6.0 +pika>=0.10.0,<1.0 +distro-info +git+https://github.com/juju/charm-helpers.git#egg=charmhelpers +# END: Amulet OpenStack Charm Helper Requirements +# NOTE: workaround for 14.04 pip/tox +pytz +pyudev # for ceph-* charm unit tests (not mocked?) diff --git a/unit_tests/test_actions.py b/unit_tests/test_actions.py index d3aacb8..823e433 100644 --- a/unit_tests/test_actions.py +++ b/unit_tests/test_actions.py @@ -48,17 +48,27 @@ class ResumeTestCase(CharmTestCase): class CompleteClusterSeriesUpgrade(CharmTestCase): def setUp(self): + to_patch = [ + "is_leader", + "config_changed", + "leader_set", + "relation_ids", + "relation_set"] super(CompleteClusterSeriesUpgrade, self).setUp( - actions, ["config_changed", "is_leader", "leader_set"]) + actions, to_patch) def test_leader_complete_series_upgrade(self): self.is_leader.return_value = True + self.relation_ids.return_value = ['relid:1'] calls = [mock.call(cluster_series_upgrading=""), mock.call(cluster_series_upgrade_leader="")] actions.complete_cluster_series_upgrade([]) self.leader_set.assert_has_calls(calls) self.config_changed.assert_called_once_with() + self.relation_set.assert_called_once_with( + relation_id='relid:1', + relation_settings={'cluster-series-upgrading': None}) def test_non_leader_complete_series_upgrade(self): self.is_leader.return_value = False diff --git a/unit_tests/test_percona_hooks.py b/unit_tests/test_percona_hooks.py index 6fc93e7..176ab16 100644 --- a/unit_tests/test_percona_hooks.py +++ b/unit_tests/test_percona_hooks.py @@ -619,6 +619,48 @@ class TestInstallPerconaXtraDB(CharmTestCase): self.run_mysql_checks.assert_not_called() +class TestSeriesUpgrade(CharmTestCase): + TO_PATCH = [ + 'register_configs', + 'pause_unit_helper', + 'set_unit_upgrading', + 'leader_get', + 'leader_set', + 'relation_ids', + 'relation_set', + 'get_relation_ip', + 'render_config', + ] + + def setUp(self): + CharmTestCase.setUp(self, hooks, self.TO_PATCH) + + def test_prepare_leader(self): + self.register_configs.return_value = 'registered_configs' + self.leader_get.return_value = None + self.get_relation_ip.return_value = '10.0.0.10' + self.relation_ids.return_value = ['relid:1'] + hooks.prepare() + self.pause_unit_helper.assert_called_once_with('registered_configs') + self.set_unit_upgrading.assert_called_once_with() + leader_set_calls = [ + mock.call(cluster_series_upgrading=True), + mock.call(cluster_series_upgrade_leader='10.0.0.10')] + self.leader_set.assert_has_calls(leader_set_calls) + self.relation_set.assert_called_once_with( + relation_id='relid:1', + relation_settings={'cluster-series-upgrading': True}) + self.render_config.assert_called_once_with([]) + + def test_prepare_non_leader(self): + self.register_configs.return_value = 'registered_configs' + self.leader_get.return_value = '10.0.0.10' + hooks.prepare() + self.pause_unit_helper.assert_called_once_with('registered_configs') + self.set_unit_upgrading.assert_called_once_with() + self.render_config.assert_called_once_with(['10.0.0.10']) + + class TestUpgradeCharm(CharmTestCase): TO_PATCH = [ 'config',