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:
parent
0e84499960
commit
d17fdd276e
|
@ -218,3 +218,12 @@ options:
|
||||||
description: |
|
description: |
|
||||||
check_crm will generate a critical alert if the failcount of a resource
|
check_crm will generate a critical alert if the failcount of a resource
|
||||||
has crossed this threshold. Set to 0 or '' to disable.
|
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
|
||||||
|
|
|
@ -126,6 +126,7 @@ from utils import (
|
||||||
emit_systemd_overrides_file,
|
emit_systemd_overrides_file,
|
||||||
trigger_corosync_update_from_leader,
|
trigger_corosync_update_from_leader,
|
||||||
emit_corosync_conf,
|
emit_corosync_conf,
|
||||||
|
assess_status_helper,
|
||||||
)
|
)
|
||||||
|
|
||||||
from charmhelpers.contrib.charmsupport import nrpe
|
from charmhelpers.contrib.charmsupport import nrpe
|
||||||
|
@ -230,6 +231,15 @@ def config_changed():
|
||||||
cfg.previous('maintenance-mode') != cfg['maintenance-mode']):
|
cfg.previous('maintenance-mode') != cfg['maintenance-mode']):
|
||||||
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():
|
def migrate_maas_dns():
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1317,6 +1317,13 @@ def assess_status_helper():
|
||||||
'blocked',
|
'blocked',
|
||||||
'stonith_enabled config option is no longer supported')
|
'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():
|
if is_unit_upgrading_set():
|
||||||
return ("blocked",
|
return ("blocked",
|
||||||
"Ready for do-release-upgrade. Set complete when finished")
|
"Ready for do-release-upgrade. Set complete when finished")
|
||||||
|
|
|
@ -422,6 +422,7 @@ class TestHooks(test_utils.CharmTestCase):
|
||||||
apt_install.assert_called_once_with(expected_pkgs, fatal=True)
|
apt_install.assert_called_once_with(expected_pkgs, fatal=True)
|
||||||
setup_ocf_files.assert_called_once_with()
|
setup_ocf_files.assert_called_once_with()
|
||||||
|
|
||||||
|
@mock.patch('pcmk.set_property')
|
||||||
@mock.patch.object(hooks, 'is_stonith_configured')
|
@mock.patch.object(hooks, 'is_stonith_configured')
|
||||||
@mock.patch.object(hooks, 'configure_stonith')
|
@mock.patch.object(hooks, 'configure_stonith')
|
||||||
@mock.patch.object(hooks, 'relation_ids')
|
@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, 'maintenance_mode')
|
||||||
@mock.patch.object(hooks, 'is_leader')
|
@mock.patch.object(hooks, 'is_leader')
|
||||||
@mock.patch.object(hooks, 'update_nrpe_config')
|
@mock.patch.object(hooks, 'update_nrpe_config')
|
||||||
|
@mock.patch.object(hooks, 'assess_status_helper')
|
||||||
@mock.patch('pcmk.commit')
|
@mock.patch('pcmk.commit')
|
||||||
@mock.patch('pcmk.wait_for_pcmk')
|
@mock.patch('pcmk.wait_for_pcmk')
|
||||||
@mock.patch.object(hooks, 'configure_corosync')
|
@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,
|
def test_config_changed(self, mock_mkdir, mock_rsync, mock_config,
|
||||||
mock_os_mkdir, mock_configure_corosync,
|
mock_os_mkdir, mock_configure_corosync,
|
||||||
mock_wait_for_pcmk, mock_pcmk_commit,
|
mock_wait_for_pcmk, mock_pcmk_commit,
|
||||||
|
mock_assess_status_helper,
|
||||||
mock_update_nrpe_config, mock_is_leader,
|
mock_update_nrpe_config, mock_is_leader,
|
||||||
mock_maintenance_mode,
|
mock_maintenance_mode,
|
||||||
mock_hanode_relation_joined,
|
mock_hanode_relation_joined,
|
||||||
mock_relation_ids,
|
mock_relation_ids,
|
||||||
mock_configure_stonith,
|
mock_configure_stonith,
|
||||||
mock_is_stonith_configured):
|
mock_is_stonith_configured,
|
||||||
|
mock_set_property):
|
||||||
|
|
||||||
mock_is_stonith_configured.return_value = False
|
mock_is_stonith_configured.return_value = False
|
||||||
mock_config.side_effect = self.test_config.get
|
mock_config.side_effect = self.test_config.get
|
||||||
mock_relation_ids.return_value = ['hanode:1']
|
mock_relation_ids.return_value = ['hanode:1']
|
||||||
mock_is_leader.return_value = True
|
mock_is_leader.return_value = True
|
||||||
|
mock_assess_status_helper.return_value = ('active', 'mockmessage')
|
||||||
hooks.config_changed()
|
hooks.config_changed()
|
||||||
mock_maintenance_mode.assert_not_called()
|
mock_maintenance_mode.assert_not_called()
|
||||||
mock_relation_ids.assert_called_with('hanode')
|
mock_relation_ids.assert_called_with('hanode')
|
||||||
mock_hanode_relation_joined.assert_called_once_with('hanode:1')
|
mock_hanode_relation_joined.assert_called_once_with('hanode:1')
|
||||||
|
mock_set_property.assert_called_with('no-quorum-policy', 'stop')
|
||||||
|
|
||||||
# enable maintenance
|
# enable maintenance
|
||||||
self.test_config.set_previous('maintenance-mode', False)
|
self.test_config.set_previous('maintenance-mode', False)
|
||||||
|
@ -467,6 +473,11 @@ class TestHooks(test_utils.CharmTestCase):
|
||||||
hooks.config_changed()
|
hooks.config_changed()
|
||||||
mock_maintenance_mode.assert_called_with(False)
|
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, 'needs_maas_dns_migration')
|
||||||
@mock.patch.object(hooks, 'relation_ids')
|
@mock.patch.object(hooks, 'relation_ids')
|
||||||
def test_migrate_maas_dns_no_migration(self, relation_ids,
|
def test_migrate_maas_dns_no_migration(self, relation_ids,
|
||||||
|
|
Loading…
Reference in New Issue