Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2022-09-21 14:43:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new.2083 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh" Wed Sep 21 14:43:26 2022 rev:259 rq:1005173 version:4.4.1+20220921.dbe833c5 Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2022-09-19 16:03:56.794248104 +0200 +++ /work/SRC/openSUSE:Factory/.crmsh.new.2083/crmsh.changes 2022-09-21 14:44:26.898077367 +0200 @@ -1,0 +2,14 @@ +Wed Sep 21 10:23:36 UTC 2022 - xli...@suse.com + +- Update to version 4.4.1+20220921.dbe833c5: + * Dev: unittest: Adjust unit test based on previous changes + * Dev: bootstrap: Adjust pcmk_delay_max and stonith-timeout for all configured fence agents + +------------------------------------------------------------------- +Mon Sep 19 14:36:59 UTC 2022 - xli...@suse.com + +- Update to version 4.4.1+20220919.2ab5b976: + * Dev: doc: add help info for related:class for 'configure show' command + * Dev: cibconfig: "crm config show related:xxx" provides partial search among class, provider, type fields + +------------------------------------------------------------------- Old: ---- crmsh-4.4.1+20220915.afcd88e6.tar.bz2 New: ---- crmsh-4.4.1+20220921.dbe833c5.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.8m3dbI/_old 2022-09-21 14:44:27.482078892 +0200 +++ /var/tmp/diff_new_pack.8m3dbI/_new 2022-09-21 14:44:27.490078913 +0200 @@ -36,7 +36,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0-or-later Group: %{pkg_group} -Version: 4.4.1+20220915.afcd88e6 +Version: 4.4.1+20220921.dbe833c5 Release: 0 URL: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.8m3dbI/_old 2022-09-21 14:44:27.530079018 +0200 +++ /var/tmp/diff_new_pack.8m3dbI/_new 2022-09-21 14:44:27.534079027 +0200 @@ -9,7 +9,7 @@ </service> <service name="tar_scm"> <param name="url">https://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">46ff3da7a92920e3e0e73d69c73e51a8846fd223</param> + <param name="changesrevision">dbe833c5f8703d6a9990ef199ca0b7aae7255b72</param> </service> </servicedata> (No newline at EOF) ++++++ crmsh-4.4.1+20220915.afcd88e6.tar.bz2 -> crmsh-4.4.1+20220921.dbe833c5.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.4.1+20220915.afcd88e6/crmsh/bootstrap.py new/crmsh-4.4.1+20220921.dbe833c5/crmsh/bootstrap.py --- old/crmsh-4.4.1+20220915.afcd88e6/crmsh/bootstrap.py 2022-09-15 14:33:01.000000000 +0200 +++ new/crmsh-4.4.1+20220921.dbe833c5/crmsh/bootstrap.py 2022-09-21 09:33:20.000000000 +0200 @@ -32,7 +32,7 @@ from . import tmpfiles from . import lock from . import userdir -from .constants import SSH_OPTION, QDEVICE_HELP_INFO, STONITH_TIMEOUT_DEFAULT, REJOIN_COUNT, REJOIN_INTERVAL +from .constants import SSH_OPTION, QDEVICE_HELP_INFO, STONITH_TIMEOUT_DEFAULT, REJOIN_COUNT, REJOIN_INTERVAL, PCMK_DELAY_MAX from . import ocfs2 from . import qdevice from . import parallax @@ -1375,9 +1375,8 @@ qdevice_inst.config_and_start_qdevice() - if _context.stage == "qdevice" and utils.service_is_active("sbd.service"): - from .sbd import SBDTimeout - SBDTimeout.adjust_sbd_timeout_related_cluster_configuration() + if _context.stage == "qdevice": + adjust_pcmk_delay_max_and_stonith_timeout() def init(): @@ -1789,13 +1788,7 @@ # attempt to join the cluster failed) init_cluster_local() - if utils.service_is_active("sbd.service"): - from .sbd import SBDTimeout - SBDTimeout.adjust_sbd_timeout_related_cluster_configuration() - else: - value = get_stonith_timeout_generally_expected() - if value: - utils.set_property_conditionally("stonith-timeout", value) + adjust_pcmk_delay_max_and_stonith_timeout() with logger_utils.status_long("Reloading cluster configuration"): @@ -1902,10 +1895,6 @@ """ Remove node from running cluster and the corosync / pacemaker configuration. """ - if utils.service_is_active("sbd.service"): - from .sbd import SBDTimeout - SBDTimeout.adjust_sbd_timeout_related_cluster_configuration(removing=True) - node = _context.cluster_node set_cluster_node_ip() @@ -1933,6 +1922,8 @@ decrease_expected_votes() + adjust_pcmk_delay_max_and_stonith_timeout() + logger.info("Propagating configuration changes across the remaining nodes") csync2_update(CSYNC2_CFG) csync2_update(corosync.conf()) @@ -2178,9 +2169,7 @@ else: logger.warning("To remove qdevice service, need to restart cluster service manually on each node") - if utils.service_is_active("sbd.service"): - from .sbd import SBDTimeout - SBDTimeout.adjust_sbd_timeout_related_cluster_configuration() + adjust_pcmk_delay_max_and_stonith_timeout() def bootstrap_remove(context): @@ -2417,4 +2406,52 @@ return None return STONITH_TIMEOUT_DEFAULT + corosync.token_and_consensus_timeout() + + +def adjust_pcmk_delay_max(): + """ + For each fence agent, + add parameter pcmk_delay_max when cluster is two-node cluster without qdevice + else remove pcmk_delay_max + """ + cib_factory.refresh() + + if utils.is_2node_cluster_without_qdevice(): + for res in cib_factory.fence_id_list_without_pcmk_delay(): + cmd = "crm resource param {} set pcmk_delay_max {}s".format(res, PCMK_DELAY_MAX) + utils.get_stdout_or_raise_error(cmd) + logger.debug("Add parameter 'pcmk_delay_max={}s' for resource '{}'".format(PCMK_DELAY_MAX, res)) + else: + for res in cib_factory.fence_id_list_with_pcmk_delay(): + cmd = "crm resource param {} delete pcmk_delay_max".format(res) + utils.get_stdout_or_raise_error(cmd) + logger.debug("Delete parameter 'pcmk_delay_max' for resource '{}'".format(res)) + + +def adjust_stonith_timeout(): + """ + Adjust stonith-timeout for sbd and other scenarios + """ + if utils.service_is_active("sbd.service"): + from .sbd import SBDTimeout + SBDTimeout.adjust_sbd_timeout_related_cluster_configuration() + else: + value = get_stonith_timeout_generally_expected() + if value: + utils.set_property_conditionally("stonith-timeout", value) + + +def adjust_pcmk_delay_max_and_stonith_timeout(): + """ + Adjust pcmk_delay_max and stonith-timeout for all configured fence agents + + Call it when: + - node join/remove + - qdevice add/remove + - add sbd via stage + """ + if not utils.service_is_active("pacemaker.service"): + return + adjust_pcmk_delay_max() + adjust_stonith_timeout() # EOF diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.4.1+20220915.afcd88e6/crmsh/cibconfig.py new/crmsh-4.4.1+20220921.dbe833c5/crmsh/cibconfig.py --- old/crmsh-4.4.1+20220915.afcd88e6/crmsh/cibconfig.py 2022-09-15 14:33:01.000000000 +0200 +++ new/crmsh-4.4.1+20220921.dbe833c5/crmsh/cibconfig.py 2022-09-21 09:33:20.000000000 +0200 @@ -2890,6 +2890,32 @@ "List of primitives ids (for group completion)." return [x.obj_id for x in self.cib_objects if x.obj_type == "primitive"] + def fence_id_list(self): + """ + List all configured fence agent's id + """ + return [x.obj_id for x in self.cib_objects if x.node.get('class') == "stonith"] + + def fence_id_list_with_pcmk_delay(self): + """ + List all fence agent's id which configured pcmk_delay_max + """ + id_list = [] + for x in self.cib_objects: + if x.node.get("class") != "stonith": + continue + for c in x.node.xpath('.//nvpair'): + if c.get("name") == "pcmk_delay_max" and int(c.get("value").strip('s')) > 0: + id_list.append(x.obj_id) + break + return id_list + + def fence_id_list_without_pcmk_delay(self): + """ + List all fence agent's id which not configured pcmk_delay_max + """ + return [_id for _id in self.fence_id_list() if _id not in self.fence_id_list_with_pcmk_delay()] + def children_id_list(self): "List of child ids (for clone/master completion)." return [x.obj_id for x in self.cib_objects if x.obj_type in constants.children_tags] @@ -3135,30 +3161,37 @@ return [x for x in self.cib_objects if x.updated or x.origin == "user"] - def get_elems_on_ra_type(self, spec): + def get_elems_of_ra_partial_search(self, spec): """ - Get elements by given ra class:provider:type or class:type or only type + Get elements by given ra class:provider:type or class:type or only class/provider/type return [] if no results """ + def match_type(obj, tp): + type_res = obj.node.get("type") + return type_res and tp.lower() in type_res.lower() + content_list = spec.split(':')[1:] if len(content_list) > 3: return [] if len(content_list) == 3: cls, provider, tp = content_list return [x for x in self.cib_objects - if x.node.get("type") == tp + if match_type(x, tp) and x.node.get("provider") == provider and x.node.get("class") == cls] if len(content_list) == 2: cls, tp = content_list return [x for x in self.cib_objects - if x.node.get("type") == tp + if match_type(x, tp) and x.node.get("class") == cls] if len(content_list) == 1: tp = content_list[0] if not tp: return [] - return [x for x in self.cib_objects if x.node.get("type") == tp] + return [x for x in self.cib_objects + if match_type(x, tp) or + x.node.get("class") == tp or + x.node.get("provider") == tp] def get_elems_on_type(self, spec): if not spec.startswith("type:"): @@ -3223,7 +3256,7 @@ obj = self.find_object(name) if obj is not None: obj_set |= orderedset.oset(self.related_elements(obj)) - obj_set |= orderedset.oset(self.get_elems_on_ra_type(spec)) + obj_set |= orderedset.oset(self.get_elems_of_ra_partial_search(spec)) else: objs = self.find_objects(spec) or [] for obj in objs: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.4.1+20220915.afcd88e6/crmsh/sbd.py new/crmsh-4.4.1+20220921.dbe833c5/crmsh/sbd.py --- old/crmsh-4.4.1+20220915.afcd88e6/crmsh/sbd.py 2022-09-15 14:33:01.000000000 +0200 +++ new/crmsh-4.4.1+20220921.dbe833c5/crmsh/sbd.py 2022-09-21 09:33:20.000000000 +0200 @@ -24,7 +24,7 @@ SBD_WATCHDOG_TIMEOUT_DEFAULT_WITH_QDEVICE = 35 QDEVICE_SYNC_TIMEOUT_MARGIN = 5 - def __init__(self, context=None, removing=False): + def __init__(self, context=None): """ Init function """ @@ -34,7 +34,6 @@ self.sbd_watchdog_timeout = self.SBD_WATCHDOG_TIMEOUT_DEFAULT self.stonith_watchdog_timeout = self.STONITH_WATCHDOG_TIMEOUT_DEFAULT self.sbd_delay_start = None - self.removing = removing self.two_node_without_qdevice = False def initialize_timeout(self): @@ -123,7 +122,7 @@ """ Load necessary configurations for both disk-based/disk-less sbd """ - self.two_node_without_qdevice = utils.is_2node_cluster_without_qdevice(self.removing) + self.two_node_without_qdevice = utils.is_2node_cluster_without_qdevice() dev_list = SBDManager.get_sbd_device_from_config() if dev_list: # disk-based @@ -222,21 +221,6 @@ """ utils.set_property_conditionally("stonith-timeout", self.get_stonith_timeout_expected()) - def adjust_pcmk_delay_max(self): - """ - Adjust pcmk_delay_max parameter for sbd ra - """ - # TODO this function should be outside of sbd.py, to adjust any fence device - - if not xmlutil.CrmMonXmlParser.is_resource_configured(SBDManager.SBD_RA): - return - - if self.two_node_without_qdevice: - cmd = "crm resource param {} set pcmk_delay_max {}s".format(SBDManager.SBD_RA_ID, self.pcmk_delay_max) - else: - cmd = "crm resource param {} delete pcmk_delay_max".format(SBDManager.SBD_RA_ID) - utils.get_stdout_or_raise_error(cmd) - def adjust_sbd_delay_start(self): """ Adjust SBD_DELAY_START in /etc/sysconfig/sbd @@ -251,17 +235,16 @@ SBDManager.update_configuration({"SBD_DELAY_START": expected_value}) @classmethod - def adjust_sbd_timeout_related_cluster_configuration(cls, removing=False): + def adjust_sbd_timeout_related_cluster_configuration(cls): """ Adjust sbd timeout related configurations """ - cls_inst = cls(removing=removing) + cls_inst = cls() cls_inst._load_configurations() message = "Adjusting sbd related timeout values" with logger_utils.status_long(message): cls_inst.adjust_sbd_delay_start() - cls_inst.adjust_pcmk_delay_max() cls_inst.adjust_stonith_timeout() cls_inst.adjust_systemd_start_timeout() @@ -537,7 +520,7 @@ # in sbd stage if self._context.cluster_is_running: - SBDTimeout.adjust_sbd_timeout_related_cluster_configuration() + bootstrap.adjust_pcmk_delay_max_and_stonith_timeout() def join_sbd(self, peer_host): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.4.1+20220915.afcd88e6/crmsh/utils.py new/crmsh-4.4.1+20220921.dbe833c5/crmsh/utils.py --- old/crmsh-4.4.1+20220915.afcd88e6/crmsh/utils.py 2022-09-15 14:33:01.000000000 +0200 +++ new/crmsh-4.4.1+20220921.dbe833c5/crmsh/utils.py 2022-09-21 09:33:20.000000000 +0200 @@ -2980,14 +2980,13 @@ raise ValueError("Failed to get quorate status from corosync-quorumtool") -def is_2node_cluster_without_qdevice(removing=False): +def is_2node_cluster_without_qdevice(): """ Check if current cluster has two nodes without qdevice """ current_num = len(list_cluster_nodes()) - remove_num = 1 if removing else 0 qdevice_num = 1 if is_qdevice_configured() else 0 - return (current_num - remove_num + qdevice_num) == 2 + return (current_num + qdevice_num) == 2 def get_pcmk_delay_max(two_node_without_qdevice=False): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.4.1+20220915.afcd88e6/doc/crm.8.adoc new/crmsh-4.4.1+20220921.dbe833c5/doc/crm.8.adoc --- old/crmsh-4.4.1+20220915.afcd88e6/doc/crm.8.adoc 2022-09-15 14:33:01.000000000 +0200 +++ new/crmsh-4.4.1+20220921.dbe833c5/doc/crm.8.adoc 2022-09-21 09:33:20.000000000 +0200 @@ -3913,7 +3913,14 @@ show xml tag:db tag:fs show related:webapp show related:IPaddr2 +show related:ipad show related:ocf:heartbeat:Dummy +show related:ocf:heartbeat:dum +show related:ocf +show related:heartbeat +show related:pacemaker +show related:suse +show related:stonith show type:primitive obscure:passwd ............... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.4.1+20220915.afcd88e6/test/unittests/test_bootstrap.py new/crmsh-4.4.1+20220921.dbe833c5/test/unittests/test_bootstrap.py --- old/crmsh-4.4.1+20220915.afcd88e6/test/unittests/test_bootstrap.py 2022-09-15 14:33:01.000000000 +0200 +++ new/crmsh-4.4.1+20220921.dbe833c5/test/unittests/test_bootstrap.py 2022-09-21 09:33:20.000000000 +0200 @@ -1005,6 +1005,63 @@ mock_isfile.assert_has_calls([mock.call("file1"), mock.call("file2")]) mock_cluster_cmd.assert_called_once_with("sync file1 file2") + @mock.patch('logging.Logger.debug') + @mock.patch('crmsh.utils.get_stdout_or_raise_error') + @mock.patch('crmsh.utils.is_2node_cluster_without_qdevice') + @mock.patch('crmsh.bootstrap.cib_factory') + def test_adjust_pcmk_delay_2node(self, mock_cib_factory, mock_2node, mock_run, mock_debug): + mock_cib_factory.refresh = mock.Mock() + mock_cib_factory.fence_id_list_without_pcmk_delay = mock.Mock() + mock_cib_factory.fence_id_list_without_pcmk_delay.return_value = ["res_1"] + mock_2node.return_value = True + bootstrap.adjust_pcmk_delay_max() + mock_run.assert_called_once_with("crm resource param res_1 set pcmk_delay_max {}s".format(constants.PCMK_DELAY_MAX)) + + @mock.patch('logging.Logger.debug') + @mock.patch('crmsh.utils.get_stdout_or_raise_error') + @mock.patch('crmsh.utils.is_2node_cluster_without_qdevice') + @mock.patch('crmsh.bootstrap.cib_factory') + def test_adjust_pcmk_delay(self, mock_cib_factory, mock_2node, mock_run, mock_debug): + mock_cib_factory.refresh = mock.Mock() + mock_cib_factory.fence_id_list_with_pcmk_delay = mock.Mock() + mock_cib_factory.fence_id_list_with_pcmk_delay.return_value = ["res_1"] + mock_2node.return_value = False + bootstrap.adjust_pcmk_delay_max() + mock_run.assert_called_once_with("crm resource param res_1 delete pcmk_delay_max") + + @mock.patch('crmsh.sbd.SBDTimeout') + @mock.patch('crmsh.utils.service_is_active') + def test_adjust_stonith_timeout_sbd(self, mock_is_active, mock_sbd_timeout): + mock_is_active.return_value = True + mock_sbd_timeout.adjust_sbd_timeout_related_cluster_configuration = mock.Mock() + bootstrap.adjust_stonith_timeout() + mock_sbd_timeout.adjust_sbd_timeout_related_cluster_configuration.assert_called_once_with() + + @mock.patch('crmsh.utils.set_property_conditionally') + @mock.patch('crmsh.bootstrap.get_stonith_timeout_generally_expected') + @mock.patch('crmsh.utils.service_is_active') + def test_adjust_stonith_timeout(self, mock_is_active, mock_get_timeout, mock_set): + mock_is_active.return_value = False + mock_get_timeout.return_value = 30 + bootstrap.adjust_stonith_timeout() + mock_set.assert_called_once_with("stonith-timeout", 30) + + @mock.patch('crmsh.utils.service_is_active') + def test_adjust_pcmk_delay_and_stonith_timeout_return(self, mock_is_active): + mock_is_active.return_value = False + bootstrap.adjust_pcmk_delay_max_and_stonith_timeout() + mock_is_active.assert_called_once_with("pacemaker.service") + + @mock.patch('crmsh.bootstrap.adjust_stonith_timeout') + @mock.patch('crmsh.bootstrap.adjust_pcmk_delay_max') + @mock.patch('crmsh.utils.service_is_active') + def test_adjust_pcmk_delay_and_stonith_timeout(self, mock_is_active, mock_adjust_pcmk_delay, mock_adjust_timeout): + mock_is_active.return_value = True + bootstrap.adjust_pcmk_delay_max_and_stonith_timeout() + mock_is_active.assert_called_once_with("pacemaker.service") + mock_adjust_pcmk_delay.assert_called_once_with() + mock_adjust_timeout.assert_called_once_with() + class TestValidation(unittest.TestCase): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.4.1+20220915.afcd88e6/test/unittests/test_sbd.py new/crmsh-4.4.1+20220921.dbe833c5/test/unittests/test_sbd.py --- old/crmsh-4.4.1+20220915.afcd88e6/test/unittests/test_sbd.py 2022-09-15 14:33:01.000000000 +0200 +++ new/crmsh-4.4.1+20220921.dbe833c5/test/unittests/test_sbd.py 2022-09-21 09:33:20.000000000 +0200 @@ -29,7 +29,6 @@ _dict = {"sbd.watchdog_timeout": 5, "sbd.msgwait": 10} _inst_q = mock.Mock() self.sbd_timeout_inst = sbd.SBDTimeout(mock.Mock(profiles_dict=_dict, is_s390=True, qdevice_inst=_inst_q)) - self.sbd_timeout_inst_removing = sbd.SBDTimeout(mock.Mock(), True) def tearDown(self): """ @@ -150,7 +149,7 @@ self.sbd_timeout_inst._load_configurations() - mock_2node.assert_called_once_with(False) + mock_2node.assert_called_once_with() mock_get_sbd_dev.assert_called_once_with() mock_get_msgwait.assert_called_once_with("/dev/sda1") mock_pcmk_delay.assert_called_once_with(True) @@ -173,7 +172,7 @@ self.sbd_timeout_inst._load_configurations() - mock_2node.assert_called_once_with(False) + mock_2node.assert_called_once_with() mock_get_sbd_dev.assert_called_once_with() mock_get_watchdog_timeout.assert_called_once_with() mock_get_stonith_watchdog_timeout.assert_called_once_with()