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-02-26 18:59:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new.29461 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh" Thu Feb 26 18:59:40 2026 rev:397 rq:1335252 version:5.0.0+20260226.8b99a4c5 Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2026-02-09 13:53:01.680010573 +0100 +++ /work/SRC/openSUSE:Factory/.crmsh.new.29461/crmsh.changes 2026-02-26 18:59:43.649240492 +0100 @@ -1,0 +2,33 @@ +Thu Feb 26 10:07:15 UTC 2026 - [email protected] + +- Update to version 5.0.0+20260226.8b99a4c5: + * Chore: codecov: update expected report count + * Fix: behave: Remove redundant dos2unix in run-functional-tests (#2034) + * Dev: behave: Adjust functional test for previous commit + * Dev: bootstrap: Disable sbd.service when the process is in 'cluster' stage + * Dev: unittests: Adjust unit test for previous commit + * Dev: sbd: Move diskless SBD warning to adjust_properties + * Dev: sbd: record ERROR when prerequisite checks fail + * Dev: unittests: Adjust unit test for previous commit + * Dev: sbd: rename SBDTimeoutChecker to SBDConfigChecker + * Dev: sbd: Replace magic numbers with IntEnum for check prerequisites + * Dev: unittests: Adjust unit test for previous commit + * Dev: sbd: Add self._log_when_not_quiet() method to avoid checking self.quiet everywhere + * Dev: unittests: Adjust unit test for previous commit + * Dev: bootstrap: The sbd stage now requires a running cluster + * Dev: sbd: Adjust related properties after cluster started on init process + * Dev: sbd: Add quiet attribute to class SBDTimeout + +------------------------------------------------------------------- +Tue Feb 10 04:53:16 UTC 2026 - [email protected] + +- Update to version 5.0.0+20260210.baf54ddb: + * Dev: workflows: Enable Python 3.14 for unit test + +------------------------------------------------------------------- +Tue Feb 10 03:12:21 UTC 2026 - [email protected] + +- Update to version 5.0.0+20260210.24e46036: + * minieval.py : remove ast.Num and ast.Str no longer available in Python 3.14 + +------------------------------------------------------------------- Old: ---- crmsh-5.0.0+20260209.ed56b53c.tar.bz2 New: ---- crmsh-5.0.0+20260226.8b99a4c5.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.wCq83j/_old 2026-02-26 18:59:45.261307755 +0100 +++ /var/tmp/diff_new_pack.wCq83j/_new 2026-02-26 18:59:45.265307922 +0100 @@ -41,7 +41,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0-or-later Group: %{pkg_group} -Version: 5.0.0+20260209.ed56b53c +Version: 5.0.0+20260226.8b99a4c5 Release: 0 URL: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.wCq83j/_old 2026-02-26 18:59:45.321310259 +0100 +++ /var/tmp/diff_new_pack.wCq83j/_new 2026-02-26 18:59:45.325310426 +0100 @@ -9,7 +9,7 @@ </service> <service name="tar_scm"> <param name="url">https://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">41e6d81ca2affd5395ba48265e00ab71c111b1d8</param> + <param name="changesrevision">c57573d04cc8f9f0a4162d330529bc609b721c2d</param> </service> </servicedata> (No newline at EOF) ++++++ crmsh-5.0.0+20260209.ed56b53c.tar.bz2 -> crmsh-5.0.0+20260226.8b99a4c5.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/.github/workflows/crmsh-ci.yml new/crmsh-5.0.0+20260226.8b99a4c5/.github/workflows/crmsh-ci.yml --- old/crmsh-5.0.0+20260209.ed56b53c/.github/workflows/crmsh-ci.yml 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/.github/workflows/crmsh-ci.yml 2026-02-26 10:31:40.000000000 +0100 @@ -35,7 +35,7 @@ runs-on: ubuntu-24.04 strategy: matrix: - python-version: ['3.11', '3.12', '3.13'] + python-version: ['3.11', '3.12', '3.13', '3.14'] fail-fast: false timeout-minutes: 5 steps: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/codecov.yml new/crmsh-5.0.0+20260226.8b99a4c5/codecov.yml --- old/crmsh-5.0.0+20260209.ed56b53c/codecov.yml 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/codecov.yml 2026-02-26 10:31:40.000000000 +0100 @@ -8,7 +8,7 @@ threshold: 0.35% codecov: notify: - after_n_builds: 33 + after_n_builds: 34 comment: - after_n_builds: 33 + after_n_builds: 34 layout: "condensed_header, flags, files, condensed_footer" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/crmsh/bootstrap.py new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/bootstrap.py --- old/crmsh-5.0.0+20260209.ed56b53c/crmsh/bootstrap.py 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/bootstrap.py 2026-02-26 10:31:40.000000000 +0100 @@ -304,7 +304,7 @@ if self.type == "init": if self.stage not in INIT_STAGES_ALL: utils.fatal(f"Invalid stage: {self.stage}(available stages: {', '.join(INIT_STAGES_EXTERNAL)})") - if self.stage in ("admin", "qdevice", "ocfs2") and not self.cluster_is_running: + if self.stage in ("admin", "sbd", "qdevice", "ocfs2") and not self.cluster_is_running: utils.fatal(f"Cluster is inactive, can't run '{self.stage}' stage") if self.stage in ("corosync", "cluster") and self.cluster_is_running: utils.fatal(f"Cluster is active, can't run '{self.stage}' stage") @@ -1465,6 +1465,11 @@ """ Initial cluster configuration. """ + if _context.stage == "cluster": + service_manager = ServiceManager() + if service_manager.service_is_enabled(constants.SBD_SERVICE): + service_manager.disable_service(constants.SBD_SERVICE) + generate_pacemaker_remote_auth() init_cluster_local() @@ -1483,9 +1488,7 @@ rsc_defaults rsc-options: resource-stickiness=1 migration-threshold=3 """) - if ServiceManager().service_is_enabled(constants.SBD_SERVICE): - _context.sbd_manager.configure_sbd() - + adjust_properties() def init_admin(): @@ -2173,10 +2176,10 @@ corosync.configure_two_node(removing=True) logger.info("Propagating configuration changes across the remaining nodes") sync_path(corosync.conf()) - adjust_properties() - sh.cluster_shell().get_stdout_or_raise_error("corosync-cfgtool -R") + adjust_properties() + if not dead_node: FirewallManager(peer=node).remove_service() @@ -2204,7 +2207,6 @@ "ssh": ssh_stage_finished, "firewalld": FirewallManager.firewalld_stage_finished, "corosync": corosync_stage_finished, - "sbd": lambda: True, "cluster": is_online } @@ -2762,7 +2764,7 @@ Adjust stonith-timeout for sbd and other scenarios """ if ServiceManager().service_is_active(constants.SBD_SERVICE): - sbd.SBDTimeoutChecker(quiet=True, fix=True).check_and_fix() + sbd.SBDConfigChecker(quiet=True, fix=True).check_and_fix() else: value = get_stonith_timeout_generally_expected() if value: @@ -2790,6 +2792,7 @@ adjust_stonith_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+20260209.ed56b53c/crmsh/minieval.py new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/minieval.py --- old/crmsh-5.0.0+20260209.ed56b53c/crmsh/minieval.py 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/minieval.py 2026-02-26 10:31:40.000000000 +0100 @@ -183,8 +183,7 @@ self.names = names self.nodes = { - ast.Num: self._eval_num, - ast.Str: self._eval_str, + ast.Constant: self._eval_constant, ast.Name: self._eval_name, ast.UnaryOp: self._eval_unaryop, ast.BinOp: self._eval_binop, @@ -204,9 +203,13 @@ elif isinstance(self.names, dict) and "None" not in self.names: self.names["None"] = None - # py3.8 uses ast.Constant instead of ast.Num, ast.Str, ast.NameConstant - if hasattr(ast, 'Constant'): - self.nodes[ast.Constant] = self._eval_constant + # py3.14 completely dropped ast.Num and ast.Str + # in favor of ast.Constant that encodes different types of value + # See https://docs.python.org/3/whatsnew/3.14.html#id9 + if hasattr(ast, 'Str'): + self.nodes[ast.Str] = self._eval_str + if hasattr(ast, 'Num'): + self.nodes[ast.Num] = self._eval_num def evaluate(self, expr): """ evaluate an expresssion, using the operators, functions and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/crmsh/sbd.py new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/sbd.py --- old/crmsh-5.0.0+20260209.ed56b53c/crmsh/sbd.py 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/sbd.py 2026-02-26 10:31:40.000000000 +0100 @@ -3,7 +3,8 @@ import typing import shutil import time -from enum import Enum +import logging +from enum import Enum, IntEnum, auto from . import utils, sh from . import bootstrap from . import log @@ -212,9 +213,15 @@ self.crashdump_watchdog_timeout = None self.sbd_msgwait_expected = None self.sbd_watchdog_timeout_expected = None + self.quiet = False if self.context: + self.quiet = self.context.quiet self._initialize_timeout_from_bootstrap() + def _log_when_not_quiet(self, level, message, *args, **kwargs): + if not self.quiet: + logger.log(level, message, *args, **kwargs) + def _initialize_timeout_from_bootstrap(self): self._set_sbd_watchdog_timeout() if self.context.diskless_sbd: @@ -230,7 +237,11 @@ if "sbd.watchdog_timeout" in self.context.profiles_dict: self.sbd_watchdog_timeout = int(self.context.profiles_dict["sbd.watchdog_timeout"]) if self.context.is_s390 and self.sbd_watchdog_timeout < self.SBD_WATCHDOG_TIMEOUT_DEFAULT_S390: - logger.warning("sbd_watchdog_timeout is set to %d for s390, it was %d", self.SBD_WATCHDOG_TIMEOUT_DEFAULT_S390, self.sbd_watchdog_timeout) + self._log_when_not_quiet( + logging.WARNING, + "sbd watchdog_timeout is set to %d for s390, it was %d", + self.SBD_WATCHDOG_TIMEOUT_DEFAULT_S390, self.sbd_watchdog_timeout + ) self.sbd_watchdog_timeout = self.SBD_WATCHDOG_TIMEOUT_DEFAULT_S390 def _set_sbd_msgwait(self): @@ -243,7 +254,11 @@ if "sbd.msgwait" in self.context.profiles_dict: sbd_msgwait = int(self.context.profiles_dict["sbd.msgwait"]) if sbd_msgwait < sbd_msgwait_default: - logger.warning("sbd msgwait is set to %d, it was %d", sbd_msgwait_default, sbd_msgwait) + self._log_when_not_quiet( + logging.WARNING, + "sbd msgwait is set to %d, it was %d", + sbd_msgwait_default, sbd_msgwait + ) sbd_msgwait = sbd_msgwait_default self.sbd_msgwait = sbd_msgwait @@ -256,7 +271,8 @@ qdevice_sync_timeout = utils.get_qdevice_sync_timeout() if self.sbd_watchdog_timeout <= qdevice_sync_timeout: watchdog_timeout_with_qdevice = qdevice_sync_timeout + self.QDEVICE_SYNC_TIMEOUT_MARGIN - logger.warning( + self._log_when_not_quiet( + logging.WARNING, "SBD_WATCHDOG_TIMEOUT should not less than %d for qdevice, it was %d", watchdog_timeout_with_qdevice, self.sbd_watchdog_timeout ) @@ -264,7 +280,8 @@ # add sbd and qdevice together from beginning elif self.context.qdevice_inst: if self.sbd_watchdog_timeout < self.SBD_WATCHDOG_TIMEOUT_DEFAULT_WITH_QDEVICE: - logger.warning( + self._log_when_not_quiet( + logging.WARNING, "SBD_WATCHDOG_TIMEOUT should not less than %d for qdevice, it was %d", self.SBD_WATCHDOG_TIMEOUT_DEFAULT_WITH_QDEVICE, self.sbd_watchdog_timeout ) @@ -458,7 +475,21 @@ __str__ = lambda self: self.name -class SBDTimeoutChecker(SBDTimeout): +class SBDCheckItem(IntEnum): + SBD_DISK_METADATA = 0 + SBD_DEVICE_METADATA_CONSISTENCY = auto() + SBD_WATCHDOG_TIMEOUT = auto() + FENCE_SBD_AGENT = auto() + SBD_DELAY_START = auto() + SBD_SYSTEMD_START_TIMEOUT = auto() + STONITH_WATCHDOG_TIMEOUT_PROPERTY = auto() + STONITH_TIMEOUT_PROPERTY = auto() + STONITH_ENABLED_PROPERTY = auto() + UNSET_SBD_DELAY_START_IN_DROPIN = auto() + ENABLE_SBD_SERVICE = auto() + + +class SBDConfigChecker(SBDTimeout): def __init__(self, quiet=False, fix=False): super().__init__() @@ -492,8 +523,8 @@ logger.info('SBD: Check sbd timeout configuration: OK.') return True - def check_and_fix(self) -> CheckResult: - checks_and_fixes = [ + def _check_and_fix_items(self) -> list[tuple]: + return [ # issue name, check method, fix method, SSH required, prerequisites checks ( "SBD disk metadata", @@ -508,7 +539,7 @@ self._check_sbd_device_metadata_consistency, self._fix_sbd_device_metadata_consistency, True, - [0] + [SBDCheckItem.SBD_DISK_METADATA] ), ( @@ -532,7 +563,11 @@ self._check_sbd_delay_start, self._fix_sbd_delay_start, True, - [0, 2, 3] + [ + SBDCheckItem.SBD_DISK_METADATA, + SBDCheckItem.SBD_WATCHDOG_TIMEOUT, + SBDCheckItem.FENCE_SBD_AGENT + ] ), ( @@ -540,7 +575,7 @@ self._check_sbd_systemd_start_timeout, self._fix_sbd_systemd_start_timeout, True, - [4] + [SBDCheckItem.SBD_DELAY_START] ), ( @@ -548,7 +583,7 @@ self._check_stonith_watchdog_timeout, self._fix_stonith_watchdog_timeout, False, - [2] + [SBDCheckItem.SBD_WATCHDOG_TIMEOUT] ), ( @@ -556,7 +591,10 @@ self._check_stonith_timeout, self._fix_stonith_timeout, False, - [0, 2] + [ + SBDCheckItem.SBD_DISK_METADATA, + SBDCheckItem.SBD_WATCHDOG_TIMEOUT + ] ), ( @@ -584,6 +622,7 @@ ), ] + def check_and_fix(self) -> CheckResult: if not ServiceManager().service_is_active(constants.SBD_SERVICE): if self.fix: raise FixAborted("%s is not active, skip fixing SBD timeout issues" % constants.SBD_SERVICE) @@ -605,9 +644,11 @@ self._load_configurations_from_runtime() - check_res_list = [CheckResult.SUCCESS for _ in range(len(checks_and_fixes))] - for index, (name, check_method, fix_method, ssh_required, prereq_checks) in enumerate(checks_and_fixes): - if prereq_checks and any(check_res_list[i] != CheckResult.SUCCESS for i in prereq_checks): + check_and_fix_items = self._check_and_fix_items() + check_res_list = [CheckResult.SUCCESS for _ in range(len(check_and_fix_items))] + for index, (name, check_method, fix_method, ssh_required, prereq_checks) in enumerate(check_and_fix_items): + if prereq_checks and any(check_res_list[p.value] != CheckResult.SUCCESS for p in prereq_checks): + check_res_list[index] = CheckResult.ERROR continue check_res = check_method() logger.debug("SBD Checking: %s, result: %s", name, check_res) @@ -626,7 +667,7 @@ else: raise FixFailure(f"Failed to fix {name} issue") - return SBDTimeoutChecker._return_helper(check_res_list) + return SBDConfigChecker._return_helper(check_res_list) def _check_config_consistency(self, error_msg: str = "") -> bool: consistent = True @@ -674,12 +715,18 @@ if self.disk_based: self.sbd_watchdog_timeout_expected, self.sbd_msgwait_expected = SBDTimeout.get_sbd_metadata_expected() if self.sbd_watchdog_timeout < self.sbd_watchdog_timeout_expected: - if not self.quiet: - logger.error("It's required that SBD watchdog timeout(now %d) >= %d", self.sbd_watchdog_timeout, self.sbd_watchdog_timeout_expected) + self._log_when_not_quiet( + logging.ERROR, + "It's required that SBD watchdog timeout(now %d) >= %d", + self.sbd_watchdog_timeout, self.sbd_watchdog_timeout_expected + ) return CheckResult.ERROR if self.sbd_msgwait < self.sbd_msgwait_expected: - if not self.quiet: - logger.error("It's required that SBD msgwait(now %d) >= %d", self.sbd_msgwait, self.sbd_msgwait_expected) + self._log_when_not_quiet( + logging.ERROR, + "It's required that SBD msgwait(now %d) >= %d", + self.sbd_msgwait, self.sbd_msgwait_expected + ) return CheckResult.ERROR return CheckResult.SUCCESS @@ -699,8 +746,11 @@ if not self.disk_based: self.sbd_watchdog_timeout_expected = SBDTimeout.get_sbd_watchdog_timeout_expected(diskless=True) if self.sbd_watchdog_timeout < self.sbd_watchdog_timeout_expected: - if not self.quiet: - logger.error("It's required that SBD_WATCHDOG_TIMEOUT(now %d) >= %d", self.sbd_watchdog_timeout, self.sbd_watchdog_timeout_expected) + self._log_when_not_quiet( + logging.ERROR, + "It's required that SBD_WATCHDOG_TIMEOUT(now %d) >= %d", + self.sbd_watchdog_timeout, self.sbd_watchdog_timeout_expected + ) return CheckResult.ERROR return CheckResult.SUCCESS @@ -714,19 +764,25 @@ return CheckResult.SUCCESS elif config_value.isdigit() and expected_value.isdigit(): if int(config_value) < int(expected_value): - if not self.quiet: - logger.error("It's required that SBD_DELAY_START is set to %s, now is %s", - expected_value, config_value) + self._log_when_not_quiet( + logging.ERROR, + "It's required that SBD_DELAY_START is set to %s, now is %s", + expected_value, config_value + ) return CheckResult.ERROR else: - if not self.quiet: - logger.warning("It's recommended that SBD_DELAY_START is set to %s, now is %s", - expected_value, config_value) + self._log_when_not_quiet( + logging.WARNING, + "It's recommended that SBD_DELAY_START is set to %s, now is %s", + expected_value, config_value + ) return CheckResult.WARNING else: - if not self.quiet: - logger.error("It's required that SBD_DELAY_START is set to %s, now is %s", - expected_value, config_value) + self._log_when_not_quiet( + logging.ERROR, + "It's required that SBD_DELAY_START is set to %s, now is %s", + expected_value, config_value + ) return CheckResult.ERROR def _fix_sbd_delay_start(self): @@ -741,21 +797,21 @@ if actual_start_timeout == expected_start_timeout: check_res_list.append(CheckResult.SUCCESS) elif actual_start_timeout < expected_start_timeout: - if not self.quiet: - logger.error( - "It's required that systemd start timeout for sbd.service is set to %ds, now is %ds on node %s", - expected_start_timeout, actual_start_timeout, node - ) + self._log_when_not_quiet( + logging.ERROR, + "It's required that systemd start timeout for sbd.service is set to %ds, now is %ds on node %s", + expected_start_timeout, actual_start_timeout, node + ) check_res_list.append(CheckResult.ERROR) else: - if not self.quiet: - logger.warning( - "It's recommended that systemd start timeout for sbd.service is set to %ds, now is %ds on node %s", - expected_start_timeout, actual_start_timeout, node - ) + self._log_when_not_quiet( + logging.WARNING, + "It's recommended that systemd start timeout for sbd.service is set to %ds, now is %ds on node %s", + expected_start_timeout, actual_start_timeout, node + ) check_res_list.append(CheckResult.WARNING) - return SBDTimeoutChecker._return_helper(check_res_list) + return SBDConfigChecker._return_helper(check_res_list) def _fix_sbd_systemd_start_timeout(self): logger.info("Adjusting systemd start timeout for sbd.service to %ds", self.sbd_systemd_start_timeout_expected) @@ -768,30 +824,41 @@ def _check_stonith_watchdog_timeout(self) -> CheckResult: value = utils.get_property("stonith-watchdog-timeout") if value and int(value) == -1: - if not self.quiet: - logger.warning("It's recommended that stonith-watchdog-timeout is et to %d, now is -1", self.stonith_watchdog_timeout) + self._log_when_not_quiet( + logging.WARNING, + "It's recommended that stonith-watchdog-timeout is set to %d, now is -1", + self.stonith_watchdog_timeout + ) return CheckResult.WARNING value = int(utils.crm_msec(value)/1000) if self.disk_based: if value > 0: - if not self.quiet: - logger.warning("It's recommended that stonith-watchdog-timeout is not set when using disk-based SBD") + self._log_when_not_quiet( + logging.WARNING, + "It's recommended that stonith-watchdog-timeout is not set when using disk-based SBD" + ) return CheckResult.WARNING else: if value == 0: - if not self.quiet: - logger.error("It's required that stonith-watchdog-timeout is set to %d, now is not set", - self.stonith_watchdog_timeout) + self._log_when_not_quiet( + logging.ERROR, + "It's required that stonith-watchdog-timeout is set to %d, now is not set", + self.stonith_watchdog_timeout + ) return CheckResult.ERROR if value < self.stonith_watchdog_timeout: - if not self.quiet: - logger.error("It's required that stonith-watchdog-timeout is set to %d, now is %d", - self.stonith_watchdog_timeout, value) + self._log_when_not_quiet( + logging.ERROR, + "It's required that stonith-watchdog-timeout is set to %d, now is %d", + self.stonith_watchdog_timeout, value + ) return CheckResult.ERROR elif value > self.stonith_watchdog_timeout: - if not self.quiet: - logger.warning("It's recommended that stonith-watchdog-timeout is set to %d, now is %d", - self.stonith_watchdog_timeout, value) + self._log_when_not_quiet( + logging.WARNING, + "It's recommended that stonith-watchdog-timeout is set to %d, now is %d", + self.stonith_watchdog_timeout, value + ) return CheckResult.WARNING return CheckResult.SUCCESS @@ -809,14 +876,18 @@ # will get default value from pacemaker metadata if not set value = int(utils.crm_msec(value)/1000) if value < expected_value: - if not self.quiet: - logger.error("It's required that stonith-timeout is set to %d, now is %d", - expected_value, value) + self._log_when_not_quiet( + logging.ERROR, + "It's required that stonith-timeout is set to %d, now is %d", + expected_value, value + ) return CheckResult.ERROR elif value > expected_value: - if not self.quiet: - logger.warning("It's recommended that stonith-timeout is set to %d, now is %d", - expected_value, value) + self._log_when_not_quiet( + logging.WARNING, + "It's recommended that stonith-timeout is set to %d, now is %d", + expected_value, value + ) return CheckResult.WARNING return CheckResult.SUCCESS @@ -828,8 +899,10 @@ def _check_stonith_enabled(self) -> CheckResult: value = utils.get_property("stonith-enabled", get_default=False) if utils.is_boolean_false(value): - if not self.quiet: - logger.error("It's required that stonith-enabled is set to true, now is false") + self._log_when_not_quiet( + logging.ERROR, + "It's required that stonith-enabled is set to true, now is false" + ) return CheckResult.ERROR return CheckResult.SUCCESS @@ -849,12 +922,14 @@ if rc == 0: check_res_list.append(CheckResult.SUCCESS) else: - if not self.quiet: - logger.warning("Runtime drop-in file %s to unset SBD_DELAY_START is missing on node %s", - SBDManager.SBD_SYSTEMD_DELAY_START_DISABLE_FILE, node) + self._log_when_not_quiet( + logging.WARNING, + "Runtime drop-in file %s to unset SBD_DELAY_START is missing on node %s", + SBDManager.SBD_SYSTEMD_DELAY_START_DISABLE_FILE, node + ) check_res_list.append(CheckResult.WARNING) - return SBDTimeoutChecker._return_helper(check_res_list) + return SBDConfigChecker._return_helper(check_res_list) def _fix_sbd_delay_start_unset_dropin(self): logger.info("Createing runtime drop-in file %s to unset SBD_DELAY_START", @@ -868,11 +943,14 @@ if service_manager.service_is_enabled(constants.SBD_SERVICE, node): check_res_list.append(CheckResult.SUCCESS) else: - if not self.quiet: - logger.error("%s is not enabled on node %s", constants.SBD_SERVICE, node) + self._log_when_not_quiet( + logging.ERROR, + "%s is not enabled on node %s", + constants.SBD_SERVICE, node + ) self.service_disabled_node_list.append(node) check_res_list.append(CheckResult.ERROR) - return SBDTimeoutChecker._return_helper(check_res_list) + return SBDConfigChecker._return_helper(check_res_list) def _fix_sbd_service_is_enabled(self): service_manager = ServiceManager() @@ -891,16 +969,25 @@ if configured: return CheckResult.SUCCESS else: - if not self.quiet: - logger.error("Fence agent %s is not configured", SBDManager.SBD_RA) + self._log_when_not_quiet( + logging.ERROR, + "Fence agent %s is not configured", + SBDManager.SBD_RA + ) return CheckResult.ERROR if not xml_inst.is_resource_configured(SBDManager.SBD_RA): - if not self.quiet: - logger.error("Fence agent %s is not configured", SBDManager.SBD_RA) + self._log_when_not_quiet( + logging.ERROR, + "Fence agent %s is not configured", + SBDManager.SBD_RA + ) return CheckResult.ERROR elif not xml_inst.is_resource_started(SBDManager.SBD_RA) and not utils.is_cluster_in_maintenance_mode(): - if not self.quiet: - logger.error("Fence agent %s is not started", SBDManager.SBD_RA) + self._log_when_not_quiet( + logging.ERROR, + "Fence agent %s is not started", + SBDManager.SBD_RA + ) return CheckResult.ERROR return CheckResult.SUCCESS @@ -1020,7 +1107,6 @@ def initialize_sbd(self): if self.diskless_sbd: logger.info("Configuring diskless SBD") - self._warn_diskless_sbd() return elif self.device_list_to_init: logger.info("Configuring disk-based SBD") @@ -1047,34 +1133,16 @@ logger.info("Enable %s on node %s", constants.SBD_SERVICE, node) service_manager.enable_service(constants.SBD_SERVICE, node) - def configure_sbd(self): - ''' - Configure fence_sbd resource and related properties - ''' - if SBDUtils.get_sbd_device_from_config(): - if utils.get_property("stonith-watchdog-timeout", get_default=False): - utils.delete_property("stonith-watchdog-timeout") - if not xmlutil.CrmMonXmlParser().is_resource_configured(self.SBD_RA): - cmd = f"crm configure primitive {self.SBD_RA_ID} {self.SBD_RA}" - sh.cluster_shell().get_stdout_or_raise_error(cmd) - else: - swt_value = self.timeout_dict.get("stonith-watchdog", 2*SBDTimeout.get_sbd_watchdog_timeout()) - utils.set_property("stonith-watchdog-timeout", swt_value) - utils.set_property("stonith-enabled", "true") - - def _warn_diskless_sbd(self, peer=None): + @staticmethod + def warn_diskless_sbd(): ''' Give warning when configuring diskless sbd ''' - # When in sbd stage or join process - if (self.diskless_sbd and self.cluster_is_running) or peer: - vote_dict = utils.get_quorum_votes_dict(peer) + if SBDUtils.is_using_diskless_sbd(): + vote_dict = utils.get_quorum_votes_dict() expected_vote = int(vote_dict.get('Expected', 0)) - if expected_vote < self.DISKLESS_SBD_MIN_EXPECTED_VOTE: - logger.warning('%s', self.DISKLESS_SBD_WARNING) - # When in init process - elif self.diskless_sbd: - logger.warning('%s', self.DISKLESS_SBD_WARNING) + if expected_vote < SBDManager.DISKLESS_SBD_MIN_EXPECTED_VOTE: + logger.warning('%s', SBDManager.DISKLESS_SBD_WARNING) def _warn_and_raise_no_sbd(self): logger.warning('%s', self.NO_SBD_WARNING) @@ -1235,8 +1303,6 @@ if dev_list: SBDUtils.verify_sbd_device(dev_list, [peer_host]) - else: - self._warn_diskless_sbd(peer_host) logger.info("Got {}SBD configuration".format("" if dev_list else "diskless ")) self.enable_sbd_service() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/crmsh/ui_cluster.py new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/ui_cluster.py --- old/crmsh-5.0.0+20260209.ed56b53c/crmsh/ui_cluster.py 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/ui_cluster.py 2026-02-26 10:31:40.000000000 +0100 @@ -352,8 +352,8 @@ firewalld Add high-availability service to firewalld csync2 Configure csync2 corosync Configure corosync - sbd Configure SBD (requires -s <dev>) cluster Bring the cluster online + sbd Configure SBD (requires -s <dev>) ocfs2 Configure OCFS2 (requires -o <dev>) NOTE: this is a Technical Preview gfs2 Configure GFS2 (requires -g <dev>) NOTE: this is a Technical Preview admin Create administration virtual IP (optional) @@ -847,7 +847,7 @@ case 'sbd': fix = parsed_args.fix try: - result = sbd.SBDTimeoutChecker(quiet=fix, fix=fix).check_and_fix() + result = sbd.SBDConfigChecker(quiet=fix, fix=fix).check_and_fix() except sbd.FixFailure as e: logger.error('%s', e) return False @@ -855,7 +855,7 @@ logger.error('%s', e) logger.error('SBD: Check sbd timeout configuration: FAIL.') return False - return sbd.SBDTimeoutChecker.log_and_return(result, fix) + return sbd.SBDConfigChecker.log_and_return(result, fix) case 'sles16': try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/crmsh/ui_sbd.py new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/ui_sbd.py --- old/crmsh-5.0.0+20260209.ed56b53c/crmsh/ui_sbd.py 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/crmsh/ui_sbd.py 2026-02-26 10:31:40.000000000 +0100 @@ -259,11 +259,11 @@ def check_timeout_configurations() -> bool: check_rc = sbd.CheckResult.SUCCESS try: - check_rc = sbd.SBDTimeoutChecker().check_and_fix() + check_rc = sbd.SBDConfigChecker().check_and_fix() except sbd.FixAborted as e: logger.error('%s', e) return False - return sbd.SBDTimeoutChecker.log_and_return(check_rc) + return sbd.SBDConfigChecker.log_and_return(check_rc) def _parse_args(self, args: tuple[str, ...]) -> dict[str, int|str]: ''' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/test/features/bootstrap_options.feature new/crmsh-5.0.0+20260226.8b99a4c5/test/features/bootstrap_options.feature --- old/crmsh-5.0.0+20260209.ed56b53c/test/features/bootstrap_options.feature 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/test/features/bootstrap_options.feature 2026-02-26 10:31:40.000000000 +0100 @@ -34,8 +34,8 @@ """ When Try "crm cluster init -N hanode2" on "hanode1" Then Expected "Can't use -N/--nodes option without -y/--yes option" in stderr - When Try "crm cluster init sbd -N hanode1 -N hanode2 -y" on "hanode1" - Then Expected "Can't use -N/--nodes option and stage(sbd) together" in stderr + When Try "crm cluster init cluster -N hanode1 -N hanode2 -y" on "hanode1" + Then Expected "Can't use -N/--nodes option and stage(cluster) together" in stderr When Try "crm corosync link help add" on "hanode1" Then Expected return code is "0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/test/features/bootstrap_sbd_delay.feature new/crmsh-5.0.0+20260226.8b99a4c5/test/features/bootstrap_sbd_delay.feature --- old/crmsh-5.0.0+20260209.ed56b53c/test/features/bootstrap_sbd_delay.feature 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/test/features/bootstrap_sbd_delay.feature 2026-02-26 10:31:40.000000000 +0100 @@ -15,13 +15,13 @@ Then Cluster service is "started" on "hanode1" And Service "sbd" is "started" on "hanode1" And Resource "stonith-sbd" type "fence_sbd" is "Started" - And SBD option "SBD_DELAY_START" value is "no" + And SBD option "SBD_DELAY_START" value is "41" And SBD option "SBD_WATCHDOG_TIMEOUT" value is "5" And SBD option "msgwait" value for "/dev/sda1" is "30" # original value is 43, which is calculated by external/sbd RA # now fence_sbd doesn't calculate it, so this value is the default one # from pacemaker - And Cluster property "stonith-timeout" is "60" + And Cluster property "stonith-timeout" is "71" And Parameter "pcmk_delay_max" not configured in "stonith-sbd" Given Has disk "/dev/sda1" on "hanode2" @@ -78,7 +78,7 @@ And Parameter "pcmk_delay_max" configured in "stonith-sbd" @clean - Scenario: disk-less SBD with small sbd_watchdog_timeout + Scenario: diskless SBD with small sbd_watchdog_timeout Given Run "test -f /etc/crm/profiles.yml" OK Given Yaml "default:corosync.totem.token" value is "5000" Given Yaml "default:sbd.watchdog_timeout" value is "15" @@ -86,17 +86,17 @@ Given Cluster service is "stopped" on "hanode1" When Run "crm cluster init -S -y" on "hanode1" Then Cluster service is "started" on "hanode1" - And SBD option "SBD_DELAY_START" value is "no" + And SBD option "SBD_DELAY_START" value is "41" And SBD option "SBD_WATCHDOG_TIMEOUT" value is "15" - And Cluster property "stonith-timeout" is "60" + And Cluster property "stonith-timeout" is "71" Given Cluster service is "stopped" on "hanode2" When Run "crm cluster join -c hanode1 -y" on "hanode2" Then Cluster service is "started" on "hanode2" - # SBD_DELAY_START >= (token + consensus + 2*SBD_WATCHDOG_TIMEOUT) # for disk-less sbd + # SBD_DELAY_START >= (token + consensus + 2*SBD_WATCHDOG_TIMEOUT) # for diskless sbd And SBD option "SBD_DELAY_START" value is "41" And SBD option "SBD_WATCHDOG_TIMEOUT" value is "15" - # stonith-timeout >= 1.2 * max(stonith_watchdog_timeout, 2*SBD_WATCHDOG_TIMEOUT) # for disk-less sbd + # stonith-timeout >= 1.2 * max(stonith_watchdog_timeout, 2*SBD_WATCHDOG_TIMEOUT) # for diskless sbd # stonith_timeout >= max(value_from_sbd, constants.STONITH_TIMEOUT_DEFAULT) + token + consensus And Cluster property "stonith-timeout" is "71" @@ -114,7 +114,7 @@ And Cluster property "stonith-timeout" is "71" When Try "crm configure property stonith-watchdog-timeout=1" on "hanode1" - Then Except "Can't set stonith-watchdog-timeout to 1 because it is less than SBD_WATCHDOG_TIMEOUT(now: 15)" in stderr + Then Except "It's required to set stonith-watchdog-timeout to at least 2*SBD_WATCHDOG_TIMEOUT: 30" in stderr @clean Scenario: disk-based SBD with big sbd_watchdog_timeout @@ -128,13 +128,13 @@ Then Cluster service is "started" on "hanode1" And Service "sbd" is "started" on "hanode1" And Resource "stonith-sbd" type "fence_sbd" is "Started" - And SBD option "SBD_DELAY_START" value is "no" + And SBD option "SBD_DELAY_START" value is "131" And SBD option "SBD_WATCHDOG_TIMEOUT" value is "5" And SBD option "msgwait" value for "/dev/sda1" is "120" # original value is 172, which is calculated by external/sbd RA # now fence_sbd doesn't calculate it, so this value is the default one # from pacemaker - And Cluster property "stonith-timeout" is "60" + And Cluster property "stonith-timeout" is "155" And Parameter "pcmk_delay_max" not configured in "stonith-sbd" Given Has disk "/dev/sda1" on "hanode2" @@ -230,7 +230,7 @@ And Parameter "pcmk_delay_max" not configured in "stonith-sbd" @clean - Scenario: Add disk-less sbd with qdevice + Scenario: Add diskless sbd with qdevice Given Run "test -f /etc/crm/profiles.yml" OK Given Yaml "default:corosync.totem.token" value is "5000" Given Yaml "default:sbd.watchdog_timeout" value is "15" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/test/features/bootstrap_sbd_normal.feature new/crmsh-5.0.0+20260226.8b99a4c5/test/features/bootstrap_sbd_normal.feature --- old/crmsh-5.0.0+20260209.ed56b53c/test/features/bootstrap_sbd_normal.feature 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/test/features/bootstrap_sbd_normal.feature 2026-02-26 10:31:40.000000000 +0100 @@ -82,8 +82,8 @@ Given Cluster service is "stopped" on "hanode2" When Run "crm cluster init ssh -y" on "hanode1" And Run "crm cluster init corosync -y" on "hanode1" - And Run "crm cluster init sbd -s /dev/sda1 -y" on "hanode1" And Run "crm cluster init cluster -y" on "hanode1" + And Run "crm cluster init sbd -s /dev/sda1 -y" on "hanode1" Then Cluster service is "started" on "hanode1" And Service "sbd" is "started" on "hanode1" When Run "crm cluster join ssh -y -c hanode1" on "hanode2" @@ -99,8 +99,8 @@ Given Cluster service is "stopped" on "hanode2" When Run "crm cluster init ssh -y" on "hanode1" And Run "crm cluster init corosync -y" on "hanode1" - And Run "crm cluster init sbd -S -y" on "hanode1" And Run "crm cluster init cluster -y" on "hanode1" + And Run "crm cluster init sbd -S -y" on "hanode1" Then Cluster service is "started" on "hanode1" And Service "sbd" is "started" on "hanode1" When Run "crm cluster join ssh -y -c hanode1" on "hanode2" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/test/features/steps/const.py new/crmsh-5.0.0+20260226.8b99a4c5/test/features/steps/const.py --- old/crmsh-5.0.0+20260209.ed56b53c/test/features/steps/const.py 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/test/features/steps/const.py 2026-02-26 10:31:40.000000000 +0100 @@ -157,8 +157,8 @@ firewalld Add high-availability service to firewalld csync2 Configure csync2 corosync Configure corosync - sbd Configure SBD (requires -s <dev>) cluster Bring the cluster online + sbd Configure SBD (requires -s <dev>) ocfs2 Configure OCFS2 (requires -o <dev>) NOTE: this is a Technical Preview gfs2 Configure GFS2 (requires -g <dev>) NOTE: this is a Technical Preview admin Create administration virtual IP (optional) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/test/run-functional-tests new/crmsh-5.0.0+20260226.8b99a4c5/test/run-functional-tests --- old/crmsh-5.0.0+20260209.ed56b53c/test/run-functional-tests 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/test/run-functional-tests 2026-02-26 10:31:40.000000000 +0100 @@ -363,7 +363,7 @@ podman_exec $node_name "sed -i s/$item/$ip/g $2" done - vip_replace_array=(`podman_exec $node_name "grep -o -E '@vip\.[0-9]' $2|sort -u|dos2unix"`) + vip_replace_array=(`podman_exec $node_name "grep -o -E '@vip\.[0-9]' $2|sort -u"`) for item in ${vip_replace_array[@]};do index=`echo $item|cut -d "." -f 2|tr -d "\r"` suffix=$((123+index)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/test/unittests/test_bootstrap.py new/crmsh-5.0.0+20260226.8b99a4c5/test/unittests/test_bootstrap.py --- old/crmsh-5.0.0+20260209.ed56b53c/test/unittests/test_bootstrap.py 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/test/unittests/test_bootstrap.py 2026-02-26 10:31:40.000000000 +0100 @@ -1528,7 +1528,7 @@ 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.SBDTimeoutChecker') + @mock.patch('crmsh.sbd.SBDConfigChecker') @mock.patch('crmsh.service_manager.ServiceManager.service_is_active') def test_adjust_stonith_timeout_sbd(self, mock_is_active, mock_sbd_checker): mock_sbd_checker_inst = mock.Mock() @@ -1577,13 +1577,14 @@ 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_stonith_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_stonith, mock_adj_priority, mock_adj_fence): + def test_adjust_properties(self, mock_is_active, mock_2node_qdevice, mock_adj_pcmk, mock_adj_stonith, mock_adj_priority, mock_adj_fence, mock_warn_sbd): mock_is_active.return_value = True mock_2node_qdevice.return_value = True bootstrap.adjust_properties() @@ -1592,6 +1593,7 @@ mock_adj_stonith.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+20260209.ed56b53c/test/unittests/test_sbd.py new/crmsh-5.0.0+20260226.8b99a4c5/test/unittests/test_sbd.py --- old/crmsh-5.0.0+20260209.ed56b53c/test/unittests/test_sbd.py 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/test/unittests/test_sbd.py 2026-02-26 10:31:40.000000000 +0100 @@ -267,11 +267,11 @@ self.assertEqual(result, 80) -class TestSBDTimeoutChecker(unittest.TestCase): +class TestSBDConfigChecker(unittest.TestCase): def setUp(self): - self.instance_check = sbd.SBDTimeoutChecker(fix=False) - self.instance_fix = sbd.SBDTimeoutChecker(fix=True) + self.instance_check = sbd.SBDConfigChecker(fix=False) + self.instance_fix = sbd.SBDConfigChecker(fix=True) @patch('logging.Logger.info') def test_log_and_return_success(self, mock_logger_info): @@ -428,24 +428,24 @@ self.assertTrue(self.instance_check._check_config_consistency("no peer nodes")) mock_logger_warning.assert_called_once_with("Skipping configuration consistency check: %s", "no peer nodes") - @patch('logging.Logger.error') @patch('crmsh.sbd.SBDTimeout.get_sbd_metadata_expected') - def test_check_sbd_disk_metadata_failure(self, mock_get_sbd_metadata_expected, mock_logger_error): + def test_check_sbd_disk_metadata_failure(self, mock_get_sbd_metadata_expected): self.instance_check.disk_based = True + self.instance_check._log_when_not_quiet = Mock() mock_get_sbd_metadata_expected.return_value = (15, 30) self.instance_check.sbd_watchdog_timeout = 10 self.assertEqual(self.instance_check._check_sbd_disk_metadata(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("It's required that SBD watchdog timeout(now %d) >= %d", 10, 15) - - @patch('logging.Logger.error') + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "It's required that SBD watchdog timeout(now %d) >= %d", 10, 15) + @patch('crmsh.sbd.SBDTimeout.get_sbd_metadata_expected') - def test_check_sbd_disk_metadata_failure_msgwait(self, mock_get_sbd_metadata_expected, mock_logger_error): + def test_check_sbd_disk_metadata_failure_msgwait(self, mock_get_sbd_metadata_expected): self.instance_check.disk_based = True + self.instance_check._log_when_not_quiet = Mock() mock_get_sbd_metadata_expected.return_value = (10, 25) self.instance_check.sbd_watchdog_timeout = 10 self.instance_check.sbd_msgwait = 20 self.assertEqual(self.instance_check._check_sbd_disk_metadata(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("It's required that SBD msgwait(now %d) >= %d", 20, 25) + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "It's required that SBD msgwait(now %d) >= %d", 20, 25) @patch('crmsh.sbd.SBDTimeout.get_sbd_metadata_expected') def test_check_sbd_disk_metadata_success(self, mock_get_sbd_metadata_expected): @@ -466,14 +466,14 @@ self.instance_fix._fix_sbd_disk_metadata() mock_logger_info.assert_called_once_with("Adjusting sbd msgwait to %d, watchdog timeout to %d", 10, 5) - @patch('logging.Logger.error') @patch('crmsh.sbd.SBDTimeout.get_sbd_watchdog_timeout_expected') - def test_check_sbd_watchdog_timeout_failure(self, mock_get_sbd_watchdog_timeout_expected, mock_logger_error): + def test_check_sbd_watchdog_timeout_failure(self, mock_get_sbd_watchdog_timeout_expected): self.instance_check.disk_based = False + self.instance_check._log_when_not_quiet = Mock() mock_get_sbd_watchdog_timeout_expected.return_value = 10 self.instance_check.sbd_watchdog_timeout = 3 self.assertEqual(self.instance_check._check_sbd_watchdog_timeout(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("It's required that SBD_WATCHDOG_TIMEOUT(now %d) >= %d", 3, 10) + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "It's required that SBD_WATCHDOG_TIMEOUT(now %d) >= %d", 3, 10) @patch('crmsh.sbd.SBDTimeout.get_sbd_watchdog_timeout_expected') def test_check_sbd_watchdog_timeout_success(self, mock_get_sbd_watchdog_timeout_expected): @@ -488,24 +488,24 @@ self.instance_fix._fix_sbd_watchdog_timeout() mock_update_sbd_configuration.assert_called_once_with({"SBD_WATCHDOG_TIMEOUT": "10"}) - @patch('logging.Logger.error') - def test_check_sbd_delay_start_failure(self, mock_logger_error): + def test_check_sbd_delay_start_failure(self): self.instance_check.sbd_delay_start_value_expected = "100" self.instance_check.sbd_delay_start_value_from_config = "30" + self.instance_check._log_when_not_quiet = Mock() self.assertEqual(self.instance_check._check_sbd_delay_start(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("It's required that SBD_DELAY_START is set to %s, now is %s", "100", "30") + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "It's required that SBD_DELAY_START is set to %s, now is %s", "100", "30") def test_check_sbd_delay_start_success(self): self.instance_check.sbd_delay_start_value_expected = "50" self.instance_check.sbd_delay_start_value_from_config = "50" self.assertTrue(self.instance_check._check_sbd_delay_start()) - @patch('logging.Logger.warning') - def test_check_sbd_delay_start_warning(self, mock_logger_warning): + def test_check_sbd_delay_start_warning(self): self.instance_check.sbd_delay_start_value_expected = "70" self.instance_check.sbd_delay_start_value_from_config = "80" + self.instance_check._log_when_not_quiet = Mock() self.assertEqual(self.instance_check._check_sbd_delay_start(), sbd.CheckResult.WARNING) - mock_logger_warning.assert_called_once_with("It's recommended that SBD_DELAY_START is set to %s, now is %s", "70", "80") + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.WARNING, "It's recommended that SBD_DELAY_START is set to %s, now is %s", "70", "80") @patch('crmsh.sbd.SBDManager.update_sbd_configuration') def test_fix_sbd_delay_start(self, mock_update_sbd_configuration): @@ -513,23 +513,24 @@ self.instance_fix._fix_sbd_delay_start() mock_update_sbd_configuration.assert_called_once_with({"SBD_DELAY_START": "80"}) - @patch('crmsh.sbd.SBDTimeoutChecker._return_helper') - @patch('logging.Logger.warning') - @patch('logging.Logger.error') + @patch('crmsh.sbd.SBDConfigChecker._return_helper') @patch('crmsh.sbd.SBDTimeout.get_sbd_systemd_start_timeout') @patch('crmsh.utils.this_node') - def test_check_sbd_systemd_start_timeout(self, mock_this_node, mock_get_sbd_systemd_start_timeout, mock_logger_error, mock_logger_warning, mock_return_helper): + def test_check_sbd_systemd_start_timeout(self, mock_this_node, mock_get_sbd_systemd_start_timeout, mock_return_helper): mock_this_node.return_value = 'node1' self.instance_check.sbd_systemd_start_timeout_expected = 60 self.instance_check.peer_node_list = ['node2', 'node3'] self.instance_check.quiet = False + self.instance_check._log_when_not_quiet = Mock() mock_get_sbd_systemd_start_timeout.side_effect = [60, 50, 70] mock_return_helper.return_value = sbd.CheckResult.ERROR self.assertEqual(self.instance_check._check_sbd_systemd_start_timeout(), sbd.CheckResult.ERROR) - mock_logger_warning.assert_called_once_with("It's recommended that systemd start timeout for sbd.service is set to %ds, now is %ds on node %s", 60, 70, 'node3') - mock_logger_error.assert_called_once_with("It's required that systemd start timeout for sbd.service is set to %ds, now is %ds on node %s", 60, 50, 'node2') + self.instance_check._log_when_not_quiet.assert_has_calls([ + call(logging.ERROR, "It's required that systemd start timeout for sbd.service is set to %ds, now is %ds on node %s", 60, 50, 'node2'), + call(logging.WARNING, "It's recommended that systemd start timeout for sbd.service is set to %ds, now is %ds on node %s", 60, 70, 'node3') + ]) @patch('crmsh.utils.cluster_run_cmd') @patch('crmsh.bootstrap.sync_path') @@ -543,22 +544,22 @@ self.instance_fix._fix_sbd_systemd_start_timeout() mock_logger_info.assert_called_once_with("Adjusting systemd start timeout for sbd.service to %ds", 120) - @patch('logging.Logger.warning') @patch('crmsh.utils.get_property') - def test_check_stonith_watchdog_timeout_disk_based_failure(self, mock_get_property, mock_logger_warning): + def test_check_stonith_watchdog_timeout_disk_based_failure(self, mock_get_property): self.instance_check.disk_based = True mock_get_property.return_value = 5 + self.instance_check._log_when_not_quiet = Mock() self.assertEqual(self.instance_check._check_stonith_watchdog_timeout(), sbd.CheckResult.WARNING) - mock_logger_warning.assert_called_once_with("It's recommended that stonith-watchdog-timeout is not set when using disk-based SBD") + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.WARNING, "It's recommended that stonith-watchdog-timeout is not set when using disk-based SBD") - @patch('logging.Logger.error') @patch('crmsh.utils.get_property') - def test_check_stonith_watchdog_timeout_disk_less_failure(self, mock_get_property, mock_logger_error): + def test_check_stonith_watchdog_timeout_disk_less_failure(self, mock_get_property): self.instance_check.disk_based = False self.instance_check.stonith_watchdog_timeout = 15 mock_get_property.return_value = "" + self.instance_check._log_when_not_quiet = Mock() self.assertEqual(self.instance_check._check_stonith_watchdog_timeout(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("It's required that stonith-watchdog-timeout is set to %d, now is not set", 15) + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "It's required that stonith-watchdog-timeout is set to %d, now is not set", 15) @patch('crmsh.utils.get_property') def test_check_stonith_watchdog_timeout_success(self, mock_get_property): @@ -584,21 +585,21 @@ mock_logger_info.assert_called_once_with("Adjusting stonith-watchdog-timeout to %d", 15) mock_set_property.assert_called_once_with('stonith-watchdog-timeout', 15) - @patch('logging.Logger.error') @patch('crmsh.utils.get_property') - def test_check_stonith_timeout_failure(self, mock_get_property, mock_logger_error): + def test_check_stonith_timeout_failure(self, mock_get_property): self.instance_check.get_stonith_timeout_expected = Mock(return_value=60) mock_get_property.return_value = 30 + self.instance_check._log_when_not_quiet = Mock() self.assertEqual(self.instance_check._check_stonith_timeout(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("It's required that stonith-timeout is set to %d, now is %d", 60, 30) + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "It's required that stonith-timeout is set to %d, now is %d", 60, 30) - @patch('logging.Logger.warning') @patch('crmsh.utils.get_property') - def test_check_stonith_timeout_warning(self, mock_get_property, mock_logger_warning): + def test_check_stonith_timeout_warning(self, mock_get_property): self.instance_check.get_stonith_timeout_expected = Mock(return_value=80) mock_get_property.return_value = 90 + self.instance_check._log_when_not_quiet = Mock() self.assertEqual(self.instance_check._check_stonith_timeout(), sbd.CheckResult.WARNING) - mock_logger_warning.assert_called_once_with("It's recommended that stonith-timeout is set to %d, now is %d", 80, 90) + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.WARNING, "It's recommended that stonith-timeout is set to %d, now is %d", 80, 90) @patch('crmsh.utils.get_property') def test_check_stonith_timeout_success(self, mock_get_property): @@ -619,24 +620,24 @@ mock_is_sbd_delay_start.return_value = False self.assertEqual(self.instance_check._check_sbd_delay_start_unset_dropin(), sbd.CheckResult.SUCCESS) - @patch('crmsh.sbd.SBDTimeoutChecker._return_helper') - @patch('logging.Logger.warning') + @patch('crmsh.sbd.SBDConfigChecker._return_helper') @patch('crmsh.utils.this_node') @patch('crmsh.sh.cluster_shell') @patch('crmsh.sbd.SBDTimeout.is_sbd_delay_start') - def test_check_sbd_delay_start_unset_dropin(self, mock_is_sbd_delay_start, mock_cluster_shell, mock_this_node, mock_logger_warning, mock_return_helper): + def test_check_sbd_delay_start_unset_dropin(self, mock_is_sbd_delay_start, mock_cluster_shell, mock_this_node, mock_return_helper): mock_is_sbd_delay_start.return_value = True mock_this_node.return_value = 'node1' mock_cluster_shell_inst = Mock() mock_cluster_shell.return_value = mock_cluster_shell_inst self.instance_check.peer_node_list = ['node2'] self.instance_check.quiet = False + self.instance_check._log_when_not_quiet = Mock() mock_cluster_shell_inst.get_rc_and_error.side_effect = [(0, None), (1, None)] mock_return_helper.return_value = sbd.CheckResult.WARNING self.assertEqual(self.instance_check._check_sbd_delay_start_unset_dropin(), sbd.CheckResult.WARNING) - mock_logger_warning.assert_called_once_with("Runtime drop-in file %s to unset SBD_DELAY_START is missing on node %s", sbd.SBDManager.SBD_SYSTEMD_DELAY_START_DISABLE_FILE, 'node2') + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.WARNING, "Runtime drop-in file %s to unset SBD_DELAY_START is missing on node %s", sbd.SBDManager.SBD_SYSTEMD_DELAY_START_DISABLE_FILE, 'node2') @patch('crmsh.sbd.SBDManager.unset_sbd_delay_start') @patch('logging.Logger.info') @@ -648,20 +649,20 @@ self.instance_check.disk_based = False self.assertEqual(self.instance_check._check_fence_sbd(), sbd.CheckResult.SUCCESS) - @patch('crmsh.sbd.SBDTimeoutChecker._return_helper') - @patch('logging.Logger.error') + @patch('crmsh.sbd.SBDConfigChecker._return_helper') @patch('crmsh.utils.this_node') @patch('crmsh.sbd.ServiceManager') - def test_check_sbd_service_is_enabled(self, mock_ServiceManager, mock_this_node, mock_logger_error, mock_return_helper): + def test_check_sbd_service_is_enabled(self, mock_ServiceManager, mock_this_node, mock_return_helper): mock_this_node.return_value = 'node1' mock_service_manager_inst = Mock() mock_ServiceManager.return_value = mock_service_manager_inst self.instance_check.peer_node_list = ['node2'] self.instance_check.quiet = False + self.instance_check._log_when_not_quiet = Mock() mock_service_manager_inst.service_is_enabled.side_effect = [True, False] mock_return_helper.return_value = sbd.CheckResult.ERROR self.assertEqual(self.instance_check._check_sbd_service_is_enabled(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("%s is not enabled on node %s", constants.SBD_SERVICE, 'node2') + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "%s is not enabled on node %s", constants.SBD_SERVICE, 'node2') @patch('logging.Logger.info') @patch('crmsh.sbd.ServiceManager') @@ -673,27 +674,27 @@ self.instance_fix._fix_sbd_service_is_enabled() mock_logger_info.assert_called_once_with("Enabling %s on node %s", constants.SBD_SERVICE, 'node2') - @patch('logging.Logger.error') @patch('crmsh.xmlutil.CrmMonXmlParser') - def test_check_fence_sbd_not_configured(self, mock_CrmMonXmlParser, mock_logger_error): + def test_check_fence_sbd_not_configured(self, mock_CrmMonXmlParser): self.instance_check.disk_based = True self.instance_check.quiet = False + self.instance_check._log_when_not_quiet = Mock() mock_parser_instance = Mock() mock_CrmMonXmlParser.return_value = mock_parser_instance mock_parser_instance.not_connected.return_value = False mock_parser_instance.is_resource_configured.return_value = False self.assertEqual(self.instance_check._check_fence_sbd(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("Fence agent %s is not configured", sbd.SBDManager.SBD_RA) + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "Fence agent %s is not configured", sbd.SBDManager.SBD_RA) - @patch('logging.Logger.error') @patch('crmsh.cibquery.get_primitives_with_ra') @patch('crmsh.cibquery.ResourceAgent') @patch('crmsh.xmlutil.text2elem') @patch('crmsh.sh.cluster_shell') @patch('crmsh.xmlutil.CrmMonXmlParser') - def test_check_fence_sbd_not_configured_cluster_offline(self, mock_CrmMonXmlParser, mock_cluster_shell, mock_text2elem, mock_ResourceAgent, mock_get_primitives_with_ra, mock_logger_error): + def test_check_fence_sbd_not_configured_cluster_offline(self, mock_CrmMonXmlParser, mock_cluster_shell, mock_text2elem, mock_ResourceAgent, mock_get_primitives_with_ra): self.instance_check.disk_based = True self.instance_check.quiet = False + self.instance_check._log_when_not_quiet = Mock() mock_parser_instance = Mock() mock_CrmMonXmlParser.return_value = mock_parser_instance mock_parser_instance.not_connected.return_value = True @@ -705,7 +706,7 @@ mock_ResourceAgent.return_value = mock_resource_agent_instance mock_get_primitives_with_ra.return_value = [] self.assertEqual(self.instance_check._check_fence_sbd(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("Fence agent %s is not configured", sbd.SBDManager.SBD_RA) + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "Fence agent %s is not configured", sbd.SBDManager.SBD_RA) @patch('crmsh.cibquery.get_primitives_with_ra') @patch('crmsh.cibquery.ResourceAgent') @@ -726,18 +727,18 @@ mock_get_primitives_with_ra.return_value = ['fence_sbd_0'] self.assertEqual(self.instance_check._check_fence_sbd(), sbd.CheckResult.SUCCESS) - @patch('logging.Logger.error') @patch('crmsh.xmlutil.CrmMonXmlParser') - def test_check_fence_sbd_not_started(self, mock_CrmMonXmlParser, mock_logger_error): + def test_check_fence_sbd_not_started(self, mock_CrmMonXmlParser): self.instance_check.disk_based = True self.instance_check.quiet = False + self.instance_check._log_when_not_quiet = Mock() mock_parser_instance = Mock() mock_CrmMonXmlParser.return_value = mock_parser_instance mock_parser_instance.not_connected.return_value = False mock_parser_instance.is_resource_configured.return_value = True mock_parser_instance.is_resource_started.return_value = False self.assertEqual(self.instance_check._check_fence_sbd(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("Fence agent %s is not started", sbd.SBDManager.SBD_RA) + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "Fence agent %s is not started", sbd.SBDManager.SBD_RA) @patch('crmsh.xmlutil.CrmMonXmlParser') def test_check_fence_sbd_success(self, mock_CrmMonXmlParser): @@ -787,14 +788,14 @@ mock_is_boolean_false.return_value = False self.assertEqual(self.instance_check._check_stonith_enabled(), sbd.CheckResult.SUCCESS) - @patch('logging.Logger.error') @patch('crmsh.utils.is_boolean_false') @patch('crmsh.utils.get_property') - def test_check_stonith_enabled_failure(self, mock_get_property, mock_is_boolean_false, mock_logger_error): + def test_check_stonith_enabled_failure(self, mock_get_property, mock_is_boolean_false): mock_get_property.return_value = "false" mock_is_boolean_false.return_value = True + self.instance_check._log_when_not_quiet = Mock() self.assertEqual(self.instance_check._check_stonith_enabled(), sbd.CheckResult.ERROR) - mock_logger_error.assert_called_once_with("It's required that stonith-enabled is set to true, now is false") + self.instance_check._log_when_not_quiet.assert_called_once_with(logging.ERROR, "It's required that stonith-enabled is set to true, now is false") @patch('logging.Logger.info') @patch('crmsh.utils.set_property') @@ -942,22 +943,13 @@ sbdmanager_instance._warn_and_raise_no_sbd() mock_logger_warning.assert_called_once_with('%s', SBDManager.NO_SBD_WARNING) - @patch('crmsh.sbd.ServiceManager') @patch('crmsh.utils.get_quorum_votes_dict') @patch('logging.Logger.warning') - def test_warn_diskless_sbd(self, mock_logger_warning, mock_get_quorum_votes_dict, mock_ServiceManager): - mock_ServiceManager.return_value.service_is_active = MagicMock(return_value=True) + @patch('crmsh.sbd.SBDUtils.is_using_diskless_sbd') + def test_warn_diskless_sbd(self, mock_is_using_sbd, mock_logger_warning, mock_get_quorum_votes_dict): + mock_is_using_sbd.return_value = True mock_get_quorum_votes_dict.return_value = {'Expected': '2', 'Total': '2'} - sbdmanager_instance = SBDManager() - sbdmanager_instance._warn_diskless_sbd(peer="node1") - mock_logger_warning.assert_called_once_with('%s', SBDManager.DISKLESS_SBD_WARNING) - - @patch('crmsh.sbd.ServiceManager') - @patch('logging.Logger.warning') - def test_warn_diskless_sbd_init(self, mock_logger_warning, mock_ServiceManager): - mock_ServiceManager.return_value.service_is_active = MagicMock(return_value=False) - sbdmanager_instance = SBDManager(diskless_sbd=True) - sbdmanager_instance._warn_diskless_sbd() + sbd.SBDManager.warn_diskless_sbd() mock_logger_warning.assert_called_once_with('%s', SBDManager.DISKLESS_SBD_WARNING) @patch('crmsh.sbd.SBDUtils.check_devices_metadata_consistent') @@ -1130,36 +1122,6 @@ sbdmanager_instance.initialize_sbd() mock_convert_timeout_dict_to_opt_str.assert_not_called() - @patch('crmsh.utils.set_property') - @patch('crmsh.sbd.ServiceManager') - @patch('crmsh.sbd.SBDTimeout.get_sbd_watchdog_timeout') - @patch('crmsh.sbd.SBDUtils.get_sbd_device_from_config') - def test_configure_sbd_diskless(self, mock_get_sbd_device, mock_get_sbd_watchdog_timeout, mock_ServiceManager, mock_set_property): - mock_get_sbd_watchdog_timeout.return_value = 1 - mock_get_sbd_device.return_value = False - sbdmanager_instance = SBDManager() - sbdmanager_instance.configure_sbd() - mock_set_property.assert_has_calls([ - call("stonith-watchdog-timeout", 2), - call("stonith-enabled", "true") - ]) - - @patch('crmsh.utils.delete_property') - @patch('crmsh.utils.get_property') - @patch('crmsh.sbd.sh.cluster_shell') - @patch('crmsh.sbd.xmlutil.CrmMonXmlParser') - @patch('crmsh.utils.set_property') - @patch('crmsh.sbd.ServiceManager') - @patch('crmsh.sbd.SBDUtils.get_sbd_device_from_config') - def test_configure_sbd(self, mock_get_sbd_device, mock_ServiceManager, mock_set_property, mock_CrmMonXmlParser, mock_cluster_shell, mock_get_property, mock_delete_property): - mock_get_sbd_device.return_value = True - mock_get_property.return_value = -1 - mock_CrmMonXmlParser.return_value.is_resource_configured.return_value = False - mock_cluster_shell.return_value.get_stdout_or_raise_error.return_value = "data" - sbdmanager_instance = SBDManager() - sbdmanager_instance.configure_sbd() - mock_cluster_shell.return_value.get_stdout_or_raise_error.assert_called_once_with("crm configure primitive stonith-sbd stonith:fence_sbd") - @patch('crmsh.utils.cluster_run_cmd') @patch('crmsh.sbd.SBDTimeout.is_sbd_delay_start') @patch('crmsh.sbd.ServiceManager') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/test/unittests/test_ui_sbd.py new/crmsh-5.0.0+20260226.8b99a4c5/test/unittests/test_ui_sbd.py --- old/crmsh-5.0.0+20260209.ed56b53c/test/unittests/test_ui_sbd.py 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/test/unittests/test_ui_sbd.py 2026-02-26 10:31:40.000000000 +0100 @@ -239,7 +239,7 @@ res = self.sbd_instance_diskbased._configure_show(["xxx1", "xxx2"]) self.assertEqual(str(e.exception), f"Unknown argument: xxx2") - @mock.patch('crmsh.sbd.SBDTimeoutChecker') + @mock.patch('crmsh.sbd.SBDConfigChecker') def test_configure_show_disk_metadata(self, mock_sbd_timeout_checker): mock_sbd_timeout_checker_instance = mock.Mock() mock_sbd_timeout_checker.return_value = mock_sbd_timeout_checker_instance @@ -250,7 +250,7 @@ mock_sbd_timeout_checker.assert_called_once_with() mock_sbd_timeout_checker_instance.check_and_fix.assert_called_once() - @mock.patch('crmsh.sbd.SBDTimeoutChecker') + @mock.patch('crmsh.sbd.SBDConfigChecker') @mock.patch('crmsh.ui_sbd.SBD._show_sysconfig') def test_configure_show_sysconfig(self, mock_show_sysconfig, mock_sbd_timeout_checker): mock_sbd_timeout_checker_instance = mock.Mock() @@ -261,7 +261,7 @@ mock_sbd_timeout_checker.assert_called_once_with() mock_sbd_timeout_checker_instance.check_and_fix.assert_called_once() - @mock.patch('crmsh.sbd.SBDTimeoutChecker') + @mock.patch('crmsh.sbd.SBDConfigChecker') def test_configure_show_property(self, mock_sbd_timeout_checker): mock_sbd_timeout_checker_instance = mock.Mock() mock_sbd_timeout_checker.return_value = mock_sbd_timeout_checker_instance @@ -285,7 +285,7 @@ self.assertIsNotNone(match) self.assertEqual(match.groups(), expected) - @mock.patch('crmsh.sbd.SBDTimeoutChecker') + @mock.patch('crmsh.sbd.SBDConfigChecker') @mock.patch('crmsh.ui_sbd.SBD._show_sysconfig') @mock.patch('builtins.print') def test_configure_show(self, mock_print, mock_show_sysconfig, mock_sbd_timeout_checker): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20260209.ed56b53c/test_container/Dockerfile new/crmsh-5.0.0+20260226.8b99a4c5/test_container/Dockerfile --- old/crmsh-5.0.0+20260209.ed56b53c/test_container/Dockerfile 2026-02-09 08:58:33.000000000 +0100 +++ new/crmsh-5.0.0+20260226.8b99a4c5/test_container/Dockerfile 2026-02-26 10:31:40.000000000 +0100 @@ -5,7 +5,7 @@ RUN zypper -n dup && zypper -n install systemd openssh \ firewalld iptables iptables-backend-nft \ - make autoconf vim which libxslt-tools asciidoc mailx iproute2 iputils bzip2 tar file glibc-locale-base dos2unix cpio gawk sudo expect diffutils \ + make autoconf vim which libxslt-tools asciidoc mailx iproute2 iputils bzip2 tar file glibc-locale-base cpio gawk sudo expect diffutils \ python313 python313-pip python313-lxml python313-python-dateutil python313-build python313-PyYAML python313-curses python313-behave python313-coverage python313-packaging \ csync2 corosync corosync-qdevice pacemaker pacemaker-remote booth corosync-qnetd
