diff --git a/config.yaml b/config.yaml index 14baeec..5c16702 100644 --- a/config.yaml +++ b/config.yaml @@ -218,3 +218,12 @@ options: description: | check_crm will generate a critical alert if the failcount of a resource has crossed this threshold. Set to 0 or '' to disable. + no_quorum_policy: + type: string + default: "stop" + description: | + What to do when the cluster does not have quorum. Allowed values: + ignore: continue all resource management, + freeze: continue resource management, but don’t recover resources from nodes not in the affected partition, + stop: stop all resources in the affected cluster partition, + suicide: fence all nodes in the affected cluster partition diff --git a/hooks/hooks.py b/hooks/hooks.py index 8af82b7..7cda3d9 100755 --- a/hooks/hooks.py +++ b/hooks/hooks.py @@ -126,6 +126,7 @@ from utils import ( emit_systemd_overrides_file, trigger_corosync_update_from_leader, emit_corosync_conf, + assess_status_helper, ) from charmhelpers.contrib.charmsupport import nrpe @@ -230,6 +231,15 @@ def config_changed(): cfg.previous('maintenance-mode') != cfg['maintenance-mode']): maintenance_mode(cfg['maintenance-mode']) + if config('no_quorum_policy').lower() in ['ignore', 'freeze', + 'stop', 'suicide']: + pcmk.set_property("no-quorum-policy", + config('no_quorum_policy').lower()) + else: + message = 'Invalid setting for no_quorum_policy' + status_set('blocked', message) + status_set(*assess_status_helper()) + def migrate_maas_dns(): """ diff --git a/hooks/utils.py b/hooks/utils.py index ab6c6bb..b0a7b49 100644 --- a/hooks/utils.py +++ b/hooks/utils.py @@ -1317,6 +1317,13 @@ def assess_status_helper(): 'blocked', 'stonith_enabled config option is no longer supported') + if config('no_quorum_policy'): + if config('no_quorum_policy').lower() not in ['ignore', 'freeze', + 'stop', 'suicide']: + return( + 'blocked', + 'Invalid no_quorum_policy specified') + if is_unit_upgrading_set(): return ("blocked", "Ready for do-release-upgrade. Set complete when finished") diff --git a/unit_tests/test_hacluster_hooks.py b/unit_tests/test_hacluster_hooks.py index 4b8dcbf..df7490f 100644 --- a/unit_tests/test_hacluster_hooks.py +++ b/unit_tests/test_hacluster_hooks.py @@ -422,6 +422,7 @@ class TestHooks(test_utils.CharmTestCase): apt_install.assert_called_once_with(expected_pkgs, fatal=True) setup_ocf_files.assert_called_once_with() + @mock.patch('pcmk.set_property') @mock.patch.object(hooks, 'is_stonith_configured') @mock.patch.object(hooks, 'configure_stonith') @mock.patch.object(hooks, 'relation_ids') @@ -429,6 +430,7 @@ class TestHooks(test_utils.CharmTestCase): @mock.patch.object(hooks, 'maintenance_mode') @mock.patch.object(hooks, 'is_leader') @mock.patch.object(hooks, 'update_nrpe_config') + @mock.patch.object(hooks, 'assess_status_helper') @mock.patch('pcmk.commit') @mock.patch('pcmk.wait_for_pcmk') @mock.patch.object(hooks, 'configure_corosync') @@ -439,21 +441,25 @@ class TestHooks(test_utils.CharmTestCase): def test_config_changed(self, mock_mkdir, mock_rsync, mock_config, mock_os_mkdir, mock_configure_corosync, mock_wait_for_pcmk, mock_pcmk_commit, + mock_assess_status_helper, mock_update_nrpe_config, mock_is_leader, mock_maintenance_mode, mock_hanode_relation_joined, mock_relation_ids, mock_configure_stonith, - mock_is_stonith_configured): + mock_is_stonith_configured, + mock_set_property): mock_is_stonith_configured.return_value = False mock_config.side_effect = self.test_config.get mock_relation_ids.return_value = ['hanode:1'] mock_is_leader.return_value = True + mock_assess_status_helper.return_value = ('active', 'mockmessage') hooks.config_changed() mock_maintenance_mode.assert_not_called() mock_relation_ids.assert_called_with('hanode') mock_hanode_relation_joined.assert_called_once_with('hanode:1') + mock_set_property.assert_called_with('no-quorum-policy', 'stop') # enable maintenance self.test_config.set_previous('maintenance-mode', False) @@ -467,6 +473,11 @@ class TestHooks(test_utils.CharmTestCase): hooks.config_changed() mock_maintenance_mode.assert_called_with(False) + # set no-quorum-policy to ignore + self.test_config.set('no_quorum_policy', 'ignore') + hooks.config_changed() + mock_set_property.assert_called_with('no-quorum-policy', 'ignore') + @mock.patch.object(hooks, 'needs_maas_dns_migration') @mock.patch.object(hooks, 'relation_ids') def test_migrate_maas_dns_no_migration(self, relation_ids,