Blob Blame History Raw
From 4fe757d176060089e46f76d66ef20918b65e1f7f Mon Sep 17 00:00:00 2001
From: Ivan Devat <idevat@redhat.com>
Date: Tue, 20 Sep 2016 08:20:29 +0200
Subject: [PATCH] squash bz1158805 Add support for qdevice/qnetd pro

66e72fa18ddb lib: do not error out in "qdevice stop" if qdevice is stopped already

788407652f58 lib: fix removing qdevice from a cluster
---
 pcs/common/report_codes.py      |  1 +
 pcs/lib/commands/qdevice.py     | 22 +++++++++++++++-------
 pcs/lib/commands/quorum.py      |  7 +++----
 pcs/lib/corosync/qdevice_net.py | 32 +++++++++++++++++++++++++-------
 pcs/lib/reports.py              | 13 +++++++++++++
 5 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/pcs/common/report_codes.py b/pcs/common/report_codes.py
index 23e931f..9b05951 100644
--- a/pcs/common/report_codes.py
+++ b/pcs/common/report_codes.py
@@ -134,6 +134,7 @@ QDEVICE_INITIALIZATION_ERROR = "QDEVICE_INITIALIZATION_ERROR"
 QDEVICE_INITIALIZATION_SUCCESS = "QDEVICE_INITIALIZATION_SUCCESS"
 QDEVICE_NOT_DEFINED = "QDEVICE_NOT_DEFINED"
 QDEVICE_NOT_INITIALIZED = "QDEVICE_NOT_INITIALIZED"
+QDEVICE_NOT_RUNNING = "QDEVICE_NOT_RUNNING"
 QDEVICE_CLIENT_RELOAD_STARTED = "QDEVICE_CLIENT_RELOAD_STARTED"
 QDEVICE_REMOVE_OR_CLUSTER_STOP_NEEDED = "QDEVICE_REMOVE_OR_CLUSTER_STOP_NEEDED"
 QDEVICE_USED_BY_CLUSTERS = "QDEVICE_USED_BY_CLUSTERS"
diff --git a/pcs/lib/commands/qdevice.py b/pcs/lib/commands/qdevice.py
index ca0ae86..119c51d 100644
--- a/pcs/lib/commands/qdevice.py
+++ b/pcs/lib/commands/qdevice.py
@@ -61,11 +61,16 @@ def qdevice_status_text(lib_env, model, verbose=False, cluster=None):
     _ensure_not_cman(lib_env)
     _check_model(model)
     runner = lib_env.cmd_runner()
-    return (
-        qdevice_net.qdevice_status_generic_text(runner, verbose)
-        +
-        qdevice_net.qdevice_status_cluster_text(runner, cluster, verbose)
-    )
+    try:
+        return (
+            qdevice_net.qdevice_status_generic_text(runner, verbose)
+            +
+            qdevice_net.qdevice_status_cluster_text(runner, cluster, verbose)
+        )
+    except qdevice_net.QnetdNotRunningException:
+        raise LibraryError(
+            reports.qdevice_not_running(model)
+        )
 
 def qdevice_enable(lib_env, model):
     """
@@ -196,8 +201,11 @@ def _check_qdevice_not_used(reporter, runner, model, force=False):
     _check_model(model)
     connected_clusters = []
     if model == "net":
-        status = qdevice_net.qdevice_status_cluster_text(runner)
-        connected_clusters = qdevice_net.qdevice_connected_clusters(status)
+        try:
+            status = qdevice_net.qdevice_status_cluster_text(runner)
+            connected_clusters = qdevice_net.qdevice_connected_clusters(status)
+        except qdevice_net.QnetdNotRunningException:
+            pass
     if connected_clusters:
         reporter.process(reports.qdevice_used_by_clusters(
             connected_clusters,
diff --git a/pcs/lib/commands/quorum.py b/pcs/lib/commands/quorum.py
index 8390fc6..aa98e61 100644
--- a/pcs/lib/commands/quorum.py
+++ b/pcs/lib/commands/quorum.py
@@ -285,6 +285,7 @@ def remove_device(lib_env, skip_offline_nodes=False):
     cfg.remove_quorum_device()
 
     if lib_env.is_corosync_conf_live:
+        communicator = lib_env.node_communicator()
         # fix quorum options for SBD to work properly
         if sbd.atb_has_to_be_enabled(lib_env.cmd_runner(), cfg):
             lib_env.report_processor.process(reports.sbd_requires_atb())
@@ -292,10 +293,6 @@ def remove_device(lib_env, skip_offline_nodes=False):
                 lib_env.report_processor, {"auto_tie_breaker": "1"}
             )
 
-    lib_env.push_corosync_conf(cfg, skip_offline_nodes)
-
-    if lib_env.is_corosync_conf_live:
-        communicator = lib_env.node_communicator()
         # disable qdevice
         lib_env.report_processor.process(
             reports.service_disable_started("corosync-qdevice")
@@ -330,6 +327,8 @@ def remove_device(lib_env, skip_offline_nodes=False):
                 skip_offline_nodes
             )
 
+    lib_env.push_corosync_conf(cfg, skip_offline_nodes)
+
 def _remove_device_model_net(lib_env, cluster_nodes, skip_offline_nodes):
     """
     remove configuration used by qdevice model net
