Add option for no-quorum-policy

Adds a config item for what to do when the cluster does not have quorum.
This is useful with stateless services where, e.g., we only need a VIP
and that can be up on a single host with no problem.

Though this would be a good relation data setting, many sites would
prefer to stop the resources rather than have a VIP on multiple hosts,
causing arp issues with the switch.

Closes-bug: #1850829
Change-Id: I961b6b32e7ed23f967b047dd0ecb45b0c0dff49a
This commit is contained in:
Xav Paice 2021-03-10 16:15:58 +13:00
parent 0e84499960
commit d17fdd276e
4 changed files with 38 additions and 1 deletions

View File

@ -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 dont 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

View File

@ -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():
"""

View File

@ -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")

View File

@ -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,