Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package crmsh for openSUSE:Factory checked 
in at 2021-08-11 11:47:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/crmsh (Old)
 and      /work/SRC/openSUSE:Factory/.crmsh.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "crmsh"

Wed Aug 11 11:47:42 2021 rev:219 rq:911376 version:4.3.1+20210811.4045e09d

Changes:
--------
--- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes      2021-07-26 
17:38:26.854068799 +0200
+++ /work/SRC/openSUSE:Factory/.crmsh.new.1899/crmsh.changes    2021-08-11 
11:49:35.313575358 +0200
@@ -1,0 +2,23 @@
+Wed Aug 11 07:15:15 UTC 2021 - xli...@suse.com
+
+- Update to version 4.3.1+20210811.4045e09d:
+  * Dev: unittest: Add unit test for previous changes
+  * Fix: bootstrap: Adjust corosync and sbd parameters according to the 
profile environment detected (bsc#1175896)
+  * Fix: sbd: adjust sbd systemd TimeoutStartSec together with SBD_DELAY_START
+  * Dev: Makefile: add etc/profiles.yml and move crm.conf.in into etc
+
+-------------------------------------------------------------------
+Thu Aug 05 08:37:03 UTC 2021 - xli...@suse.com
+
+- Update to version 4.3.1+20210805.18f9a8c1:
+  * Fix: doc: Note that resource tracing is only supported by OCF 
RAs(bsc#1188966)
+  * Dev: testcases: adjust expected output for previous changes
+  * Dev: ui_resource: Enhancement trace output
+
+-------------------------------------------------------------------
+Wed Jul 28 06:14:24 UTC 2021 - xli...@suse.com
+
+- Update to version 4.3.1+20210728.8029db25:
+  * Medium: ra: performance/usability improvement (avoid systemd)
+
+-------------------------------------------------------------------

Old:
----
  crmsh-4.3.1+20210726.3de6f304.tar.bz2

New:
----
  crmsh-4.3.1+20210811.4045e09d.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ crmsh.spec ++++++
--- /var/tmp/diff_new_pack.liSsWr/_old  2021-08-11 11:49:35.749574834 +0200
+++ /var/tmp/diff_new_pack.liSsWr/_new  2021-08-11 11:49:35.753574829 +0200
@@ -36,7 +36,7 @@
 Summary:        High Availability cluster command-line interface
 License:        GPL-2.0-or-later
 Group:          %{pkg_group}
-Version:        4.3.1+20210726.3de6f304
+Version:        4.3.1+20210811.4045e09d
 Release:        0
 URL:            http://crmsh.github.io
 Source0:        %{name}-%{version}.tar.bz2

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.liSsWr/_old  2021-08-11 11:49:35.781574795 +0200
+++ /var/tmp/diff_new_pack.liSsWr/_new  2021-08-11 11:49:35.785574791 +0200
@@ -9,6 +9,6 @@
 </service>
 <service name="tar_scm">
   <param name="url">https://github.com/ClusterLabs/crmsh.git</param>
-  <param 
name="changesrevision">27fd7dc2f00797a9593d6b672005c0590d13836e</param>
+  <param 
name="changesrevision">4045e09d6208e04923342b8ede1520aca88eda7d</param>
 </service>
 </servicedata>
\ No newline at end of file

++++++ crmsh-4.3.1+20210726.3de6f304.tar.bz2 -> 
crmsh-4.3.1+20210811.4045e09d.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/Makefile.am 
new/crmsh-4.3.1+20210811.4045e09d/Makefile.am
--- old/crmsh-4.3.1+20210726.3de6f304/Makefile.am       2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/Makefile.am       2021-08-11 
09:00:07.000000000 +0200
@@ -25,7 +25,7 @@
 # Documentation
 doc_DATA = AUTHORS COPYING README.md ChangeLog $(generated_docs)
 crmconfdir=$(sysconfdir)/crm
-crmconf_DATA = crm.conf
+crmconf_DATA = etc/crm.conf etc/profiles.yml
 contribdir      = $(docdir)/contrib
 contrib_DATA   = contrib/pcmk.vim  contrib/README.vimsyntax
 helpdir     = $(datadir)/$(PACKAGE)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/configure.ac 
new/crmsh-4.3.1+20210811.4045e09d/configure.ac
--- old/crmsh-4.3.1+20210726.3de6f304/configure.ac      2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/configure.ac      2021-08-11 
09:00:07.000000000 +0200
@@ -55,7 +55,7 @@
 
 AC_CONFIG_FILES(Makefile \
 hb_report/hb_report      \
-crm.conf                 \
+etc/crm.conf             \
 version                  \
 crmsh.spec               \
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/crm.conf.in 
new/crmsh-4.3.1+20210811.4045e09d/crm.conf.in
--- old/crmsh-4.3.1+20210726.3de6f304/crm.conf.in       2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/crm.conf.in       1970-01-01 
01:00:00.000000000 +0100
@@ -1,117 +0,0 @@
-; crmsh configuration file
-; To override per user, create a file ~/.config/crm/crm.conf
-;
-; [core]
-; editor = $EDITOR
-; pager = $PAGER
-; user =
-; skill_level = expert
-; sort_elements = yes
-; check_frequency = always
-; check_mode = strict
-; wait = no
-; add_quotes = yes
-; manage_children = ask
-; force = no
-; debug = no
-; ptest = ptest, crm_simulate
-; dotty = dotty
-; dot = dot
-; ignore_missing_metadata = no
-; report_tool_options =
-; lock_timeout = 120
-
-; obscure_pattern option is the persisent configuration of CLI.
-; Example, for the high security concern, obscure_pattern = passw* | ip
-; which makes `crm configure show` is equal to
-;
-; node-1:~ # crm configure show obscure:passw* obscure:ip
-; node 1084783297: node1
-; primitive fence_device stonith:fence_ilo5 \
-;         params password="******"
-; primitive ip IPaddr2 \
-;         params ip="******"
-;
-; The default option is passw*
-; If you don't want to obscure, change the value to blank.
-;
-; obscure_pattern = passw*
-
-[path]
-; sharedir = <detected>
-; cache = <detected>
-; crm_config = <detected>
-; crm_daemon_dir = <detected>
-crm_daemon_user = @CRM_DAEMON_USER@
-ocf_root = @OCF_ROOT_DIR@
-; crm_dtd_dir = <detected>
-; pe_state_dir = <detected>
-; heartbeat_dir = <detected>
-; hb_delnode = /usr/share/heartbeat/hb_delnode
-; nagios_plugins = /usr/lib/nagios/plugins
-
-; [color]
-; style = color
-; error = red bold
-; ok = green bold
-; warn = yellow bold
-; info = cyan
-; help_keyword = blue bold underline
-; help_header = normal bold
-; help_topic = yellow bold
-; help_block = cyan
-; keyword = yellow
-; identifier = normal
-; attr_name = cyan
-; attr_value = red
-; resource_reference = green
-; id_reference = green
-; score = magenta
-; ticket = magenta
-
-; [report]
-; from_time = -12H
-; compress = yes
-; speed_up = no
-; collect_extra_logs = /var/log/messages /var/log/pacemaker.log
-; remove_exist_dest = no
-; single_node = no
-;
-;   sanitize_rule = sanitize_pattern[:options] ...
-;
-; This defines the way to hide sensitive data generated by hb_report.
-;
-; 'sanitize_pattern' is a RegEx string, which is used to matches 'name'
-; field of CIB params. The sanitize process will hide 'value' of those
-; matched 'name:value' pairs in CIB, PE, pacemaker.log.
-;
-; 'options' is the predefined, and 'raw' is the only one defined
-; currently. With ':raw" option, the sanitize process will fetch
-; 'value' results out of CIB 'name:value' pairs, and use them to
-; hide all clear text occurence from all files hb_report collected.
-;
-; Example 1:
-;   sanitize_rule = passw.*
-;
-; This is the default. It will hide password nam:value pairs.
-; The result of hb_report clould be like
-;     name="password", value=******
-;     @name=password @value=******
-;     passwd=******
-;
-;
-; Example 2:
-;   sanitize_rule = ip.*:raw
-;
-; This will only hide ip addresses. Example, the sanitize process will fetch
-; ip=10.10.10.10 and replace all clear text occurrence of "10.10.10.10"
-;
-;
-; Example 3:
-;   sanitize_rule = passw.*|ip.*:raw
-;
-; This is useful for the higher security concern.
-; The sanitize process will hide all "name:value" pair for password like in
-; example 1, and all clear text ip addresses like in example 2 above.
-;
-; sanitize_rule = passw.*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/crmsh/bootstrap.py 
new/crmsh-4.3.1+20210811.4045e09d/crmsh/bootstrap.py
--- old/crmsh-4.3.1+20210726.3de6f304/crmsh/bootstrap.py        2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/crmsh/bootstrap.py        2021-08-11 
09:00:07.000000000 +0200
@@ -19,6 +19,7 @@
 import time
 import readline
 import shutil
+import yaml
 from string import Template
 from lxml import etree
 from pathlib import Path
@@ -75,6 +76,10 @@
     Context object used to avoid having to pass these variables
     to every bootstrap method.
     """
+    PROFILES_FILE = "/etc/crm/profiles.yml"
+    DEFAULT_PROFILE_NAME = "default"
+    S390_PROFILE_NAME = "s390"
+
     def __init__(self):
         '''
         Initialize attributes
@@ -118,6 +123,10 @@
         self.interfaces_inst = None
         self.with_other_user = True
         self.cluster_is_running = None
+        self.cloud_type = None
+        self.is_s390 = False
+        self.profiles_data = None
+        self.profiles_dict = {}
         self.default_nic_list = []
         self.default_ip_list = []
         self.local_ip_list = []
@@ -186,6 +195,59 @@
         from .sbd import SBDManager
         self.sbd_manager = SBDManager(self)
 
+    def detect_platform(self):
+        """
+        Detect platform
+        Return profile type for different platform
+        """
+        profile_type = None
+
+        self.is_s390 = "390" in os.uname().machine
+        if self.is_s390:
+            profile_type = self.S390_PROFILE_NAME
+        else:
+            self.cloud_type = utils.detect_cloud()
+            if self.cloud_type:
+                profile_type = self.cloud_type
+
+        if profile_type:
+            status("Detected \"{}\" platform".format(profile_type))
+        return profile_type
+
+    def load_specific_profile(self, profile_type):
+        """
+        Load specific profile
+        """
+        profile_dict = {}
+        if not profile_type:
+            return profile_dict
+
+        if profile_type in self.profiles_data:
+            status("Loading \"{}\" profile from {}".format(profile_type, 
self.PROFILES_FILE))
+            profile_dict = self.profiles_data[profile_type]
+        else:
+            status("\"{}\" profile does not exist in {}".format(profile_type, 
self.PROFILES_FILE))
+        return profile_dict
+
+    def load_profiles(self):
+        """
+        Load profiles data for different environment
+        """
+        profile_type = self.detect_platform()
+
+        if not os.path.exists(self.PROFILES_FILE):
+            return
+        with open(self.PROFILES_FILE) as f:
+            self.profiles_data = yaml.load(f, Loader=yaml.SafeLoader)
+        # empty file
+        if not self.profiles_data:
+            return
+
+        default_profile_dict = 
self.load_specific_profile(self.DEFAULT_PROFILE_NAME)
+        specific_profile_dict = self.load_specific_profile(profile_type)
+        # merge two dictionaries
+        self.profiles_dict = {**default_profile_dict, **specific_profile_dict}
+
 
 _context = None
 
@@ -435,8 +497,9 @@
 @contextmanager
 def status_long(msg):
     log("# {}...".format(msg))
-    if not _context.quiet:
-        sys.stdout.write("  {}...".format(msg))
+    if not _context or not _context.quiet:
+        space = "  " if _context else ""
+        sys.stdout.write("{}{}...".format(space, msg))
         sys.stdout.flush()
     try:
         yield
@@ -447,14 +510,14 @@
 
 
 def status_progress():
-    if not _context.quiet:
+    if not _context or not _context.quiet:
         sys.stdout.write(".")
         sys.stdout.flush()
 
 
 def status_done():
     log("# done")
-    if not _context.quiet:
+    if not _context or not _context.quiet:
         print("done")
 
 
@@ -696,10 +759,24 @@
     if pass_msg:
         warn("You should change the hacluster password to something more 
secure!")
 
-    utils.start_service("pacemaker.service", enable=True)
+    start_pacemaker()
     wait_for_cluster()
 
 
+def start_pacemaker():
+    """
+    Start pacemaker service with wait time for sbd
+    """
+    from .sbd import SBDManager
+    pacemaker_start_msg = "Starting pacemaker"
+    if utils.package_is_installed("sbd") and \
+            utils.service_is_enabled("sbd.service") and \
+            SBDManager.is_delay_start():
+        pacemaker_start_msg += "(waiting for sbd 
{}s)".format(SBDManager.get_suitable_sbd_systemd_timeout())
+    with status_long(pacemaker_start_msg):
+        utils.start_service("pacemaker.service", enable=True)
+
+
 def install_tmp(tmpfile, to):
     with open(tmpfile, "r") as src:
         with utils.open_atomic(to, "w") as dst:
@@ -1164,26 +1241,32 @@
     csync2_update(corosync.conf())
 
 
+def adjust_corosync_parameters_according_to_profiles():
+    """
+    Adjust corosync's parameters according profiles
+    """
+    if not _context.profiles_dict:
+        return
+    for k, v in _context.profiles_dict.items():
+        if k.startswith("corosync."):
+            corosync.set_value('.'.join(k.split('.')[1:]), v)
+
+
 def init_corosync():
     """
     Configure corosync (unicast or multicast, encrypted?)
     """
-    def requires_unicast():
-        host = utils.detect_cloud()
-        if host is not None:
-            status("Detected cloud platform: {}".format(host))
-        return host is not None
-
     init_corosync_auth()
 
     if os.path.exists(corosync.conf()):
         if not confirm("%s already exists - overwrite?" % (corosync.conf())):
             return
 
-    if _context.unicast or requires_unicast():
+    if _context.unicast or _context.cloud_type:
         init_corosync_unicast()
     else:
         init_corosync_multicast()
+    adjust_corosync_parameters_according_to_profiles()
 
 
 def init_sbd():
@@ -2016,6 +2099,7 @@
 
     _context.initialize_qdevice()
     _context.validate_option()
+    _context.load_profiles()
     _context.init_sbd_manager()
 
     # Need hostname resolution to work, want NTP (but don't block ssh_remote 
or csync2_remote)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/crmsh/corosync.py 
new/crmsh-4.3.1+20210811.4045e09d/crmsh/corosync.py
--- old/crmsh-4.3.1+20210726.3de6f304/crmsh/corosync.py 2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/crmsh/corosync.py 2021-08-11 
09:00:07.000000000 +0200
@@ -608,17 +608,8 @@
 
 totem {
     version:    2
-    secauth:    on
-    crypto_hash:    sha1
-    crypto_cipher:  aes256
     cluster_name:   %(clustername)s
     clear_node_high_bit: yes
-
-    token:      5000
-    token_retransmits_before_loss_const: 10
-    join:       60
-    consensus:  6000
-    max_messages:   20
 """
 _COROSYNC_CONF_TEMPLATE_TAIL = """
     %(rrp_mode)s
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/crmsh/ra.py 
new/crmsh-4.3.1+20210811.4045e09d/crmsh/ra.py
--- old/crmsh-4.3.1+20210726.3de6f304/crmsh/ra.py       2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/crmsh/ra.py       2021-08-11 
09:00:07.000000000 +0200
@@ -65,7 +65,7 @@
 
 @utils.memoize
 def can_use_crm_resource():
-    _rc, s = get_stdout("crm_resource --list-standards", stderr_on=False)
+    _rc, s = get_stdout("crm_resource --list-ocf-providers", stderr_on=False)
     return s != ""
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/crmsh/sbd.py 
new/crmsh-4.3.1+20210811.4045e09d/crmsh/sbd.py
--- old/crmsh-4.3.1+20210726.3de6f304/crmsh/sbd.py      2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/crmsh/sbd.py      2021-08-11 
09:00:07.000000000 +0200
@@ -4,7 +4,6 @@
 from . import utils
 from . import bootstrap
 from .bootstrap import SYSCONFIG_SBD
-from .constants import SSH_OPTION
 
 
 class SBDManager(object):
@@ -27,9 +26,10 @@
 If you want to use diskless SBD for two-nodes cluster, should be combined with 
QDevice."""
     PARSE_RE = "[; ]"
     DISKLESS_CRM_CMD = "crm configure property stonith-enabled=true 
stonith-watchdog-timeout={} stonith-timeout={}"
+
+    SBD_WATCHDOG_TIMEOUT_DEFAULT = 5
+    SBD_WATCHDOG_TIMEOUT_DEFAULT_S390 = 15
     SBD_WATCHDOG_TIMEOUT_DEFAULT_WITH_QDEVICE = 35
-    STONITH_WATCHDOG_TIMEOUT_DEFAULT = "10s"
-    STONITH_WATCHDOG_TIMEOUT_DEFAULT_S390 = "30s"
 
     def __init__(self, context):
         """
@@ -42,29 +42,37 @@
         self.diskless_sbd = context.diskless_sbd
         self._sbd_devices = None
         self._watchdog_inst = None
-        self._stonith_watchdog_timeout = self.STONITH_WATCHDOG_TIMEOUT_DEFAULT
         self._stonith_timeout = 60
-        self._sbd_watchdog_timeout = 0
-        self._is_s390 = "390" in os.uname().machine
+        if context.is_s390:
+            self._sbd_watchdog_timeout = self.SBD_WATCHDOG_TIMEOUT_DEFAULT_S390
+        else:
+            self._sbd_watchdog_timeout = self.SBD_WATCHDOG_TIMEOUT_DEFAULT
+        self._stonith_watchdog_timeout = -1
         self._context = context
+        self._delay_start = False
 
     @staticmethod
     def _get_device_uuid(dev, node=None):
         """
         Get UUID for specific device and node
         """
-        cmd = "sbd -d {} dump".format(dev)
-        if node:
-            cmd = "ssh {} root@{} '{}'".format(SSH_OPTION, node, cmd)
-
-        rc, out, err = utils.get_stdout_stderr(cmd)
-        if rc != 0 and err:
-            raise ValueError("Cannot dump sbd meta-data: {}".format(err))
-        if rc == 0 and out:
-            res = re.search("UUID\s*:\s*(.*)\n", out)
-            if not res:
-                raise ValueError("Cannot find sbd device UUID for 
{}".format(dev))
-            return res.group(1)
+        out = utils.get_stdout_or_raise_error("sbd -d {} dump".format(dev), 
remote=node)
+        res = re.search("UUID\s*:\s*(.*)\n", out)
+        if not res:
+            raise ValueError("Cannot find sbd device UUID for {}".format(dev))
+        return res.group(1)
+
+    @staticmethod
+    def _get_sbd_msgwait(dev):
+        """
+        Get msgwait for sbd device
+        """
+        out = utils.get_stdout_or_raise_error("sbd -d {} dump".format(dev))
+        # Format like "Timeout (msgwait)  : 30"
+        res = re.search("\(msgwait\)\s+:\s+(\d+)", out)
+        if not res:
+            raise ValueError("Cannot get sbd msgwait for {}".format(dev))
+        return int(res.group(1))
 
     def _compare_device_uuid(self, dev, node_list):
         """
@@ -144,27 +152,53 @@
             dev_list = self._get_sbd_device_interactive()
         self._sbd_devices = dev_list
 
-    def _initialize_sbd(self):
+    def _adjust_sbd_watchdog_timeout_for_s390(self):
         """
-        Initialize SBD device
+        Correct watchdog timeout if less than s390 default
         """
+        if self._context.is_s390 and self._sbd_watchdog_timeout < 
self.SBD_WATCHDOG_TIMEOUT_DEFAULT_S390:
+            bootstrap.warn("sbd_watchdog_timeout is set to {} for s390, it was 
{}".format(self.SBD_WATCHDOG_TIMEOUT_DEFAULT_S390, self._sbd_watchdog_timeout))
+            self._sbd_watchdog_timeout = self.SBD_WATCHDOG_TIMEOUT_DEFAULT_S390
+
+    def _initialize_sbd(self):
+        """
+        Initialize SBD parameters according to profiles.yml, or the crmsh 
defined defaulst as the last resort.
+        This covers both disk-based-sbd, and diskless-sbd scenarios.
+        For diskless-sbd, set _sbd_watchdog_timeout then return;
+        For disk-based-sbd, also calculate the msgwait value, then initialize 
the SBD device.
+        """
+        if "sbd.watchdog_timeout" in self._context.profiles_dict:
+            self._sbd_watchdog_timeout = 
self._context.profiles_dict["sbd.watchdog_timeout"]
+            self._adjust_sbd_watchdog_timeout_for_s390()
         if self.diskless_sbd:
             return
+
+        sbd_msgwait_default = int(self._sbd_watchdog_timeout) * 2
+        sbd_msgwait = sbd_msgwait_default
+        if "sbd.msgwait" in self._context.profiles_dict:
+            sbd_msgwait = self._context.profiles_dict["sbd.msgwait"]
+            if int(sbd_msgwait) < sbd_msgwait_default:
+                bootstrap.warn("sbd msgwait is set to {}, it was 
{}".format(sbd_msgwait_default, sbd_msgwait))
+                sbd_msgwait = sbd_msgwait_default
+        opt = "-4 {} -1 {}".format(sbd_msgwait, self._sbd_watchdog_timeout)
+
         for dev in self._sbd_devices:
-            rc, _, err = bootstrap.invoke("sbd -d {} create".format(dev))
+            rc, _, err = bootstrap.invoke("sbd {} -d {} create".format(opt, 
dev))
             if not rc:
                 bootstrap.error("Failed to initialize SBD device {}: 
{}".format(dev, err))
 
-    def _update_configuration(self):
+    def _update_sbd_configuration(self):
         """
         Update /etc/sysconfig/sbd
         """
         shutil.copyfile(self.SYSCONFIG_SBD_TEMPLATE, SYSCONFIG_SBD)
-        self._determine_sbd_watchdog_timeout()
+        self._adjust_sbd_watchdog_timeout_with_diskless_and_qdevice()
+        if utils.detect_virt():
+            self._delay_start = True
         sbd_config_dict = {
                 "SBD_PACEMAKER": "yes",
                 "SBD_STARTMODE": "always",
-                "SBD_DELAY_START": "yes" if utils.detect_virt() and 
self._sbd_devices else "no",
+                "SBD_DELAY_START": "yes" if self._delay_start else "no",
                 "SBD_WATCHDOG_DEV": self._watchdog_inst.watchdog_device_name
                 }
         if self._sbd_watchdog_timeout > 0:
@@ -174,34 +208,27 @@
         utils.sysconfig_set(SYSCONFIG_SBD, **sbd_config_dict)
         bootstrap.csync2_update(SYSCONFIG_SBD)
 
-    def _determine_sbd_watchdog_timeout(self):
+    def _adjust_sbd_watchdog_timeout_with_diskless_and_qdevice(self):
         """
-        When using diskless SBD, determine value of SBD_WATCHDOG_TIMEOUT
+        When using diskless SBD with Qdevice, adjust value of 
sbd_watchdog_timeout
         """
         if not self.diskless_sbd:
             return
         # add sbd after qdevice started
         if utils.is_qdevice_configured() and 
utils.service_is_active("corosync-qdevice.service"):
             qdevice_sync_timeout = utils.get_qdevice_sync_timeout()
-            self._sbd_watchdog_timeout = qdevice_sync_timeout + 5
-            if self._is_s390 and self._sbd_watchdog_timeout < 15:
-                self._sbd_watchdog_timeout = 15
+            if self._sbd_watchdog_timeout <= qdevice_sync_timeout:
+                watchdog_timeout_with_qdevice = qdevice_sync_timeout + 5
+                bootstrap.warn("sbd_watchdog_timeout is set to {} for qdevice, 
it was {}".format(watchdog_timeout_with_qdevice, self._sbd_watchdog_timeout))
+                self._sbd_watchdog_timeout = watchdog_timeout_with_qdevice
             self._stonith_timeout = 
self.calculate_stonith_timeout(self._sbd_watchdog_timeout)
         # add sbd and qdevice together from beginning
         elif self._context.qdevice_inst:
-            self._sbd_watchdog_timeout = 
self.SBD_WATCHDOG_TIMEOUT_DEFAULT_WITH_QDEVICE
+            if self._sbd_watchdog_timeout < 
self.SBD_WATCHDOG_TIMEOUT_DEFAULT_WITH_QDEVICE:
+                bootstrap.warn("sbd_watchdog_timeout is set to {} for qdevice, 
it was {}".format(self.SBD_WATCHDOG_TIMEOUT_DEFAULT_WITH_QDEVICE, 
self._sbd_watchdog_timeout))
+                self._sbd_watchdog_timeout = 
self.SBD_WATCHDOG_TIMEOUT_DEFAULT_WITH_QDEVICE
             self._stonith_timeout = 
self.calculate_stonith_timeout(self._sbd_watchdog_timeout)
 
-    def _determine_stonith_watchdog_timeout(self):
-        """
-        Determine value of stonith-watchdog-timeout
-        """
-        res = SBDManager.get_sbd_value_from_config("SBD_WATCHDOG_TIMEOUT")
-        if res:
-            self._stonith_watchdog_timeout = -1
-        elif self._is_s390:
-            self._stonith_watchdog_timeout = 
self.STONITH_WATCHDOG_TIMEOUT_DEFAULT_S390
-
     def _get_sbd_device_from_config(self):
         """
         Gets currently configured SBD device, i.e. what's in /etc/sysconfig/sbd
@@ -212,6 +239,44 @@
         else:
             return None
 
+    @staticmethod
+    def is_delay_start():
+        """
+        Check if SBD_DELAY_START is yes
+        """
+        res = SBDManager.get_sbd_value_from_config("SBD_DELAY_START")
+        return utils.is_boolean_true(res)
+
+    @staticmethod
+    def get_sbd_watchdog_timeout():
+        """
+        Get SBD_WATCHDOG_TIMEOUT from /etc/sysconfig/sbd
+        """
+        res = SBDManager.get_sbd_value_from_config("SBD_WATCHDOG_TIMEOUT")
+        if not res:
+            raise ValueError("Cannot get the value of SBD_WATCHDOG_TIMEOUT")
+        return int(res)
+
+    @staticmethod
+    def get_sbd_start_timeout_threshold():
+        """
+        Get sbd start timeout threshold
+        TimeoutStartUSec of sbd shouldn't less than this value
+        """
+        dev_list = SBDManager.get_sbd_device_from_config()
+        if not dev_list:
+            return int(SBDManager.get_sbd_watchdog_timeout() * 2)
+        else:
+            return int(SBDManager._get_sbd_msgwait(dev_list[0]))
+
+    @staticmethod
+    def get_suitable_sbd_systemd_timeout():
+        """
+        Get suitable systemd start timeout for sbd.service
+        """
+        timeout_value = SBDManager.get_sbd_start_timeout_threshold()
+        return int(timeout_value * 1.2)
+
     def _restart_cluster_and_configure_sbd_ra(self):
         """
         Try to configure sbd resource, restart cluster on needed
@@ -241,6 +306,29 @@
             # in init process
             bootstrap.invoke("systemctl enable sbd.service")
 
+    def _adjust_systemd(self):
+        """
+        Adjust start timeout for sbd when set SBD_DELAY_START
+        """
+        if not self.is_delay_start():
+            return
+
+        # TimeoutStartUSec default is 1min 30s, need to parse as seconds
+        cmd = "systemctl show -p TimeoutStartUSec sbd --value"
+        out = utils.get_stdout_or_raise_error(cmd)
+        res_seconds = re.search("(\d+)s", out)
+        default_start_timeout = int(res_seconds.group(1)) if res_seconds else 0
+        res_min = re.search("(\d+)min", out)
+        default_start_timeout += 60 * int(res_min.group(1)) if res_min else 0
+        if default_start_timeout >= self.get_sbd_start_timeout_threshold():
+            return
+
+        systemd_sbd_dir = "/etc/systemd/system/sbd.service.d"
+        utils.mkdirp(systemd_sbd_dir)
+        sbd_delay_start_file = 
"{}/sbd_delay_start.conf".format(systemd_sbd_dir)
+        
utils.str2file("[Service]\nTimeoutSec={}".format(self.get_suitable_sbd_systemd_timeout()),
 sbd_delay_start_file)
+        utils.get_stdout_or_raise_error("systemctl daemon-reload")
+
     def _warn_diskless_sbd(self, peer=None):
         """
         Give warning when configuring diskless sbd
@@ -275,9 +363,9 @@
         self._warn_diskless_sbd()
         with bootstrap.status_long("Initializing {}SBD...".format("diskless " 
if self.diskless_sbd else "")):
             self._initialize_sbd()
-            self._update_configuration()
-        self._determine_stonith_watchdog_timeout()
+            self._update_sbd_configuration()
         self._enable_sbd_service()
+        self._adjust_systemd()
 
     def configure_sbd_resource(self):
         """
@@ -318,6 +406,7 @@
             self._verify_sbd_device(dev_list, [peer_host])
         else:
             self._warn_diskless_sbd(peer_host)
+        self._adjust_systemd()
         bootstrap.status("Got {}SBD configuration".format("" if dev_list else 
"diskless "))
         bootstrap.invoke("systemctl enable sbd.service")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/crmsh/ui_cluster.py 
new/crmsh-4.3.1+20210811.4045e09d/crmsh/ui_cluster.py
--- old/crmsh-4.3.1+20210726.3de6f304/crmsh/ui_cluster.py       2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/crmsh/ui_cluster.py       2021-08-11 
09:00:07.000000000 +0200
@@ -96,7 +96,7 @@
             if utils.service_is_active("pacemaker.service"):
                 err_buf.info("Cluster services already started")
                 return
-            utils.start_service("pacemaker")
+            bootstrap.start_pacemaker()
             if utils.is_qdevice_configured():
                 utils.start_service("corosync-qdevice")
             err_buf.info("Cluster services started")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/crmsh/ui_resource.py 
new/crmsh-4.3.1+20210811.4045e09d/crmsh/ui_resource.py
--- old/crmsh-4.3.1+20210726.3de6f304/crmsh/ui_resource.py      2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/crmsh/ui_resource.py      2021-08-11 
09:00:07.000000000 +0200
@@ -701,12 +701,8 @@
             self._trace_op_interval(context, rsc_id, rsc, op, interval)
         if not cib_factory.commit():
             return False
-        if op is not None:
-            common_info("Trace for %s:%s is written to %s/trace_ra/" %
-                        (rsc_id, op, config.path.heartbeat_dir))
-        else:
-            common_info("Trace for %s is written to %s/trace_ra/" %
-                        (rsc_id, config.path.heartbeat_dir))
+        rsc_type = rsc.node.get("type")
+        common_info("Trace for {}{} is written to 
{}/trace_ra/{}".format(rsc_id, ":"+op if op else "", config.path.heartbeat_dir, 
rsc_type))
         if op is not None and op != "monitor":
             common_info("Trace set, restart %s to trace the %s operation" % 
(rsc_id, op))
         else:
@@ -760,4 +756,7 @@
             self._untrace_op(context, rsc_id, rsc, op)
         else:
             self._untrace_op_interval(context, rsc_id, rsc, op, interval)
-        return cib_factory.commit()
+        if not cib_factory.commit():
+            return False
+        common_info("Stop tracing {}{}".format(rsc_id, " for operation "+op if 
op else ""))
+        return True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/doc/crm.8.adoc 
new/crmsh-4.3.1+20210811.4045e09d/doc/crm.8.adoc
--- old/crmsh-4.3.1+20210726.3de6f304/doc/crm.8.adoc    2021-07-26 
05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/doc/crm.8.adoc    2021-08-11 
09:00:07.000000000 +0200
@@ -2006,6 +2006,10 @@
 set a trace for `monitor` with interval `0`, or use `probe` as the
 operation name.
 
+Note: RA tracing is only supported by OCF resource agents;
+The pacemaker-execd daemon does not log recurring monitor operations
+unless an error occurred.
+
 Usage:
 ...............
 trace <rsc> [<op> [<interval>] ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/etc/crm.conf.in 
new/crmsh-4.3.1+20210811.4045e09d/etc/crm.conf.in
--- old/crmsh-4.3.1+20210726.3de6f304/etc/crm.conf.in   1970-01-01 
01:00:00.000000000 +0100
+++ new/crmsh-4.3.1+20210811.4045e09d/etc/crm.conf.in   2021-08-11 
09:00:07.000000000 +0200
@@ -0,0 +1,117 @@
+; crmsh configuration file
+; To override per user, create a file ~/.config/crm/crm.conf
+;
+; [core]
+; editor = $EDITOR
+; pager = $PAGER
+; user =
+; skill_level = expert
+; sort_elements = yes
+; check_frequency = always
+; check_mode = strict
+; wait = no
+; add_quotes = yes
+; manage_children = ask
+; force = no
+; debug = no
+; ptest = ptest, crm_simulate
+; dotty = dotty
+; dot = dot
+; ignore_missing_metadata = no
+; report_tool_options =
+; lock_timeout = 120
+
+; obscure_pattern option is the persisent configuration of CLI.
+; Example, for the high security concern, obscure_pattern = passw* | ip
+; which makes `crm configure show` is equal to
+;
+; node-1:~ # crm configure show obscure:passw* obscure:ip
+; node 1084783297: node1
+; primitive fence_device stonith:fence_ilo5 \
+;         params password="******"
+; primitive ip IPaddr2 \
+;         params ip="******"
+;
+; The default option is passw*
+; If you don't want to obscure, change the value to blank.
+;
+; obscure_pattern = passw*
+
+[path]
+; sharedir = <detected>
+; cache = <detected>
+; crm_config = <detected>
+; crm_daemon_dir = <detected>
+crm_daemon_user = @CRM_DAEMON_USER@
+ocf_root = @OCF_ROOT_DIR@
+; crm_dtd_dir = <detected>
+; pe_state_dir = <detected>
+; heartbeat_dir = <detected>
+; hb_delnode = /usr/share/heartbeat/hb_delnode
+; nagios_plugins = /usr/lib/nagios/plugins
+
+; [color]
+; style = color
+; error = red bold
+; ok = green bold
+; warn = yellow bold
+; info = cyan
+; help_keyword = blue bold underline
+; help_header = normal bold
+; help_topic = yellow bold
+; help_block = cyan
+; keyword = yellow
+; identifier = normal
+; attr_name = cyan
+; attr_value = red
+; resource_reference = green
+; id_reference = green
+; score = magenta
+; ticket = magenta
+
+; [report]
+; from_time = -12H
+; compress = yes
+; speed_up = no
+; collect_extra_logs = /var/log/messages /var/log/pacemaker.log
+; remove_exist_dest = no
+; single_node = no
+;
+;   sanitize_rule = sanitize_pattern[:options] ...
+;
+; This defines the way to hide sensitive data generated by hb_report.
+;
+; 'sanitize_pattern' is a RegEx string, which is used to matches 'name'
+; field of CIB params. The sanitize process will hide 'value' of those
+; matched 'name:value' pairs in CIB, PE, pacemaker.log.
+;
+; 'options' is the predefined, and 'raw' is the only one defined
+; currently. With ':raw" option, the sanitize process will fetch
+; 'value' results out of CIB 'name:value' pairs, and use them to
+; hide all clear text occurence from all files hb_report collected.
+;
+; Example 1:
+;   sanitize_rule = passw.*
+;
+; This is the default. It will hide password nam:value pairs.
+; The result of hb_report clould be like
+;     name="password", value=******
+;     @name=password @value=******
+;     passwd=******
+;
+;
+; Example 2:
+;   sanitize_rule = ip.*:raw
+;
+; This will only hide ip addresses. Example, the sanitize process will fetch
+; ip=10.10.10.10 and replace all clear text occurrence of "10.10.10.10"
+;
+;
+; Example 3:
+;   sanitize_rule = passw.*|ip.*:raw
+;
+; This is useful for the higher security concern.
+; The sanitize process will hide all "name:value" pair for password like in
+; example 1, and all clear text ip addresses like in example 2 above.
+;
+; sanitize_rule = passw.*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.3.1+20210726.3de6f304/etc/profiles.yml 
new/crmsh-4.3.1+20210811.4045e09d/etc/profiles.yml
--- old/crmsh-4.3.1+20210726.3de6f304/etc/profiles.yml  1970-01-01 
01:00:00.000000000 +0100
+++ new/crmsh-4.3.1+20210811.4045e09d/etc/profiles.yml  2021-08-11 
09:00:07.000000000 +0200
@@ -0,0 +1,29 @@
+# The valid profile names are:
+# "microsoft-azure", "google-cloud-platform", "amazon-web-services", "s390", 
"default"
+#
+# "default" profile is loaded in the beginning.
+#
+# Those specific profile will override the corresponding values in "default"
+# profile if the specific environment is detected.
+#
+# Users could customize the "default" profile for their needs, for example,
+# those on-premise environments which is not defined yet.
+#
+# Profiles are only loaded on bootstrap init node.
+#
+# More details please see man corosync.conf, man sbd
+
+default:
+  corosync.totem.crypto_hash: sha1
+  corosync.totem.crypto_cipher: aes256
+  corosync.totem.token: 5000
+  corosync.totem.join: 60
+  corosync.totem.max_messages: 20
+  corosync.totem.token_retransmits_before_loss_const: 10
+  # sbd.msgwait is set to sbd.watchdog_timeout*2 by crmsh
+  # or, you can define your own value in profiles.yml
+  sbd.watchdog_timeout: 15
+
+microsoft-azure:
+  corosync.totem.token: 30000
+  sbd.watchdog_timeout: 60
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-4.3.1+20210726.3de6f304/test/testcases/common.excl 
new/crmsh-4.3.1+20210811.4045e09d/test/testcases/common.excl
--- old/crmsh-4.3.1+20210726.3de6f304/test/testcases/common.excl        
2021-07-26 05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/test/testcases/common.excl        
2021-08-11 09:00:07.000000000 +0200
@@ -8,7 +8,7 @@
 Error signing on to the CRMd service
 Error connecting to the controller
 Error performing operation: Transport endpoint is not connected
-.EXT crm_resource --list-standards
+.EXT crm_resource --list-ocf-providers
 .EXT crm_resource --list-ocf-alternatives Delay
 .EXT crm_resource --list-ocf-alternatives Dummy
 ^\.EXT crmd version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-4.3.1+20210726.3de6f304/test/testcases/resource.exp 
new/crmsh-4.3.1+20210811.4045e09d/test/testcases/resource.exp
--- old/crmsh-4.3.1+20210726.3de6f304/test/testcases/resource.exp       
2021-07-26 05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/test/testcases/resource.exp       
2021-08-11 09:00:07.000000000 +0200
@@ -327,7 +327,7 @@
 </cib>
 
 .TRY resource trace p0 probe
-INFO: Trace for p0:monitor is written to /var/lib/heartbeat/trace_ra/
+INFO: Trace for p0:monitor is written to /var/lib/heartbeat/trace_ra/Dummy
 INFO: Trace set, restart p0 to trace non-monitor operations
 .INP: configure
 .INP: _regtest on
@@ -355,7 +355,7 @@
 </cib>
 
 .TRY resource trace p0 start
-INFO: Trace for p0:start is written to /var/lib/heartbeat/trace_ra/
+INFO: Trace for p0:start is written to /var/lib/heartbeat/trace_ra/Dummy
 INFO: Trace set, restart p0 to trace the start operation
 .INP: configure
 .INP: _regtest on
@@ -388,7 +388,7 @@
 </cib>
 
 .TRY resource trace p0 stop
-INFO: Trace for p0:stop is written to /var/lib/heartbeat/trace_ra/
+INFO: Trace for p0:stop is written to /var/lib/heartbeat/trace_ra/Dummy
 INFO: Trace set, restart p0 to trace the stop operation
 .INP: configure
 .INP: _regtest on
@@ -426,6 +426,7 @@
 </cib>
 
 .TRY resource untrace p0 probe
+INFO: Stop tracing p0 for operation monitor
 .INP: configure
 .INP: _regtest on
 .INP: show xml p0
@@ -457,6 +458,7 @@
 </cib>
 
 .TRY resource untrace p0 start
+INFO: Stop tracing p0 for operation start
 .INP: configure
 .INP: _regtest on
 .INP: show xml p0
@@ -483,6 +485,7 @@
 </cib>
 
 .TRY resource untrace p0 stop
+INFO: Stop tracing p0 for operation stop
 .INP: configure
 .INP: _regtest on
 .INP: show xml p0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-4.3.1+20210726.3de6f304/test/unittests/test_bootstrap.py 
new/crmsh-4.3.1+20210811.4045e09d/test/unittests/test_bootstrap.py
--- old/crmsh-4.3.1+20210726.3de6f304/test/unittests/test_bootstrap.py  
2021-07-26 05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/test/unittests/test_bootstrap.py  
2021-08-11 09:00:07.000000000 +0200
@@ -12,6 +12,7 @@
 
 import os
 import unittest
+import yaml
 
 try:
     from unittest import mock
@@ -139,6 +140,98 @@
         ctx.qdevice_inst.valid_qdevice_options.assert_called_once_with()
         ctx._validate_sbd_option.assert_called_once_with()
 
+    @mock.patch('crmsh.bootstrap.status')
+    def test_load_specific_profile_return(self, mock_status):
+        res = self.ctx_inst.load_specific_profile(None)
+        assert res == {}
+        mock_status.assert_not_called()
+
+    @mock.patch('crmsh.bootstrap.status')
+    def test_load_specific_profile_not_exist(self, mock_status):
+        self.ctx_inst.profiles_data = {"name": "test"}
+        res = self.ctx_inst.load_specific_profile("newname")
+        assert res == {}
+        mock_status.assert_called_once_with("\"newname\" profile does not 
exist in {}".format(bootstrap.Context.PROFILES_FILE))
+
+    @mock.patch('crmsh.bootstrap.status')
+    def test_load_specific_profile(self, mock_status):
+        self.ctx_inst.profiles_data = {"name": "test"}
+        res = self.ctx_inst.load_specific_profile("name")
+        assert res == "test"
+        mock_status.assert_called_once_with("Loading \"name\" profile from 
{}".format(bootstrap.Context.PROFILES_FILE))
+
+    @mock.patch('crmsh.bootstrap.status')
+    @mock.patch('crmsh.utils.detect_cloud')
+    @mock.patch('os.uname')
+    def test_detect_platform_s390(self, mock_uname, mock_cloud, mock_status):
+        mock_uname.return_value = mock.Mock(machine="s390")
+        res = self.ctx_inst.detect_platform()
+        self.assertEqual(res, bootstrap.Context.S390_PROFILE_NAME)
+        mock_uname.assert_called_once_with()
+        mock_cloud.assert_not_called()
+        mock_status.assert_called_once_with("Detected \"{}\" 
platform".format(res))
+
+    @mock.patch('crmsh.bootstrap.status')
+    @mock.patch('crmsh.utils.detect_cloud')
+    @mock.patch('os.uname')
+    def test_detect_platform(self, mock_uname, mock_cloud, mock_status):
+        mock_uname.return_value = mock.Mock(machine="xxx")
+        mock_cloud.return_value = "azure"
+        res = self.ctx_inst.detect_platform()
+        self.assertEqual(res, "azure")
+        mock_uname.assert_called_once_with()
+        mock_cloud.assert_called_once_with()
+        mock_status.assert_called_once_with("Detected \"{}\" 
platform".format(res))
+
+    @mock.patch('os.path.exists')
+    @mock.patch('crmsh.bootstrap.Context.detect_platform')
+    def test_load_profiles_file_not_exist(self, mock_platform, mock_exists):
+        mock_platform.return_value = "s390"
+        mock_exists.return_value = False
+        self.ctx_inst.load_profiles()
+        mock_platform.assert_called_once_with()
+        mock_exists.assert_called_once_with(bootstrap.Context.PROFILES_FILE)
+
+    @mock.patch('yaml.load')
+    @mock.patch('builtins.open', new_callable=mock.mock_open, read_data="")
+    @mock.patch('os.path.exists')
+    @mock.patch('crmsh.bootstrap.Context.detect_platform')
+    def test_load_profiles_file_empty(self, mock_platform, mock_exists, 
mock_open_file, mock_load):
+        mock_platform.return_value = "s390"
+        mock_exists.return_value = True
+        mock_load.return_value = ""
+        self.ctx_inst.load_profiles()
+        mock_platform.assert_called_once_with()
+        mock_exists.assert_called_once_with(bootstrap.Context.PROFILES_FILE)
+        mock_open_file.assert_called_once_with(bootstrap.Context.PROFILES_FILE)
+        mock_load.assert_called_once_with(mock_open_file.return_value, 
Loader=yaml.SafeLoader)
+
+    @mock.patch('crmsh.bootstrap.Context.load_specific_profile')
+    @mock.patch('yaml.load')
+    @mock.patch('builtins.open', new_callable=mock.mock_open, read_data="")
+    @mock.patch('os.path.exists')
+    @mock.patch('crmsh.bootstrap.Context.detect_platform')
+    def test_load_profiles_file(self, mock_platform, mock_exists, 
mock_open_file, mock_load, mock_load_specific):
+        mock_platform.return_value = "s390"
+        mock_exists.return_value = True
+        mock_load.return_value = "data"
+        mock_load_specific.side_effect = [
+                {"name": "xin", "age": 18},
+                {"name": "wang"}
+                ]
+
+        self.ctx_inst.load_profiles()
+        assert self.ctx_inst.profiles_dict == {"name": "wang", "age": 18}
+
+        mock_platform.assert_called_once_with()
+        mock_exists.assert_called_once_with(bootstrap.Context.PROFILES_FILE)
+        mock_open_file.assert_called_once_with(bootstrap.Context.PROFILES_FILE)
+        mock_load.assert_called_once_with(mock_open_file.return_value, 
Loader=yaml.SafeLoader)
+        mock_load_specific.assert_has_calls([
+            mock.call(bootstrap.Context.DEFAULT_PROFILE_NAME),
+            mock.call("s390")
+            ])
+
 
 class TestBootstrap(unittest.TestCase):
     """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-4.3.1+20210726.3de6f304/test/unittests/test_sbd.py 
new/crmsh-4.3.1+20210811.4045e09d/test/unittests/test_sbd.py
--- old/crmsh-4.3.1+20210726.3de6f304/test/unittests/test_sbd.py        
2021-07-26 05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/test/unittests/test_sbd.py        
2021-08-11 09:00:07.000000000 +0200
@@ -189,11 +189,18 @@
         self.sbd_inst_diskless._get_sbd_device()
 
     def test_initialize_sbd_return(self):
+        self.sbd_inst_diskless._context = mock.Mock(profiles_dict={})
         self.sbd_inst_diskless._initialize_sbd()
 
+    @mock.patch('crmsh.bootstrap.warn')
+    @mock.patch('crmsh.sbd.SBDManager._adjust_sbd_watchdog_timeout_for_s390')
     @mock.patch('crmsh.bootstrap.error')
     @mock.patch('crmsh.bootstrap.invoke')
-    def test_initialize_sbd(self, mock_invoke, mock_error):
+    def test_initialize_sbd(self, mock_invoke, mock_error, mock_adjust_s390, 
mock_warn):
+        self.sbd_inst._context = mock.Mock(profiles_dict={
+            "sbd.msgwait": 9,
+            "sbd.watchdog_timeout": 5
+            })
         self.sbd_inst._sbd_devices = ["/dev/sdb1", "/dev/sdc1"]
         mock_invoke.side_effect = [(True, None, None), (False, None, "error")]
         mock_error.side_effect = ValueError
@@ -202,15 +209,16 @@
             self.sbd_inst._initialize_sbd()
 
         mock_invoke.assert_has_calls([
-            mock.call("sbd -d /dev/sdb1 create"),
-            mock.call("sbd -d /dev/sdc1 create")
+            mock.call("sbd -4 10 -1 5 -d /dev/sdb1 create"),
+            mock.call("sbd -4 10 -1 5 -d /dev/sdc1 create")
             ])
+        mock_warn.assert_called_once_with("sbd msgwait is set to 10, it was 9")
         mock_error.assert_called_once_with("Failed to initialize SBD device 
/dev/sdc1: error")
 
     @mock.patch('crmsh.utils.detect_virt')
     @mock.patch('crmsh.bootstrap.csync2_update')
     @mock.patch('crmsh.utils.sysconfig_set')
-    @mock.patch('crmsh.sbd.SBDManager._determine_sbd_watchdog_timeout')
+    
@mock.patch('crmsh.sbd.SBDManager._adjust_sbd_watchdog_timeout_with_diskless_and_qdevice')
     @mock.patch('shutil.copyfile')
     def test_update_configuration(self, mock_copy, mock_determine, 
mock_sysconfig, mock_update, mock_detect):
         self.sbd_inst._sbd_devices = ["/dev/sdb1", "/dev/sdc1"]
@@ -218,7 +226,7 @@
         mock_detect.return_value = True
 
         self.sbd_inst._sbd_watchdog_timeout = 30
-        self.sbd_inst._update_configuration()
+        self.sbd_inst._update_sbd_configuration()
 
         
mock_copy.assert_called_once_with("/usr/share/fillup-templates/sysconfig.sbd", 
"/etc/sysconfig/sbd")
         mock_sysconfig.assert_called_once_with("/etc/sysconfig/sbd", 
SBD_PACEMAKER='yes', SBD_STARTMODE='always', SBD_DELAY_START='yes', 
SBD_WATCHDOG_DEV='/dev/watchdog', SBD_DEVICE='/dev/sdb1;/dev/sdc1', 
SBD_WATCHDOG_TIMEOUT="30")
@@ -274,7 +282,7 @@
         mock_package.assert_called_once_with("sbd")
 
     @mock.patch('crmsh.bootstrap.invoke')
-    @mock.patch('crmsh.sbd.SBDManager._update_configuration')
+    @mock.patch('crmsh.sbd.SBDManager._update_sbd_configuration')
     @mock.patch('crmsh.sbd.SBDManager._initialize_sbd')
     @mock.patch('crmsh.bootstrap.status_long')
     @mock.patch('crmsh.sbd.SBDManager._get_sbd_device')
@@ -300,16 +308,15 @@
         mock_watchdog_inst.init_watchdog.assert_called_once_with()
         mock_invoke.assert_called_once_with("systemctl disable sbd.service")
  
-    @mock.patch('crmsh.sbd.SBDManager._determine_stonith_watchdog_timeout')
     @mock.patch('crmsh.sbd.SBDManager._enable_sbd_service')
     @mock.patch('crmsh.sbd.SBDManager._warn_diskless_sbd')
-    @mock.patch('crmsh.sbd.SBDManager._update_configuration')
+    @mock.patch('crmsh.sbd.SBDManager._update_sbd_configuration')
     @mock.patch('crmsh.sbd.SBDManager._initialize_sbd')
     @mock.patch('crmsh.bootstrap.status_long')
     @mock.patch('crmsh.sbd.SBDManager._get_sbd_device')
     @mock.patch('crmsh.watchdog.Watchdog')
     @mock.patch('crmsh.utils.package_is_installed')
-    def test_sbd_init(self, mock_package, mock_watchdog, mock_get_device, 
mock_status, mock_initialize, mock_update, mock_warn, mock_enable_sbd, 
mock_determine):
+    def test_sbd_init(self, mock_package, mock_watchdog, mock_get_device, 
mock_status, mock_initialize, mock_update, mock_warn, mock_enable_sbd):
         mock_package.return_value = True
         self.sbd_inst_diskless._context = mock.Mock(watchdog=None)
         mock_watchdog_inst = mock.Mock()
@@ -326,7 +333,6 @@
         mock_watchdog_inst.init_watchdog.assert_called_once_with()
         mock_warn.assert_called_once_with()
         mock_enable_sbd.assert_called_once_with()
-        mock_determine.assert_called_once_with()
 
     @mock.patch('crmsh.sbd.SBDManager.configure_sbd_resource')
     @mock.patch('crmsh.bootstrap.wait_for_cluster')
@@ -348,7 +354,7 @@
         self.sbd_inst_diskless._restart_cluster_and_configure_sbd_ra()
         mock_warn.assert_has_calls([
             mock.call("To start sbd.service, need to restart cluster service 
manually on each node"),
-            mock.call("Then run \"crm configure property stonith-enabled=true 
stonith-watchdog-timeout=10s stonith-timeout=60s\" on any node")
+            mock.call("Then run \"crm configure property stonith-enabled=true 
stonith-watchdog-timeout=-1 stonith-timeout=60s\" on any node")
             ])
 
     @mock.patch('crmsh.sbd.SBDManager.configure_sbd_resource')
@@ -472,7 +478,7 @@
         mock_package.assert_called_once_with("sbd")
         mock_enabled.assert_called_once_with("sbd.service")
         mock_get_device.assert_called_once_with()
-        mock_invoke.assert_called_once_with("crm configure property 
stonith-enabled=true stonith-watchdog-timeout=10s stonith-timeout=60s")
+        mock_invoke.assert_called_once_with("crm configure property 
stonith-enabled=true stonith-watchdog-timeout=-1 stonith-timeout=60s")
         mock_error.assert_called_once_with("Can't enable STONITH for diskless 
SBD")
         mock_ra_configured.assert_called_once_with("stonith:external/sbd")
 
@@ -598,23 +604,15 @@
         self.assertEqual("Device /dev/sdb1 doesn't have the same UUID with 
node1", str(err.exception))
         mock_get_uuid.assert_has_calls([mock.call("/dev/sdb1"), 
mock.call("/dev/sdb1", "node1")])
 
-    @mock.patch('crmsh.utils.get_stdout_stderr')
-    def test_get_device_uuid_error_dump(self, mock_run):
-        mock_run.return_value = (1, None, "error data")
-        with self.assertRaises(ValueError) as err:
-            self.sbd_inst._get_device_uuid("/dev/sdb1")
-        self.assertEqual("Cannot dump sbd meta-data: error data", 
str(err.exception))
-        mock_run.assert_called_once_with("sbd -d /dev/sdb1 dump")
-
-    @mock.patch('crmsh.utils.get_stdout_stderr')
+    @mock.patch('crmsh.utils.get_stdout_or_raise_error')
     def test_get_device_uuid_not_match(self, mock_run):
-        mock_run.return_value = (0, "output data", None)
+        mock_run.return_value = "data"
         with self.assertRaises(ValueError) as err:
             self.sbd_inst._get_device_uuid("/dev/sdb1")
         self.assertEqual("Cannot find sbd device UUID for /dev/sdb1", 
str(err.exception))
-        mock_run.assert_called_once_with("sbd -d /dev/sdb1 dump")
+        mock_run.assert_called_once_with("sbd -d /dev/sdb1 dump", remote=None)
 
-    @mock.patch('crmsh.utils.get_stdout_stderr')
+    @mock.patch('crmsh.utils.get_stdout_or_raise_error')
     def test_get_device_uuid(self, mock_run):
         output = """
         ==Dumping header on disk /dev/sda1
@@ -628,66 +626,50 @@
         Timeout (msgwait)  : 10
         ==Header on disk /dev/sda1 is dumped
         """
-        mock_run.return_value = (0, output, None)
+        mock_run.return_value = output
         res = self.sbd_inst._get_device_uuid("/dev/sda1", node="node1")
         self.assertEqual(res, "a2e9a92c-cc72-4ef9-ac55-ccc342f3546b")
-        mock_run.assert_called_once_with("ssh -o StrictHostKeyChecking=no 
root@node1 'sbd -d /dev/sda1 dump'")
-
-    @mock.patch('crmsh.utils.parse_sysconfig')
-    def test_determine_watchdog_timeout(self, mock_parse):
-        mock_parse_inst = mock.Mock()
-        mock_parse.return_value = mock_parse_inst
-        mock_parse_inst.get.return_value = "5"
-        self.sbd_inst._determine_stonith_watchdog_timeout()
-        assert self.sbd_inst._stonith_watchdog_timeout == -1
-        mock_parse.assert_called_once_with(bootstrap.SYSCONFIG_SBD)
-        mock_parse_inst.get.assert_called_once_with("SBD_WATCHDOG_TIMEOUT")
-
-    @mock.patch('crmsh.utils.parse_sysconfig')
-    def test_determine_watchdog_timeout_s390(self, mock_parse):
-        mock_parse_inst = mock.Mock()
-        mock_parse.return_value = mock_parse_inst
-        mock_parse_inst.get.return_value = None
-        self.sbd_inst._is_s390 = True
-        self.sbd_inst._determine_stonith_watchdog_timeout()
-        assert self.sbd_inst._stonith_watchdog_timeout == "30s"
-        mock_parse.assert_called_once_with(bootstrap.SYSCONFIG_SBD)
-        mock_parse_inst.get.assert_called_once_with("SBD_WATCHDOG_TIMEOUT")
+        mock_run.assert_called_once_with("sbd -d /dev/sda1 dump", 
remote="node1")
 
     @mock.patch('crmsh.utils.is_qdevice_configured')
-    def test_determine_sbd_watchdog_timeout_return(self, 
mock_qdevice_configured):
-        self.sbd_inst._determine_sbd_watchdog_timeout()
+    def 
test_adjust_sbd_watchdog_timeout_with_diskless_and_qdevice_return(self, 
mock_qdevice_configured):
+        self.sbd_inst._adjust_sbd_watchdog_timeout_with_diskless_and_qdevice()
         mock_qdevice_configured.assert_not_called()
 
+    @mock.patch('crmsh.bootstrap.warn')
     @mock.patch('crmsh.sbd.SBDManager.calculate_stonith_timeout')
     @mock.patch('crmsh.utils.get_qdevice_sync_timeout')
     @mock.patch('crmsh.utils.service_is_active')
     @mock.patch('crmsh.utils.is_qdevice_configured')
-    def test_determine_sbd_watchdog_timeout_after_qdevice(self, 
mock_qdevice_configured, mock_active, mock_get_qsync_timeout, mock_cal_timeout):
+    def 
test_adjust_sbd_watchdog_timeout_with_diskless_and_qdevice_after_qdevice(self, 
mock_qdevice_configured, mock_active, mock_get_qsync_timeout, mock_cal_timeout, 
mock_warn):
         mock_qdevice_configured.return_value = True
         mock_active.return_value = True
-        mock_get_qsync_timeout.return_value = 5
-        self.sbd_inst_diskless._is_s390 = True
-        mock_cal_timeout.return_value = 20
+        mock_get_qsync_timeout.return_value = 30
+        self.sbd_inst_diskless._sbd_watchdog_timeout = 5
+        mock_cal_timeout.return_value = 70
 
-        self.sbd_inst_diskless._determine_sbd_watchdog_timeout()
+        
self.sbd_inst_diskless._adjust_sbd_watchdog_timeout_with_diskless_and_qdevice()
 
         mock_qdevice_configured.assert_called_once_with()
         mock_active.assert_called_once_with("corosync-qdevice.service")
         mock_get_qsync_timeout.assert_called_once_with()
-        mock_cal_timeout.assert_called_once_with(15)
+        mock_cal_timeout.assert_called_once_with(35)
+        mock_warn.assert_called_once_with("sbd_watchdog_timeout is set to 35 
for qdevice, it was 5")
 
+    @mock.patch('crmsh.bootstrap.warn')
     @mock.patch('crmsh.sbd.SBDManager.calculate_stonith_timeout')
     @mock.patch('crmsh.utils.is_qdevice_configured')
-    def test_determine_sbd_watchdog_timeout(self, mock_qdevice_configured, 
mock_cal_timeout):
+    def test_adjust_sbd_watchdog_timeout_with_diskless_and_qdevice(self, 
mock_qdevice_configured, mock_cal_timeout, mock_warn):
         self.sbd_inst_diskless._context = mock.Mock(qdevice_inst=mock.Mock())
         mock_qdevice_configured.return_value = False
-        mock_cal_timeout.return_value = 20
+        mock_cal_timeout.return_value = 10
+        self.sbd_inst_diskless._sbd_watchdog_timeout = 5
 
-        self.sbd_inst_diskless._determine_sbd_watchdog_timeout()
+        
self.sbd_inst_diskless._adjust_sbd_watchdog_timeout_with_diskless_and_qdevice()
 
         mock_qdevice_configured.assert_called_once_with()
         
mock_cal_timeout.assert_called_once_with(sbd.SBDManager.SBD_WATCHDOG_TIMEOUT_DEFAULT_WITH_QDEVICE)
+        mock_warn.assert_called_once_with("sbd_watchdog_timeout is set to 35 
for qdevice, it was 5")
 
     @mock.patch('crmsh.sbd.SBDManager._get_sbd_device_from_config')
     @mock.patch('crmsh.utils.service_is_active')
@@ -737,3 +719,118 @@
     def test_calculate_stonith_timeout(self):
         res = self.sbd_inst.calculate_stonith_timeout(5)
         assert res == 12
+
+    @mock.patch('crmsh.sbd.SBDManager.is_delay_start')
+    @mock.patch('crmsh.utils.get_stdout_or_raise_error')
+    def test_adjust_systemd_no_delay(self, mock_run, mock_delay_start):
+        mock_delay_start.return_value = False
+        self.sbd_inst._adjust_systemd()
+        mock_delay_start.assert_called_once_with()
+        mock_run.assert_not_called()
+
+    @mock.patch('crmsh.sbd.SBDManager.get_sbd_start_timeout_threshold')
+    @mock.patch('crmsh.utils.mkdirp')
+    @mock.patch('crmsh.utils.get_stdout_or_raise_error')
+    @mock.patch('crmsh.sbd.SBDManager.is_delay_start')
+    def test_adjust_systemd_return(self, mock_delay_start, mock_run, 
mock_dirp, mock_threshold):
+        mock_threshold.return_value = 10
+        mock_delay_start.return_value = True
+        mock_run.return_value = "1min 30s"
+
+        self.sbd_inst._adjust_systemd()
+
+        mock_run.assert_called_once_with("systemctl show -p TimeoutStartUSec 
sbd --value")
+        mock_threshold.assert_called_once_with()
+        mock_dirp.assert_not_called()
+
+    @mock.patch('crmsh.utils.str2file')
+    @mock.patch('crmsh.utils.mkdirp')
+    @mock.patch('crmsh.utils.get_stdout_or_raise_error')
+    @mock.patch('crmsh.sbd.SBDManager.get_suitable_sbd_systemd_timeout')
+    @mock.patch('crmsh.sbd.SBDManager.get_sbd_start_timeout_threshold')
+    @mock.patch('crmsh.sbd.SBDManager.is_delay_start')
+    def test_adjust_systemd(self, mock_delay_start, mock_threshold, 
mock_systemd_timeout, mock_run, mock_dirp, mock_str2file):
+        mock_delay_start.return_value = True
+        mock_threshold.return_value = 120
+        mock_systemd_timeout.return_value = 144
+        mock_run.return_value = "1min 30s"
+
+        self.sbd_inst._adjust_systemd()
+
+        mock_run.assert_has_calls([
+            mock.call("systemctl show -p TimeoutStartUSec sbd --value"),
+            mock.call("systemctl daemon-reload")
+            ])
+        mock_dirp.assert_called_once_with("/etc/systemd/system/sbd.service.d")
+        mock_str2file.assert_called_once_with('[Service]\nTimeoutSec=144', 
'/etc/systemd/system/sbd.service.d/sbd_delay_start.conf')
+        mock_delay_start.assert_called_once_with()
+        mock_threshold.assert_called_once_with()
+        mock_systemd_timeout.assert_called_once_with()
+
+    @mock.patch('crmsh.utils.get_stdout_or_raise_error')
+    def test_get_sbd_msgwait_exception(self, mock_run):
+        mock_run.return_value = "data"
+        with self.assertRaises(ValueError) as err:
+            sbd.SBDManager._get_sbd_msgwait("/dev/sda1")
+        self.assertEqual("Cannot get sbd msgwait for /dev/sda1", 
str(err.exception))
+
+    @mock.patch('crmsh.utils.get_stdout_or_raise_error')
+    def test_get_sbd_msgwait(self, mock_run):
+        mock_run.return_value = """
+        Timeout (allocate) : 2
+        Timeout (loop)     : 1
+        Timeout (msgwait)  : 30
+        ==Header on disk /dev/sda1 is dumped
+        """
+        res = sbd.SBDManager._get_sbd_msgwait("/dev/sda1")
+        self.assertEqual(res, 30)
+        mock_run.assert_called_once_with("sbd -d /dev/sda1 dump")
+
+    @mock.patch('crmsh.sbd.SBDManager.get_sbd_start_timeout_threshold')
+    def test_get_suitable_sbd_systemd_timeout(self, mock_threshold):
+        mock_threshold.return_value = 10
+        res = sbd.SBDManager.get_suitable_sbd_systemd_timeout()
+        self.assertEqual(res, 12)
+        mock_threshold.assert_called_once_with()
+
+    @mock.patch('crmsh.bootstrap.warn')
+    def test_adjust_sbd_watchdog_timeout_for_s390(self, mock_warn):
+        self.sbd_inst._context = mock.Mock(is_s390=True)
+        self.sbd_inst._sbd_watchdog_timeout = 10
+        self.sbd_inst._adjust_sbd_watchdog_timeout_for_s390()
+        mock_warn.assert_called_once_with("sbd_watchdog_timeout is set to 15 
for s390, it was 10")
+
+    @mock.patch('crmsh.sbd.SBDManager.get_sbd_value_from_config')
+    def test_get_sbd_watchdog_timeout_exception(self, mock_get_value):
+        mock_get_value.return_value = None
+        with self.assertRaises(ValueError) as err:
+            sbd.SBDManager.get_sbd_watchdog_timeout()
+        self.assertEqual("Cannot get the value of SBD_WATCHDOG_TIMEOUT", 
str(err.exception))
+        mock_get_value.assert_called_once_with("SBD_WATCHDOG_TIMEOUT")
+
+    @mock.patch('crmsh.sbd.SBDManager.get_sbd_value_from_config')
+    def test_get_sbd_watchdog_timeout(self, mock_get_value):
+        mock_get_value.return_value = 10
+        res = sbd.SBDManager.get_sbd_watchdog_timeout()
+        self.assertEqual(res, 10)
+        mock_get_value.assert_called_once_with("SBD_WATCHDOG_TIMEOUT")
+
+    @mock.patch('crmsh.sbd.SBDManager.get_sbd_watchdog_timeout')
+    @mock.patch('crmsh.sbd.SBDManager.get_sbd_device_from_config')
+    def test_get_sbd_start_timeout_threshold_diskless(self, mock_get_device, 
mock_get_timeout):
+        mock_get_device.return_value = None
+        mock_get_timeout.return_value = 10
+        res = sbd.SBDManager.get_sbd_start_timeout_threshold()
+        self.assertEqual(res, 20)
+        mock_get_device.assert_called_once_with()
+        mock_get_timeout.assert_called_once_with()
+
+    @mock.patch('crmsh.sbd.SBDManager._get_sbd_msgwait')
+    @mock.patch('crmsh.sbd.SBDManager.get_sbd_device_from_config')
+    def test_get_sbd_start_timeout_threshold(self, mock_get_device, 
mock_get_msgwait):
+        mock_get_device.return_value = ["/dev/sdb1"]
+        mock_get_msgwait.return_value = 10
+        res = sbd.SBDManager.get_sbd_start_timeout_threshold()
+        self.assertEqual(res, 10)
+        mock_get_device.assert_called_once_with()
+        mock_get_msgwait.assert_called_once_with("/dev/sdb1")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-4.3.1+20210726.3de6f304/test/unittests/test_ui_cluster.py 
new/crmsh-4.3.1+20210811.4045e09d/test/unittests/test_ui_cluster.py
--- old/crmsh-4.3.1+20210726.3de6f304/test/unittests/test_ui_cluster.py 
2021-07-26 05:56:03.000000000 +0200
+++ new/crmsh-4.3.1+20210811.4045e09d/test/unittests/test_ui_cluster.py 
2021-08-11 09:00:07.000000000 +0200
@@ -43,11 +43,12 @@
         mock_active.assert_called_once_with("pacemaker.service")
         mock_info.assert_called_once_with("Cluster services already started")
 
+    @mock.patch('crmsh.bootstrap.start_pacemaker')
     @mock.patch('crmsh.ui_cluster.err_buf.info')
     @mock.patch('crmsh.utils.is_qdevice_configured')
     @mock.patch('crmsh.utils.start_service')
     @mock.patch('crmsh.utils.service_is_active')
-    def test_do_start(self, mock_active, mock_start, mock_qdevice_configured, 
mock_info):
+    def test_do_start(self, mock_active, mock_start, mock_qdevice_configured, 
mock_info, mock_start_pacemaker):
         context_inst = mock.Mock()
         mock_active.return_value = False
         mock_qdevice_configured.return_value = True
@@ -55,7 +56,7 @@
         self.ui_cluster_inst.do_start(context_inst)
 
         mock_active.assert_called_once_with("pacemaker.service")
-        mock_start.assert_has_calls([mock.call("pacemaker"), 
mock.call("corosync-qdevice")])
+        mock_start.assert_has_calls([mock.call("corosync-qdevice")])
         mock_qdevice_configured.assert_called_once_with()
         mock_info.assert_called_once_with("Cluster services started")
 

Reply via email to