diff --git a/pcs/lib/corosync/qdevice_net.py b/pcs/lib/corosync/qdevice_net.py
index 200e45a..fa44923 100644
--- a/pcs/lib/corosync/qdevice_net.py
+++ b/pcs/lib/corosync/qdevice_net.py
@@ -35,6 +35,9 @@ __qdevice_certutil = os.path.join(
     "corosync-qdevice-net-certutil"
 )
 
+class QnetdNotRunningException(Exception):
+    pass
+
 def qdevice_setup(runner):
     """
     initialize qdevice on local host
@@ -79,10 +82,10 @@ def qdevice_status_generic_text(runner, verbose=False):
     get qdevice runtime status in plain text
     bool verbose get more detailed output
     """
-    cmd = [__qnetd_tool, "-s"]
+    args = ["-s"]
     if verbose:
-        cmd.append("-v")
-    stdout, stderr, retval = runner.run(cmd)
+        args.append("-v")
+    stdout, stderr, retval = _qdevice_run_tool(runner, args)
     if retval != 0:
         raise LibraryError(
             reports.qdevice_get_status_error(
@@ -98,12 +101,12 @@ def qdevice_status_cluster_text(runner, cluster=None, verbose=False):
     bool verbose get more detailed output
     string cluster show information only about specified cluster
     """
-    cmd = [__qnetd_tool, "-l"]
+    args = ["-l"]
     if verbose:
-        cmd.append("-v")
+        args.append("-v")
     if cluster:
-        cmd.extend(["-c", cluster])
-    stdout, stderr, retval = runner.run(cmd)
+        args.extend(["-c", cluster])
+    stdout, stderr, retval = _qdevice_run_tool(runner, args)
     if retval != 0:
         raise LibraryError(
             reports.qdevice_get_status_error(
@@ -114,6 +117,10 @@ def qdevice_status_cluster_text(runner, cluster=None, verbose=False):
     return stdout
 
 def qdevice_connected_clusters(status_cluster_text):
+    """
+    parse qnetd cluster status listing and return connected clusters' names
+    string status_cluster_text output of corosync-qnetd-tool -l
+    """
     connected_clusters = []
     regexp = re.compile(r'^Cluster "(?P<cluster>[^"]+)":$')
     for line in status_cluster_text.splitlines():
@@ -122,6 +129,17 @@ def qdevice_connected_clusters(status_cluster_text):
             connected_clusters.append(match.group("cluster"))
     return connected_clusters
 
+def _qdevice_run_tool(runner, args):
+    """
+    run corosync-qnetd-tool, raise QnetdNotRunningException if qnetd not running
+    CommandRunner runner
+    iterable args corosync-qnetd-tool arguments
+    """
+    stdout, stderr, retval = runner.run([__qnetd_tool] + args)
+    if retval == 3 and "is qnetd running?" in stderr.lower():
+        raise QnetdNotRunningException()
+    return stdout, stderr, retval
+
 def qdevice_enable(runner):
     """
     make qdevice start automatically on boot on local host
diff --git a/pcs/lib/reports.py b/pcs/lib/reports.py
index b9e9a66..cff491c 100644
--- a/pcs/lib/reports.py
+++ b/pcs/lib/reports.py
@@ -842,6 +842,19 @@ def qdevice_destroy_error(model, reason):
         }
     )
 
+def qdevice_not_running(model):
+    """
+    qdevice is expected to be running but is not running
+    string model qdevice model
+    """
+    return ReportItem.error(
+        report_codes.QDEVICE_NOT_RUNNING,
+        "Quorum device '{model}' is not running",
+        info={
+            "model": model,
+        }
+    )
+
 def qdevice_get_status_error(model, reason):
     """
     unable to get runtime status of qdevice
-- 
1.8.3.1