Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2026-04-02 17:44:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new.21863 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh" Thu Apr 2 17:44:42 2026 rev:402 rq:1344335 version:5.0.0+20260402.90d08295 Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2026-04-01 19:53:34.484472853 +0200 +++ /work/SRC/openSUSE:Factory/.crmsh.new.21863/crmsh.changes 2026-04-02 17:46:10.447708173 +0200 @@ -1,0 +2,26 @@ +Thu Apr 02 09:48:36 UTC 2026 - [email protected] + +- Update to version 5.0.0+20260402.90d08295: + * Dev: behave: Add functional test case for previous commit + * Dev: unittests: Adjust unit test for previous commit + * Dev: sbd: And check and fix methods for fence_sbd pcmk_delay_max and crashdump parameter + +------------------------------------------------------------------- +Thu Apr 02 09:04:04 UTC 2026 - [email protected] + +- Update to version 5.0.0+20260402.f2dfba7d: + * Dev: unittests: Adjust unit test for previous commit + * Dev: bootstrap: Reject setup sbd stage if cluster is not quorate + * Dev: ui_sbd: Rename SBD.check_timeout_configurations to SBD.check_sbd_health + * Dev: sbd: Add diskless SBD warning while doing sbd health check + +------------------------------------------------------------------- +Thu Apr 02 06:45:43 UTC 2026 - [email protected] + +- Update to version 5.0.0+20260402.66548890: + * Dev: unittests: Adjust unit test for previous commit + * Dev: behave: Adjust functional test for previous commit + * Dev: doc: Update the formular to calculate the expected fencing-watchdog-timeout + * Fix: sbd: Update the formular to calculate the expected fencing-watchdog-timeout + +------------------------------------------------------------------- Old: ---- crmsh-5.0.0+20260401.827507a4.tar.bz2 New: ---- crmsh-5.0.0+20260402.90d08295.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.wQlYt6/_old 2026-04-02 17:46:11.515751950 +0200 +++ /var/tmp/diff_new_pack.wQlYt6/_new 2026-04-02 17:46:11.515751950 +0200 @@ -41,7 +41,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0-or-later Group: %{pkg_group} -Version: 5.0.0+20260401.827507a4 +Version: 5.0.0+20260402.90d08295 Release: 0 URL: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.wQlYt6/_old 2026-04-02 17:46:11.599755393 +0200 +++ /var/tmp/diff_new_pack.wQlYt6/_new 2026-04-02 17:46:11.635756868 +0200 @@ -9,7 +9,7 @@ </service> <service name="tar_scm"> <param name="url">https://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">e6dc4d82b19cba2e3d29ea342d57243cb08c82da</param> + <param name="changesrevision">0b408da8bf1caaf7e3471f62ff5f1a8f6aab41e3</param> </service> </servicedata> (No newline at EOF) ++++++ crmsh-5.0.0+20260401.827507a4.tar.bz2 -> crmsh-5.0.0+20260402.90d08295.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/crmsh/bootstrap.py new/crmsh-5.0.0+20260402.90d08295/crmsh/bootstrap.py --- old/crmsh-5.0.0+20260401.827507a4/crmsh/bootstrap.py 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/crmsh/bootstrap.py 2026-04-02 11:19:24.000000000 +0200 @@ -243,12 +243,11 @@ with_sbd_option = self.sbd_devices or self.diskless_sbd if self.stage == "sbd": - if self.cluster_is_running: - utils.check_all_nodes_reachable("setup SBD") - node_list = utils.list_cluster_nodes() - else: - node_list = [utils.this_node()] - for node in node_list: + utils.check_all_nodes_reachable("setup SBD") + if not utils.calculate_quorate_status(): + utils.fatal("Cluster is not quorate, can't run 'sbd' stage") + + for node in utils.list_cluster_nodes(): if not utils.package_is_installed("sbd", node): utils.fatal(sbd.SBDManager.SBD_NOT_INSTALLED_MSG + f" on {node}") if self.sbd_devices and not utils.package_is_installed("fence-agents-sbd", node): @@ -2791,14 +2790,11 @@ def adjust_fencing_timeout(): """ - Adjust fencing-timeout for sbd and other scenarios + Adjust fencing-timeout for non sbd scenarios """ - if ServiceManager().service_is_active(constants.SBD_SERVICE): - sbd.SBDConfigChecker(quiet=True, fix=True).check_and_fix() - else: - value = get_fencing_timeout_generally_expected() - if value: - utils.set_property("fencing-timeout", value, conditional=True) + value = get_fencing_timeout_generally_expected() + if value: + utils.set_property("fencing-timeout", value, conditional=True) def adjust_properties(): @@ -2815,14 +2811,17 @@ - remove qdevice - add sbd via stage """ - if not ServiceManager().service_is_active("pacemaker.service"): + service_manager = ServiceManager() + if not service_manager.service_is_active("pacemaker.service"): return is_2node_wo_qdevice = utils.is_2node_cluster_without_qdevice() - adjust_pcmk_delay_max(is_2node_wo_qdevice) - adjust_fencing_timeout() + if service_manager.service_is_active(constants.SBD_SERVICE): + sbd.SBDConfigChecker(quiet=True, fix=True).check_and_fix() + else: + adjust_pcmk_delay_max(is_2node_wo_qdevice) + adjust_fencing_timeout() adjust_priority_in_rsc_defaults(is_2node_wo_qdevice) adjust_priority_fencing_delay(is_2node_wo_qdevice) - sbd.SBDManager.warn_diskless_sbd() def retrieve_files(from_node: str, file_list: list, msg: str = None): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/crmsh/sbd.py new/crmsh-5.0.0+20260402.90d08295/crmsh/sbd.py --- old/crmsh-5.0.0+20260401.827507a4/crmsh/sbd.py 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/crmsh/sbd.py 2026-04-02 11:19:24.000000000 +0200 @@ -187,6 +187,22 @@ value = utils.get_property("fencing-watchdog-timeout") return value and utils.crm_msec(value) > 0 + @staticmethod + def get_fence_sbd_parameters() -> list[dict]: + configure_show_output = sh.cluster_shell().get_stdout_or_raise_error("crm configure show xml") + configure_show_in_xml = xmlutil.text2elem(configure_show_output) + ra_inst = cibquery.ResourceAgent("stonith", "", "fence_sbd") + res_id_list = cibquery.get_primitives_with_ra(configure_show_in_xml, ra_inst) + + parameter_list = [] + for res in res_id_list: + parameter_list.append({ + "resource_id": res, + "crashdump": cibquery.get_parameter_value(configure_show_in_xml, res, "crashdump"), + "pcmk_delay_max": cibquery.get_parameter_value(configure_show_in_xml, res, "pcmk_delay_max"), + }) + return parameter_list + class SBDTimeout(object): ''' @@ -297,11 +313,14 @@ raise ValueError("Cannot get the value of SBD_WATCHDOG_TIMEOUT") return int(res) - def get_fencing_watchdog_timeout_expected(self): - if self.crashdump_watchdog_timeout: - return SBDTimeout.get_sbd_watchdog_timeout() + self.crashdump_watchdog_timeout - else: - return 2 * SBDTimeout.get_sbd_watchdog_timeout() + @staticmethod + def get_fencing_watchdog_timeout_expected( + crashdump_watchdog_timeout: int|None = None, + sbd_watchdog_timeout: int|None = None + ): + cwt = crashdump_watchdog_timeout or SBDUtils.get_crashdump_watchdog_timeout() + swt = sbd_watchdog_timeout or SBDTimeout.get_sbd_watchdog_timeout() + return max(swt+cwt, 2*swt) if cwt else 2 * swt def _load_configurations_from_runtime(self): ''' @@ -317,10 +336,11 @@ self.sbd_msgwait = device_metadata.get("msgwait") self.sbd_watchdog_timeout = device_metadata.get("watchdog") self.pcmk_delay_max = utils.get_pcmk_delay_max(self.two_node_without_qdevice) + self.fence_sbd_parameters = SBDUtils.get_fence_sbd_parameters() else: # disk-less self.disk_based = False self.sbd_watchdog_timeout = SBDTimeout.get_sbd_watchdog_timeout() - self.fencing_watchdog_timeout = self.get_fencing_watchdog_timeout_expected() + self.fencing_watchdog_timeout = SBDTimeout.get_fencing_watchdog_timeout_expected() self.sbd_delay_start_value_expected = self.get_sbd_delay_start_expected() if utils.detect_virt() else "no" self.sbd_delay_start_value_from_config = SBDUtils.get_sbd_value_from_config("SBD_DELAY_START") if not self.sbd_delay_start_value_from_config: @@ -487,6 +507,7 @@ SBD_DEVICE_METADATA_CONSISTENCY = auto() SBD_WATCHDOG_TIMEOUT = auto() FENCE_SBD_AGENT = auto() + FENCE_SBD_AGENT_PARAMETERS = auto() SBD_DELAY_START = auto() SBD_SYSTEMD_START_TIMEOUT = auto() FENCING_WATCHDOG_TIMEOUT_PROPERTY = auto() @@ -566,6 +587,14 @@ ), ( + "fence_sbd agent parameters", + self._check_fence_sbd_parameters, + self._fix_fence_sbd_parameters, + False, + [SBDCheckItem.FENCE_SBD_AGENT] + ), + + ( "SBD_DELAY_START", self._check_sbd_delay_start, self._fix_sbd_delay_start, @@ -573,7 +602,7 @@ [ SBDCheckItem.SBD_DISK_METADATA, SBDCheckItem.SBD_WATCHDOG_TIMEOUT, - SBDCheckItem.FENCE_SBD_AGENT + SBDCheckItem.FENCE_SBD_AGENT_PARAMETERS ] ), @@ -682,6 +711,7 @@ raise FixFailure(f"Failed to fix {name} issue") SBDConfigChecker._check_deprecated_property() + SBDManager.warn_diskless_sbd() return SBDConfigChecker._return_helper(check_res_list) @@ -988,6 +1018,7 @@ def _check_fence_sbd(self) -> CheckResult: if not self.disk_based: return CheckResult.SUCCESS + xml_inst = xmlutil.CrmMonXmlParser() if xml_inst.not_connected(): cib = xmlutil.text2elem(sh.cluster_shell().get_stdout_or_raise_error("crm configure show xml")) @@ -1016,6 +1047,7 @@ SBDManager.SBD_RA ) return CheckResult.ERROR + return CheckResult.SUCCESS def _fix_fence_sbd(self): @@ -1025,8 +1057,9 @@ logger.info("Configuring fence agent %s", SBDManager.SBD_RA) cmd = f"crm configure primitive {SBDManager.SBD_RA_ID} {SBDManager.SBD_RA}" shell.get_stdout_or_raise_error(cmd) - is_2node_wo_qdevice = utils.is_2node_cluster_without_qdevice() - bootstrap.adjust_pcmk_delay_max(is_2node_wo_qdevice) + if self.two_node_without_qdevice: + cmd = f"crm resource param {SBDManager.SBD_RA_ID} set pcmk_delay_max {constants.PCMK_DELAY_MAX}s" + shell.get_stdout_or_raise_error(cmd) elif not xml_inst.is_resource_started(SBDManager.SBD_RA): res_id_list = xml_inst.get_resource_id_list_via_type(SBDManager.SBD_RA) for res_id in res_id_list: @@ -1044,6 +1077,77 @@ ): utils.DeprecatedTermTranslator(prop).check() + def _check_fence_sbd_parameters(self) -> CheckResult: + if not self.disk_based: + return CheckResult.SUCCESS + if not self.fence_sbd_parameters: + self._log_when_not_quiet( + logging.ERROR, + "Fence agent %s is not configured", + SBDManager.SBD_RA + ) + return CheckResult.ERROR + + result_list = [] + for fence_sbd_param in self.fence_sbd_parameters: + res_id, crashdump, pcmk_delay_max = fence_sbd_param.values() + if utils.is_boolean_false(crashdump) and self.crashdump_watchdog_timeout: + self._log_when_not_quiet( + logging.ERROR, + "It's required that crashdump parameter is set to '1' in resource %s when sbd crashdump is configured, now is not set", + res_id + ) + result_list.append(CheckResult.ERROR) + elif utils.is_boolean_true(crashdump) and not self.crashdump_watchdog_timeout: + self._log_when_not_quiet( + logging.WARNING, + "It's recommended that crashdump parameter should not be set in resource %s when sbd crashdump is not configured", + res_id + ) + result_list.append(CheckResult.WARNING) + + if self.two_node_without_qdevice and not pcmk_delay_max: + self._log_when_not_quiet( + logging.ERROR, + "It's required that pcmk_delay_max parameter is set to %ds in resource %s for 2-node cluster without qdevice, now is not set", + constants.PCMK_DELAY_MAX, res_id + ) + result_list.append(CheckResult.ERROR) + elif pcmk_delay_max and not self.two_node_without_qdevice: + self._log_when_not_quiet( + logging.WARNING, + "It's recommended that pcmk_delay_max parameter should not be set in resource %s for clusters other than 2-node cluster without qdevice", + res_id + ) + result_list.append(CheckResult.WARNING) + + return SBDConfigChecker._return_helper(result_list) + + def _fix_fence_sbd_parameters(self): + shell = sh.cluster_shell() + for fence_sbd_param in self.fence_sbd_parameters: + cmd_for_crashdump, cmd_for_pcmk_delay_max = None, None + res_id, crashdump, pcmk_delay_max = fence_sbd_param.values() + + if utils.is_boolean_false(crashdump) and self.crashdump_watchdog_timeout: + logger.info("Setting crashdump parameter to '1' in resource %s", res_id) + cmd_for_crashdump = f"crm resource param {res_id} set crashdump 1" + elif utils.is_boolean_true(crashdump) and not self.crashdump_watchdog_timeout: + logger.info("Removing crashdump parameter in resource %s", res_id) + cmd_for_crashdump = f"crm resource param {res_id} delete crashdump" + if cmd_for_crashdump: + shell.get_stdout_or_raise_error(cmd_for_crashdump) + + if self.two_node_without_qdevice and not pcmk_delay_max: + logger.info("Setting pcmk_delay_max parameter to %ds in resource %s", constants.PCMK_DELAY_MAX, res_id) + cmd_for_pcmk_delay_max = f"crm resource param {res_id} set pcmk_delay_max {constants.PCMK_DELAY_MAX}s" + elif pcmk_delay_max and not self.two_node_without_qdevice: + logger.info("Removing pcmk_delay_max parameter in resource %s", res_id) + cmd_for_pcmk_delay_max = f"crm resource param {res_id} delete pcmk_delay_max" + if cmd_for_pcmk_delay_max: + shell.get_stdout_or_raise_error(cmd_for_pcmk_delay_max) + + class SBDManager: SYSCONFIG_SBD = "/etc/sysconfig/sbd" SYSCONFIG_SBD_TEMPLATE = "/usr/share/fillup-templates/sysconfig.sbd" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/crmsh/ui_sbd.py new/crmsh-5.0.0+20260402.90d08295/crmsh/ui_sbd.py --- old/crmsh-5.0.0+20260401.827507a4/crmsh/ui_sbd.py 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/crmsh/ui_sbd.py 2026-04-02 11:19:24.000000000 +0200 @@ -256,10 +256,10 @@ self._show_property() print() - return SBD.check_timeout_configurations() + return SBD.check_sbd_health() @staticmethod - def check_timeout_configurations() -> bool: + def check_sbd_health() -> bool: check_rc = sbd.CheckResult.SUCCESS try: check_rc = sbd.SBDConfigChecker().check_and_fix() @@ -459,7 +459,6 @@ Configure diskless SBD based on input parameters and runtime config ''' update_dict = {} - timeout_dict = {} watchdog_timeout = parameter_dict.get("watchdog") if watchdog_timeout and watchdog_timeout != self.watchdog_timeout_from_config: @@ -473,23 +472,21 @@ self._check_kdump_service() result_dict = self._set_crashdump_in_sysconfig(crashdump_watchdog_timeout, diskless=True) update_dict = {**update_dict, **result_dict} - sbd_watchdog_timeout = watchdog_timeout or self.watchdog_timeout_from_config - fencing_watchdog_timeout = sbd_watchdog_timeout + crashdump_watchdog_timeout - logger.info("Set fencing-watchdog-timeout to SBD_WATCHDOG_TIMEOUT + crashdump-watchdog-timeout: %s", fencing_watchdog_timeout) - timeout_dict["fencing-watchdog"] = fencing_watchdog_timeout if not update_dict: logger.info("No change in SBD configuration") return restart_first = False if watchdog_timeout: - expected_fencing_watchdog_timeout = timeout_dict.get("fencing-watchdog", 2*watchdog_timeout) + expected_fencing_watchdog_timeout = sbd.SBDTimeout.get_fencing_watchdog_timeout_expected( + crashdump_watchdog_timeout, + watchdog_timeout + ) # If the expected fencing-watchdog-timeout is smaller than runtime SBD_WATCHDOG_TIMEOUT, restart cluster first if expected_fencing_watchdog_timeout < self.watchdog_timeout_from_config: restart_first = True sbd_manager = sbd.SBDManager( - timeout_dict=timeout_dict, update_dict=update_dict, diskless_sbd=True ) @@ -745,4 +742,4 @@ self._print_sbd_cgroup_status() self._print_watchdog_info() self._print_sbd_agent_status() - return SBD.check_timeout_configurations() + return SBD.check_sbd_health() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/crmsh/utils.py new/crmsh-5.0.0+20260402.90d08295/crmsh/utils.py --- old/crmsh-5.0.0+20260401.827507a4/crmsh/utils.py 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/crmsh/utils.py 2026-04-02 11:19:24.000000000 +0200 @@ -2460,10 +2460,14 @@ return reachable_node_list -def calculate_quorate_status(expected_votes, actual_votes): +def calculate_quorate_status(expected_votes=-1, actual_votes=-1): """ Given expected votes and actual votes, calculate if is quorated """ + if expected_votes <= 0 or actual_votes < 0: + quorum_votes_dict = get_quorum_votes_dict() + expected_votes = quorum_votes_dict.get("Expected") + actual_votes = quorum_votes_dict.get("Total") return int(actual_votes)/int(expected_votes) > 0.5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/doc/crm.8.adoc new/crmsh-5.0.0+20260402.90d08295/doc/crm.8.adoc --- old/crmsh-5.0.0+20260401.827507a4/doc/crm.8.adoc 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/doc/crm.8.adoc 2026-04-02 11:19:24.000000000 +0200 @@ -354,7 +354,7 @@ fencing-watchdog-timeout = 2 * SBD_WATCHDOG_TIMEOUT # When setting crashdump watchdog timeout - fencing-watchdog-timeout = SBD_WATCHDOG_TIMEOUT + crashdump_watchdog_timeout + fencing-watchdog-timeout = max(SBD_WATCHDOG_TIMEOUT + crashdump_watchdog_timeout, 2 * SBD_WATCHDOG_TIMEOUT) ............... `fencing-timeout`: ............... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/test/features/bootstrap_sbd_delay.feature new/crmsh-5.0.0+20260402.90d08295/test/features/bootstrap_sbd_delay.feature --- old/crmsh-5.0.0+20260401.827507a4/test/features/bootstrap_sbd_delay.feature 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/test/features/bootstrap_sbd_delay.feature 2026-04-02 11:19:24.000000000 +0200 @@ -369,6 +369,17 @@ Then Expected "It's required that fencing-timeout is set to 71, now is 50" in stderr When Run "crm cluster health sbd --fix" on "hanode1" Then Expected "SBD: Check sbd timeout configuration: OK" in stdout + # check crashdump and pcmk_delay_max + When Run "crm resource param fencing-sbd set crashdump 1" on "hanode1" + When Run "crm resource param fencing-sbd delete pcmk_delay_max" on "hanode1" + When Try "crm cluster health sbd" on "hanode1" + Then Expected multiple lines in stderr + """ + It's recommended that crashdump parameter should not be set in resource fencing-sbd when sbd crashdump is not configured + It's required that pcmk_delay_max parameter is set to 30s in resource fencing-sbd for 2-node cluster without qdevice, now is not set + """ + When Run "crm cluster health sbd --fix" on "hanode1" + Then Expected "SBD: Check sbd timeout configuration: OK" in stdout # Adjust token timeout in corosync.conf When Run "sed -i 's/token: .*/token: 10000/' /etc/corosync/corosync.conf" on "hanode1" When Run "sed -i 's/token: .*/token: 10000/' /etc/corosync/corosync.conf" on "hanode2" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/test/features/sbd_ui.feature new/crmsh-5.0.0+20260402.90d08295/test/features/sbd_ui.feature --- old/crmsh-5.0.0+20260401.827507a4/test/features/sbd_ui.feature 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/test/features/sbd_ui.feature 2026-04-02 11:19:24.000000000 +0200 @@ -121,6 +121,8 @@ Then Run "crm sbd configure show property |grep fencing-watchdog-timeout=75" OK When Run "crm sbd configure crashdump-watchdog-timeout=60" on "hanode1" Then Expected "No change in SBD configuration" in stdout + When Run "crm sbd configure crashdump-watchdog-timeout=10" on "hanode1" + Then Run "crm sbd configure show property |grep fencing-watchdog-timeout=30" OK # Purge crashdump When Run "crm sbd purge crashdump" on "hanode1" When Try "crm sbd configure show sysconfig |grep SBD_TIMEOUT_ACTION=flush,crashdump" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/test/unittests/test_bootstrap.py new/crmsh-5.0.0+20260402.90d08295/test/unittests/test_bootstrap.py --- old/crmsh-5.0.0+20260401.827507a4/test/unittests/test_bootstrap.py 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/test/unittests/test_bootstrap.py 2026-04-02 11:19:24.000000000 +0200 @@ -139,9 +139,14 @@ ctx._validate_sbd_option() mock_error.assert_called_once_with("Can't use -s and -S options together") + @mock.patch('crmsh.utils.list_cluster_nodes') + @mock.patch('crmsh.utils.check_all_nodes_reachable') + @mock.patch('crmsh.utils.calculate_quorate_status') @mock.patch('crmsh.utils.package_is_installed') @mock.patch('crmsh.utils.fatal') - def test_validate_sbd_option_error_sbd_stage_no_option(self, mock_error, mock_installed): + def test_validate_sbd_option_error_sbd_stage_no_option(self, mock_error, mock_installed, mock_quorate, mock_check_all, mock_list): + mock_list.return_value = ["node1"] + mock_quorate.return_value = True mock_installed.return_value = True mock_error.side_effect = SystemExit ctx = crmsh.bootstrap.Context() @@ -151,10 +156,15 @@ ctx._validate_sbd_option() mock_error.assert_called_once_with("Stage sbd should specify sbd device by -s or diskless sbd by -S option") + @mock.patch('crmsh.utils.list_cluster_nodes') + @mock.patch('crmsh.utils.check_all_nodes_reachable') + @mock.patch('crmsh.utils.calculate_quorate_status') @mock.patch('crmsh.utils.package_is_installed') @mock.patch('crmsh.utils.fatal') @mock.patch('crmsh.service_manager.ServiceManager.service_is_active') - def test_validate_sbd_option_error_sbd_stage_service(self, mock_active, mock_error, mock_installed): + def test_validate_sbd_option_error_sbd_stage_service(self, mock_active, mock_error, mock_installed, mock_quorate, mock_check_all, mock_list): + mock_list.return_value = ["node1"] + mock_quorate.return_value = True mock_installed.return_value = True mock_error.side_effect = SystemExit ctx = crmsh.bootstrap.Context() @@ -166,18 +176,19 @@ mock_error.assert_called_once_with("Can't configure stage sbd: sbd.service already running! Please use crm option '-F' if need to redeploy") mock_active.assert_called_once_with("sbd.service") + @mock.patch('crmsh.utils.calculate_quorate_status') @mock.patch('crmsh.utils.fatal') @mock.patch('crmsh.utils.list_cluster_nodes') @mock.patch('crmsh.utils.package_is_installed') @mock.patch('crmsh.utils.check_all_nodes_reachable') - def test_validate_sbd_option_error_sbd_stage(self, mock_check_all, mock_installed, mock_list, mock_fatal): + def test_validate_sbd_option_error_sbd_stage(self, mock_check_all, mock_installed, mock_list, mock_fatal, mock_quorate): + mock_quorate.return_value = True mock_fatal.side_effect = ValueError mock_list.return_value = ["node1", "node2"] mock_installed.side_effect = [True, False] ctx = crmsh.bootstrap.Context() ctx.stage = "sbd" ctx.diskless_sbd = True - ctx.cluster_is_running = True with self.assertRaises(ValueError): ctx._validate_sbd_option() mock_check_all.assert_called_once_with("setup SBD") @@ -186,18 +197,19 @@ mock.call("sbd", "node2") ]) + @mock.patch('crmsh.utils.calculate_quorate_status') @mock.patch('crmsh.utils.fatal') @mock.patch('crmsh.utils.package_is_installed') @mock.patch('crmsh.utils.list_cluster_nodes') @mock.patch('crmsh.utils.check_all_nodes_reachable') - def test_validate_sbd_option_sbd_package_not_installed(self, mock_check_all, mock_list, mock_installed, mock_fatal): + def test_validate_sbd_option_sbd_package_not_installed(self, mock_check_all, mock_list, mock_installed, mock_fatal, mock_quorate): + mock_quorate.return_value = True mock_fatal.side_effect = ValueError mock_list.return_value = ["node1", "node2"] mock_installed.return_value = False ctx = crmsh.bootstrap.Context() ctx.stage = "sbd" ctx.diskless_sbd = True - ctx.cluster_is_running = True with self.assertRaises(ValueError): ctx._validate_sbd_option() @@ -206,13 +218,16 @@ mock_installed.assert_called_once_with("sbd", "node1") mock_fatal.assert_called_once_with(sbd.SBDManager.SBD_NOT_INSTALLED_MSG + " on node1") + @mock.patch('crmsh.utils.list_cluster_nodes') + @mock.patch('crmsh.utils.check_all_nodes_reachable') + @mock.patch('crmsh.utils.calculate_quorate_status') @mock.patch('crmsh.utils.fatal') @mock.patch('crmsh.utils.package_is_installed') - @mock.patch('crmsh.utils.this_node') @mock.patch('crmsh.sbd.SBDUtils.verify_sbd_device') - def test_validate_sbd_option_fence_sbd_package_not_installed(self, mock_verify, mock_this_node, mock_installed, mock_fatal): + def test_validate_sbd_option_fence_sbd_package_not_installed(self, mock_verify, mock_installed, mock_fatal, mock_quorate, mock_check_all, mock_list): + mock_quorate.return_value = True + mock_list.return_value = ["node1"] mock_fatal.side_effect = ValueError - mock_this_node.return_value = "node1" mock_installed.side_effect = [True, False] ctx = crmsh.bootstrap.Context() ctx.sbd_devices = ["/dev/sda1"] @@ -1478,21 +1493,9 @@ bootstrap.adjust_pcmk_delay_max(False) mock_run.assert_called_once_with("crm resource param res_1 delete pcmk_delay_max") - @mock.patch('crmsh.sbd.SBDConfigChecker') - @mock.patch('crmsh.service_manager.ServiceManager.service_is_active') - def test_adjust_fencing_timeout_sbd(self, mock_is_active, mock_sbd_checker): - mock_sbd_checker_inst = mock.Mock() - mock_sbd_checker.return_value = mock_sbd_checker_inst - mock_sbd_checker_inst.check_and_fix = mock.Mock() - mock_is_active.return_value = True - bootstrap.adjust_fencing_timeout() - mock_sbd_checker.assert_called_once_with(quiet=True, fix=True) - @mock.patch('crmsh.utils.set_property') @mock.patch('crmsh.bootstrap.get_fencing_timeout_generally_expected') - @mock.patch('crmsh.service_manager.ServiceManager.service_is_active') - def test_adjust_fencing_timeout(self, mock_is_active, mock_get_timeout, mock_set): - mock_is_active.return_value = False + def test_adjust_fencing_timeout(self, mock_get_timeout, mock_set): mock_get_timeout.return_value = 30 bootstrap.adjust_fencing_timeout() mock_set.assert_called_once_with("fencing-timeout", 30, conditional=True) @@ -1527,23 +1530,24 @@ bootstrap.adjust_properties() mock_is_active.assert_called_once_with("pacemaker.service") - @mock.patch('crmsh.sbd.SBDManager.warn_diskless_sbd') @mock.patch('crmsh.bootstrap.adjust_priority_fencing_delay') @mock.patch('crmsh.bootstrap.adjust_priority_in_rsc_defaults') @mock.patch('crmsh.bootstrap.adjust_fencing_timeout') @mock.patch('crmsh.bootstrap.adjust_pcmk_delay_max') @mock.patch('crmsh.utils.is_2node_cluster_without_qdevice') @mock.patch('crmsh.service_manager.ServiceManager.service_is_active') - def test_adjust_properties(self, mock_is_active, mock_2node_qdevice, mock_adj_pcmk, mock_adj_fencing, mock_adj_priority, mock_adj_fence, mock_warn_sbd): - mock_is_active.return_value = True + def test_adjust_properties(self, mock_is_active, mock_2node_qdevice, mock_adj_pcmk, mock_adj_fencing, mock_adj_priority, mock_adj_fence): + mock_is_active.side_effect = [True, False] mock_2node_qdevice.return_value = True bootstrap.adjust_properties() - mock_is_active.assert_called_once_with("pacemaker.service") + mock_is_active.assert_has_calls([ + mock.call("pacemaker.service"), + mock.call("sbd.service") + ]) mock_adj_pcmk.assert_called_once_with(True) mock_adj_fencing.assert_called_once_with() mock_adj_priority.assert_called_once_with(True) mock_adj_fence.assert_called_once_with(True) - mock_warn_sbd.assert_called_once_with() @mock.patch('crmsh.utils.cluster_copy_path') @mock.patch('crmsh.utils.fetch_cluster_node_list_from_node') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/test/unittests/test_sbd.py new/crmsh-5.0.0+20260402.90d08295/test/unittests/test_sbd.py --- old/crmsh-5.0.0+20260401.827507a4/test/unittests/test_sbd.py 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/test/unittests/test_sbd.py 2026-04-02 11:19:24.000000000 +0200 @@ -335,10 +335,11 @@ self.instance_check._check_config_consistency.assert_called_once() @patch('crmsh.sbd.SBDConfigChecker._check_deprecated_property') + @patch('crmsh.sbd.SBDManager.warn_diskless_sbd') @patch('crmsh.utils.list_cluster_nodes_except_me') @patch('crmsh.utils.check_all_nodes_reachable') @patch('crmsh.sbd.ServiceManager') - def test_check_and_fix_not_fix(self, mock_service_manager, mock_check_all_nodes_reachable, mock_list_cluster_nodes_except_me, mock_check_deprecated_property): + def test_check_and_fix_not_fix(self, mock_service_manager, mock_check_all_nodes_reachable, mock_list_cluster_nodes_except_me, mock_warn_diskless_sbd, mock_check_deprecated_property): mock_service_manager_inst = Mock() mock_service_manager.return_value = mock_service_manager_inst mock_service_manager_inst.service_is_active = Mock(return_value=True) @@ -385,10 +386,11 @@ self.assertTrue("Failed to fix SBD disk metadata" in str(context.exception)) @patch('crmsh.sbd.SBDConfigChecker._check_deprecated_property') + @patch('crmsh.sbd.SBDManager.warn_diskless_sbd') @patch('crmsh.utils.list_cluster_nodes_except_me') @patch('crmsh.utils.check_all_nodes_reachable') @patch('crmsh.sbd.ServiceManager') - def test_check_and_fix_fix_success(self, mock_service_manager, mock_check_all_nodes_reachable, mock_list_cluster_nodes_except_me, mock_check_deprecated_property): + def test_check_and_fix_fix_success(self, mock_service_manager, mock_check_all_nodes_reachable, mock_list_cluster_nodes_except_me, mock_warn_diskless_sbd, mock_check_deprecated_property): mock_service_manager_inst = Mock() mock_service_manager.return_value = mock_service_manager_inst mock_service_manager_inst.service_is_active = Mock(return_value=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260401.827507a4/test/unittests/test_ui_sbd.py new/crmsh-5.0.0+20260402.90d08295/test/unittests/test_ui_sbd.py --- old/crmsh-5.0.0+20260401.827507a4/test/unittests/test_ui_sbd.py 2026-04-01 08:32:17.000000000 +0200 +++ new/crmsh-5.0.0+20260402.90d08295/test/unittests/test_ui_sbd.py 2026-04-02 11:19:24.000000000 +0200 @@ -452,7 +452,6 @@ mock_SBDManager.return_value.init_and_deploy_sbd = mock.Mock() self.sbd_instance_diskless._configure_diskless(parameter_dict) mock_SBDManager.assert_called_once_with( - timeout_dict={'fencing-watchdog': 24}, update_dict={'SBD_WATCHDOG_TIMEOUT': '12', 'SBD_WATCHDOG_DEV': '/dev/watchdog100', 'SBD_TIMEOUT_ACTION': 'flush,crashdump', 'SBD_OPTS': '-C 12 -Z'}, diskless_sbd=True ) @@ -716,7 +715,7 @@ self.sbd_instance_diskbased.cluster_shell.get_stdout_or_raise_error.side_effect = [data_node1, "10", data_node2, "10"] self.sbd_instance_diskbased._print_watchdog_info() - @mock.patch('crmsh.ui_sbd.SBD.check_timeout_configurations') + @mock.patch('crmsh.ui_sbd.SBD.check_sbd_health') def test_do_status(self, mock_check_timeout): self.sbd_instance_diskbased._load_attributes = mock.Mock() self.sbd_instance_diskbased._print_sbd_type = mock.Mock()
