File 0016-high-bootstrap-Add-option-to-enable-diskless-SBD-mod.patch of Package crmsh

From 6f0b4d75121973a69d783ac6b0480f0516936227 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?= <krig@koru.se>
Date: Tue, 20 Jun 2017 14:53:16 +0200
Subject: [PATCH 16/16] high: bootstrap: Add option to enable diskless SBD mode
 to cluster init (bsc#1045118)

---
 crmsh/bootstrap.py  | 94 +++++++++++++++++++++++++++++++++++++++++++++--------
 crmsh/ui_cluster.py |  3 ++
 doc/crm.8.adoc      |  3 ++
 3 files changed, 87 insertions(+), 13 deletions(-)

diff --git a/crmsh/bootstrap.py b/crmsh/bootstrap.py
index 2fcd55b6..6e4c5049 100644
--- a/crmsh/bootstrap.py
+++ b/crmsh/bootstrap.py
@@ -53,6 +53,7 @@ class Context(object):
         self.ocfs2_device = None
         self.shared_device = None
         self.sbd_device = None
+        self.diskless_sbd = False  # if True, enable SBD for diskless operation
         self.unicast = None
         self.admin_ip = None
         self.watchdog = None
@@ -515,7 +516,9 @@ def init_cluster_local():
     if pass_msg:
         warn("You should change the hacluster password to something more secure!")
 
-    if configured_sbd_device():
+    # for cluster join, diskless_sbd flag is set in join_cluster() if
+    # sbd is running on seed host
+    if configured_sbd_device() or _context.diskless_sbd:
         invoke("systemctl enable sbd.service")
     else:
         invoke("systemctl disable sbd.service")
@@ -876,9 +879,9 @@ Configure Shared Storage:
     status("Created %s for OCFS2 partition" % (_context.ocfs2_device))
 
 
-def check_watchdog():
+def detect_watchdog_device():
     """
-    Verify watchdog device. Fall back to /dev/watchdog.
+    Find the watchdog device. Fall back to /dev/watchdog.
     """
     wdconf = "/etc/modules-load.d/watchdog.conf"
     watchdog_dev = "/dev/watchdog"
@@ -888,15 +891,66 @@ def check_watchdog():
             m = re.match(r'^\s*watchdog-device\s*=\s*(.*)$', line)
             if m:
                 watchdog_dev = m.group(1)
+    return watchdog_dev
+
+
+def check_watchdog():
+    """
+    Verify watchdog device. Fall back to /dev/watchdog.
+    """
+    watchdog_dev = detect_watchdog_device()
     rc, _out, _err = utils.get_stdout_stderr("wdctl %s" % (watchdog_dev))
     return rc == 0
 
 
+def sysconfig_comment_out(scfile, key):
+    """
+    Comments out the given key in the sysconfig file
+    """
+    matcher = re.compile(r'^\s*{}\s*='.format(key))
+    outp, ncomments = "", 0
+    for line in scfile.readlines():
+        if matcher.match(line):
+            outp += '#' + line
+            ncomments += 1
+        else:
+            outp += line
+    return outp, ncomments
+
+
+def init_sbd_diskless():
+    """
+    Initialize SBD in diskless mode.
+    """
+    status_long("Initializing diskless SBD...")
+    if os.path.isfile(SYSCONFIG_SBD):
+        log("Overwriting {} with diskless configuration".format(SYSCONFIG_SBD))
+        scfg, nmatches = sysconfig_comment_out(open(SYSCONFIG_SBD), "SBD_DEVICE")
+        if nmatches > 0:
+            utils.str2file(scfg, SYSCONFIG_SBD)
+    else:
+        log("Creating {} with diskless configuration".format(SYSCONFIG_SBD))
+    utils.sysconfig_set(SYSCONFIG_SBD,
+                        SBD_WATCHDOG="yes",
+                        SBD_PACEMAKER="yes",
+                        SBD_STARTMODE="always",
+                        SBD_DELAY_START="no",
+                        SBD_WATCHDOG_DEVICE=detect_watchdog_device())
+    csync2_update(SYSCONFIG_SBD)
+    status_done()
+
+
 def init_sbd():
     """
     Configure SBD (Storage-based fencing).
+
+    SBD can also run in diskless mode if no device
+    is configured.
     """
-    if not _context.sbd_device:
+    if not _context.sbd_device and _context.diskless_sbd:
+        init_sbd_diskless()
+        return
+    elif not _context.sbd_device:
         # SBD device not set up by init_storage (ocfs2 template) and
         # also not passed in as command line argument - prompt user
         if _context.yes_to_all:
@@ -921,17 +975,21 @@ Configure SBD:
         if not confirm("Do you wish to use SBD?"):
             warn("Not configuring SBD - STONITH will be disabled.")
             # Comment out SBD devices if present
-            scfg = open(SYSCONFIG_SBD).read()
-            scfg, nmatches = re.subn(r'^\([^#].*\)$', r'#\1', scfg)
-            if nmatches > 0:
-                utils.str2file(scfg, SYSCONFIG_SBD)
-                csync2_update(SYSCONFIG_SBD)
+            if os.path.isfile(SYSCONFIG_SBD):
+                scfg, nmatches = sysconfig_comment_out(open(SYSCONFIG_SBD), "SBD_DEVICE")
+                if nmatches > 0:
+                    utils.str2file(scfg, SYSCONFIG_SBD)
+                    csync2_update(SYSCONFIG_SBD)
             return
 
         dev = ""
         dev_looks_sane = False
         while not dev_looks_sane:
-            dev = prompt_for_string('Path to storage device (e.g. /dev/disk/by-id/...)', r'\/.*', dev)
+            dev = prompt_for_string('Path to storage device (e.g. /dev/disk/by-id/...), or "none"', r'none|\/.*', dev)
+            if dev == "none":
+                _context.diskless_sbd = True
+                init_sbd_diskless()
+                return
             if not is_block_device(dev):
                 print >>sys.stderr, "    That doesn't look like a block device"
             else:
@@ -978,11 +1036,14 @@ op_defaults op-options: timeout=600 record-pending=true
 rsc_defaults rsc-options: resource-stickiness=1 migration-threshold=3
 """)
 
-    if utils.parse_sysconfig(SYSCONFIG_SBD).get("SBD_DEVICE"):
+    if configured_sbd_device():
         if not invoke("crm configure primitive stonith-sbd stonith:external/sbd pcmk_delay_max=30s"):
             error("Can't create stonith-sbd primitive")
         if not invoke("crm configure property stonith-enabled=true"):
-            error("Can't enable STONITH")
+            error("Can't enable STONITH for SBD")
+    elif _context.diskless_sbd:
+        if not invoke("crm configure property stonith-enabled=true"):
+            error("Can't enable STONITH for diskless SBD")
 
 
 def init_vgfs():
@@ -1235,6 +1296,11 @@ def join_cluster(seed_host):
     if is_unicast:
         corosync.add_node(utils.this_node())
 
+    # if no SBD devices are configured,
+    # check the existing cluster if the sbd service is enabled
+    if not configured_sbd_device() and invoke("ssh root@{} systemctl is-enabled sbd.service".format(seed_host)):
+        _context.diskless_sbd = True
+
     # Initialize the cluster before adjusting quorum. This is so
     # that we can query the cluster to find out how many nodes
     # there are (so as not to adjust multiple times if a previous
@@ -1414,7 +1480,7 @@ def remove_localhost_check():
 
 
 def bootstrap_init(cluster_name="hacluster", nic=None, ocfs2_device=None,
-                   shared_device=None, sbd_device=None, quiet=False,
+                   shared_device=None, sbd_device=None, diskless_sbd=False, quiet=False,
                    template=None, admin_ip=None, yes_to_all=False,
                    unicast=False, watchdog=None, stage=None, args=None):
     """
@@ -1422,6 +1488,7 @@ def bootstrap_init(cluster_name="hacluster", nic=None, ocfs2_device=None,
     -o <ocfs2-device>
     -p <shared-device>
     -s <sbd-device>
+    -S - configure SBD without disk
     -t <template>
     -A [<admin-ip>]
     -q - quiet
@@ -1447,6 +1514,7 @@ def bootstrap_init(cluster_name="hacluster", nic=None, ocfs2_device=None,
     _context.ocfs2_device = ocfs2_device
     _context.shared_device = shared_device
     _context.sbd_device = sbd_device
+    _context.diskless_sbd = diskless_sbd
     _context.unicast = unicast
     _context.admin_ip = admin_ip
     _context.watchdog = watchdog
diff --git a/crmsh/ui_cluster.py b/crmsh/ui_cluster.py
index 9be66522..6db3f401 100644
--- a/crmsh/ui_cluster.py
+++ b/crmsh/ui_cluster.py
@@ -142,6 +142,8 @@ Note:
                           help='Additional nodes to add to the created cluster. ' +
                           'May include the current node, which will always be the initial cluster node.')
         # parser.add_option("--quick-start", dest="quickstart", action="store_true", help="Perform basic system configuration (NTP, watchdog, /etc/hosts)")
+        parser.add_option("-S", "--enable-sbd", dest="diskless_sbd", action="store_true",
+                          help="Enable SBD even if no SBD device is configured (diskless mode)")
         parser.add_option("-w", "--watchdog", dest="watchdog", metavar="WATCHDOG",
                           help="Use the given watchdog device")
 
@@ -187,6 +189,7 @@ Note:
             ocfs2_device=options.ocfs2_device,
             shared_device=options.shared_device,
             sbd_device=options.sbd_device,
+            diskless_sbd=options.diskless_sbd,
             quiet=options.quiet,
             template=options.template,
             admin_ip=options.admin_ip,
diff --git a/doc/crm.8.adoc b/doc/crm.8.adoc
index 6b7ec2f9..7bb902a8 100644
--- a/doc/crm.8.adoc
+++ b/doc/crm.8.adoc
@@ -1140,6 +1140,9 @@ Options:
 *-w WATCHDOG, --watchdog=WATCHDOG*::
     Use the given watchdog device.
 
+*-S, --enable-sbd*::
+    Enable SBD even if no SBD device is configured (diskless mode).
+
 Network configuration:
 
 Options for configuring the network and messaging layer.
-- 
2.12.2

openSUSE Build Service is sponsored by