|
|
15f218 |
From 66b5e393aebd84b08047f33d09bc4cbce730e205 Mon Sep 17 00:00:00 2001
|
|
|
15f218 |
From: Ondrej Mular <omular@redhat.com>
|
|
|
15f218 |
Date: Tue, 23 Aug 2016 11:19:20 +0200
|
|
|
15f218 |
Subject: [PATCH] sbd: fix check if ATB is required when enabling sbd
|
|
|
15f218 |
|
|
|
15f218 |
---
|
|
|
15f218 |
pcs/common/report_codes.py | 1 +
|
|
|
15f218 |
pcs/lib/commands/sbd.py | 3 +-
|
|
|
15f218 |
pcs/lib/reports.py | 12 +++
|
|
|
15f218 |
pcs/lib/sbd.py | 39 ++++++++-
|
|
|
15f218 |
pcs/test/test_lib_sbd.py | 193 +++++++--------------------------------------
|
|
|
15f218 |
5 files changed, 80 insertions(+), 168 deletions(-)
|
|
|
15f218 |
|
|
|
15f218 |
diff --git a/pcs/common/report_codes.py b/pcs/common/report_codes.py
|
|
|
15f218 |
index 5e46a1f..e6a86ec 100644
|
|
|
15f218 |
--- a/pcs/common/report_codes.py
|
|
|
15f218 |
+++ b/pcs/common/report_codes.py
|
|
|
15f218 |
@@ -155,6 +155,7 @@ SBD_DISABLING_STARTED = "SBD_DISABLING_STARTED"
|
|
|
15f218 |
SBD_ENABLING_STARTED = "SBD_ENABLING_STARTED"
|
|
|
15f218 |
SBD_NOT_INSTALLED = "SBD_NOT_INSTALLED"
|
|
|
15f218 |
SBD_NOT_ENABLED = "SBD_NOT_ENABLED"
|
|
|
15f218 |
+SBD_REQUIRES_ATB = "SBD_REQUIRES_ATB"
|
|
|
15f218 |
SERVICE_DISABLE_ERROR = "SERVICE_DISABLE_ERROR"
|
|
|
15f218 |
SERVICE_DISABLE_STARTED = "SERVICE_DISABLE_STARTED"
|
|
|
15f218 |
SERVICE_DISABLE_SUCCESS = "SERVICE_DISABLE_SUCCESS"
|
|
|
15f218 |
diff --git a/pcs/lib/commands/sbd.py b/pcs/lib/commands/sbd.py
|
|
|
15f218 |
index 265ebb5..2acb104 100644
|
|
|
15f218 |
--- a/pcs/lib/commands/sbd.py
|
|
|
15f218 |
+++ b/pcs/lib/commands/sbd.py
|
|
|
15f218 |
@@ -159,7 +159,8 @@ def enable_sbd(
|
|
|
15f218 |
|
|
|
15f218 |
# enable ATB if needed
|
|
|
15f218 |
corosync_conf = lib_env.get_corosync_conf()
|
|
|
15f218 |
- if sbd.atb_has_to_be_enabled(lib_env.cmd_runner(), corosync_conf):
|
|
|
15f218 |
+ if sbd.atb_has_to_be_enabled_pre_enable_check(corosync_conf):
|
|
|
15f218 |
+ lib_env.report_processor.process(reports.sbd_requires_atb())
|
|
|
15f218 |
corosync_conf.set_quorum_options(
|
|
|
15f218 |
lib_env.report_processor, {"auto_tie_breaker": "1"}
|
|
|
15f218 |
)
|
|
|
15f218 |
diff --git a/pcs/lib/reports.py b/pcs/lib/reports.py
|
|
|
15f218 |
index 568bb7e..a701679 100644
|
|
|
15f218 |
--- a/pcs/lib/reports.py
|
|
|
15f218 |
+++ b/pcs/lib/reports.py
|
|
|
15f218 |
@@ -1928,3 +1928,15 @@ def quorum_cannot_disable_atb_due_to_sbd(
|
|
|
15f218 |
"unable to disable auto_tie_breaker: SBD fencing will have no effect",
|
|
|
15f218 |
forceable=forceable
|
|
|
15f218 |
)
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
+def sbd_requires_atb():
|
|
|
15f218 |
+ """
|
|
|
15f218 |
+ Warning that ATB will be enabled in order to make SBD fencing effective.
|
|
|
15f218 |
+ """
|
|
|
15f218 |
+ return ReportItem.warning(
|
|
|
15f218 |
+ report_codes.SBD_REQUIRES_ATB,
|
|
|
15f218 |
+ "auto_tie_breaker quorum option will be enabled to make SBD fencing "
|
|
|
15f218 |
+ "effective. Cluster has to be offline to be able to make this change."
|
|
|
15f218 |
+ )
|
|
|
15f218 |
+
|
|
|
15f218 |
diff --git a/pcs/lib/sbd.py b/pcs/lib/sbd.py
|
|
|
15f218 |
index c9f013b..39de740 100644
|
|
|
15f218 |
--- a/pcs/lib/sbd.py
|
|
|
15f218 |
+++ b/pcs/lib/sbd.py
|
|
|
15f218 |
@@ -46,6 +46,25 @@ def _run_parallel_and_raise_lib_error_on_failure(func, param_list):
|
|
|
15f218 |
raise LibraryError(*report_list)
|
|
|
15f218 |
|
|
|
15f218 |
|
|
|
15f218 |
+def _even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ corosync_conf_facade, node_number_modifier=0
|
|
|
15f218 |
+):
|
|
|
15f218 |
+ """
|
|
|
15f218 |
+ Returns True whenever cluster has no quorum device configured and number of
|
|
|
15f218 |
+ nodes + node_number_modifier is even number, False otherwise.
|
|
|
15f218 |
+
|
|
|
15f218 |
+ corosync_conf_facade --
|
|
|
15f218 |
+ node_number_modifier -- this value will be added to current number of nodes.
|
|
|
15f218 |
+ This can be useful to test whenever is ATB needed when adding/removing
|
|
|
15f218 |
+ node.
|
|
|
15f218 |
+ """
|
|
|
15f218 |
+ return (
|
|
|
15f218 |
+ not corosync_conf_facade.has_quorum_device()
|
|
|
15f218 |
+ and
|
|
|
15f218 |
+ (len(corosync_conf_facade.get_nodes()) + node_number_modifier) % 2 == 0
|
|
|
15f218 |
+ )
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
def is_auto_tie_breaker_needed(
|
|
|
15f218 |
runner, corosync_conf_facade, node_number_modifier=0
|
|
|
15f218 |
):
|
|
|
15f218 |
@@ -60,15 +79,29 @@ def is_auto_tie_breaker_needed(
|
|
|
15f218 |
node.
|
|
|
15f218 |
"""
|
|
|
15f218 |
return (
|
|
|
15f218 |
- not corosync_conf_facade.has_quorum_device()
|
|
|
15f218 |
- and
|
|
|
15f218 |
- (len(corosync_conf_facade.get_nodes()) + node_number_modifier) % 2 == 0
|
|
|
15f218 |
+ _even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ corosync_conf_facade, node_number_modifier
|
|
|
15f218 |
+ )
|
|
|
15f218 |
and
|
|
|
15f218 |
is_sbd_installed(runner)
|
|
|
15f218 |
and
|
|
|
15f218 |
is_sbd_enabled(runner)
|
|
|
15f218 |
)
|
|
|
15f218 |
|
|
|
15f218 |
+
|
|
|
15f218 |
+def atb_has_to_be_enabled_pre_enable_check(corosync_conf_facade):
|
|
|
15f218 |
+ """
|
|
|
15f218 |
+ Returns True whenever quorum option auto_tie_breaker is needed to be enabled
|
|
|
15f218 |
+ for proper working of SBD fencing. False if it is not needed. This function
|
|
|
15f218 |
+ doesn't check if sbd is installed nor enabled.
|
|
|
15f218 |
+ """
|
|
|
15f218 |
+ return (
|
|
|
15f218 |
+ not corosync_conf_facade.is_enabled_auto_tie_breaker()
|
|
|
15f218 |
+ and
|
|
|
15f218 |
+ _even_number_of_nodes_and_no_qdevice(corosync_conf_facade)
|
|
|
15f218 |
+ )
|
|
|
15f218 |
+
|
|
|
15f218 |
+
|
|
|
15f218 |
def atb_has_to_be_enabled(runner, corosync_conf_facade, node_number_modifier=0):
|
|
|
15f218 |
"""
|
|
|
15f218 |
Return True whenever quorum option auto tie breaker has to be enabled for
|
|
|
15f218 |
diff --git a/pcs/test/test_lib_sbd.py b/pcs/test/test_lib_sbd.py
|
|
|
15f218 |
index fd29484..516e0bd 100644
|
|
|
15f218 |
--- a/pcs/test/test_lib_sbd.py
|
|
|
15f218 |
+++ b/pcs/test/test_lib_sbd.py
|
|
|
15f218 |
@@ -86,195 +86,60 @@ class RunParallelAndRaiseLibErrorOnFailureTest(TestCase):
|
|
|
15f218 |
)
|
|
|
15f218 |
|
|
|
15f218 |
|
|
|
15f218 |
-@mock.patch("pcs.lib.sbd.is_sbd_installed")
|
|
|
15f218 |
-@mock.patch("pcs.lib.sbd.is_sbd_enabled")
|
|
|
15f218 |
-class IsAutoTieBreakerNeededTest(TestCase):
|
|
|
15f218 |
+class EvenNumberOfNodesAndNoQdevice(TestCase):
|
|
|
15f218 |
def setUp(self):
|
|
|
15f218 |
- self.runner = "runner"
|
|
|
15f218 |
self.mock_corosync_conf = mock.MagicMock(spec_set=CorosyncConfigFacade)
|
|
|
15f218 |
|
|
|
15f218 |
def _set_ret_vals(self, nodes, qdevice):
|
|
|
15f218 |
self.mock_corosync_conf.get_nodes.return_value = nodes
|
|
|
15f218 |
self.mock_corosync_conf.has_quorum_device.return_value = qdevice
|
|
|
15f218 |
|
|
|
15f218 |
- def test_sbd_enabled_even_nodes_has_qdevice(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2], True)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_enabled_even_nodes_no_qdevice(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2], False)
|
|
|
15f218 |
- self.assertTrue(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_not_installed_even_nodes_no_qdevice(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = False
|
|
|
15f218 |
- mock_installed.return_value = False
|
|
|
15f218 |
+ def test_even_num_no_qdevice(self):
|
|
|
15f218 |
self._set_ret_vals([1, 2], False)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_enabled_odd_nodes_has_qdevice(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2, 3], True)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_enabled_odd_nodes_no_qdevice(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2, 3], False)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf
|
|
|
15f218 |
+ self.assertTrue(lib_sbd._even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ self.mock_corosync_conf
|
|
|
15f218 |
))
|
|
|
15f218 |
|
|
|
15f218 |
- def test_sbd_disabled_even_nodes_has_qdevice(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = False
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
+ def test_even_num_qdevice(self):
|
|
|
15f218 |
self._set_ret_vals([1, 2], True)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_disabled_even_nodes_no_qdevice(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = False
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2], False)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf
|
|
|
15f218 |
+ self.assertFalse(lib_sbd._even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ self.mock_corosync_conf
|
|
|
15f218 |
))
|
|
|
15f218 |
|
|
|
15f218 |
- def test_sbd_disabled_odd_nodes_has_qdevice(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = False
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2, 3], True)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_disabled_odd_nodes_no_qdevice(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = False
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
+ def test_odd_num_no_qdevice(self):
|
|
|
15f218 |
self._set_ret_vals([1, 2, 3], False)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf
|
|
|
15f218 |
+ self.assertFalse(lib_sbd._even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ self.mock_corosync_conf
|
|
|
15f218 |
))
|
|
|
15f218 |
|
|
|
15f218 |
- def test_sbd_enabled_odd_nodes_no_qdevice_plus_node(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2, 3], False)
|
|
|
15f218 |
- self.assertTrue(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf, 1
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_not_installed_odd_nodes_no_qdevice_plus_node(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = False
|
|
|
15f218 |
- mock_installed.return_value = False
|
|
|
15f218 |
- self._set_ret_vals([1, 2, 3], False)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf, 1
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_enabled_odd_nodes_no_qdevice_minus_node(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2, 3], False)
|
|
|
15f218 |
- self.assertTrue(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf, -1
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_enabled_odd_nodes_no_qdevice_plus_2_nodes(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2, 3], False)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf, 2
|
|
|
15f218 |
- ))
|
|
|
15f218 |
-
|
|
|
15f218 |
- def test_sbd_enabled_odd_nodes_no_qdevice_minus_2_nodes(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2, 3], False)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf, -2
|
|
|
15f218 |
+ def test_odd_num_qdevice(self):
|
|
|
15f218 |
+ self._set_ret_vals([1, 2, 3], True)
|
|
|
15f218 |
+ self.assertFalse(lib_sbd._even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ self.mock_corosync_conf
|
|
|
15f218 |
))
|
|
|
15f218 |
|
|
|
15f218 |
- def test_sbd_enabled_even_nodes_no_qdevice_plus_node(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
+ def test_even_num_no_qdevice_plus_one(self):
|
|
|
15f218 |
self._set_ret_vals([1, 2], False)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf, 1
|
|
|
15f218 |
+ self.assertFalse(lib_sbd._even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ self.mock_corosync_conf, 1
|
|
|
15f218 |
))
|
|
|
15f218 |
|
|
|
15f218 |
- def test_sbd_enabled_even_nodes_no_qdevice_minus_node(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2], False)
|
|
|
15f218 |
- self.assertFalse(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf, -1
|
|
|
15f218 |
+ def test_even_num_qdevice_plus_one(self):
|
|
|
15f218 |
+ self._set_ret_vals([1, 2], True)
|
|
|
15f218 |
+ self.assertFalse(lib_sbd._even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ self.mock_corosync_conf, 1
|
|
|
15f218 |
))
|
|
|
15f218 |
|
|
|
15f218 |
- def test_sbd_enabled_even_nodes_no_qdevice_plus_2_nodes(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2], False)
|
|
|
15f218 |
- self.assertTrue(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf, 2
|
|
|
15f218 |
+ def test_odd_num_no_qdevice_plus_one(self):
|
|
|
15f218 |
+ self._set_ret_vals([1, 2, 3], False)
|
|
|
15f218 |
+ self.assertTrue(lib_sbd._even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ self.mock_corosync_conf, 1
|
|
|
15f218 |
))
|
|
|
15f218 |
|
|
|
15f218 |
- def test_sbd_enabled_even_nodes_no_qdevice_minus_2_nodes(
|
|
|
15f218 |
- self, mock_enabled, mock_installed
|
|
|
15f218 |
- ):
|
|
|
15f218 |
- mock_enabled.return_value = True
|
|
|
15f218 |
- mock_installed.return_value = True
|
|
|
15f218 |
- self._set_ret_vals([1, 2, 3, 4], False)
|
|
|
15f218 |
- self.assertTrue(lib_sbd.is_auto_tie_breaker_needed(
|
|
|
15f218 |
- self.runner, self.mock_corosync_conf, -2
|
|
|
15f218 |
+ def test_odd_num_qdevice_plus_one(self):
|
|
|
15f218 |
+ self._set_ret_vals([1, 2, 3], True)
|
|
|
15f218 |
+ self.assertFalse(lib_sbd._even_number_of_nodes_and_no_qdevice(
|
|
|
15f218 |
+ self.mock_corosync_conf, 1
|
|
|
15f218 |
))
|
|
|
15f218 |
|
|
|
15f218 |
|
|
|
15f218 |
--
|
|
|
15f218 |
1.8.3.1
|
|
|
15f218 |
|