Blob Blame History Raw
From d88962d655257940a678724cc8d7bc1008ed3a46 Mon Sep 17 00:00:00 2001
From: Tomas Jelinek <tojeline@redhat.com>
Date: Tue, 5 May 2020 11:02:36 +0200
Subject: [PATCH 1/3] fix running 'pcs status' on remote nodes

---
 pcs/lib/commands/status.py                 |  24 +++-
 pcs_test/tier0/lib/commands/test_status.py | 122 +++++++++++++++++++++
 2 files changed, 141 insertions(+), 5 deletions(-)

diff --git a/pcs/lib/commands/status.py b/pcs/lib/commands/status.py
index 26332a65..84e3e046 100644
--- a/pcs/lib/commands/status.py
+++ b/pcs/lib/commands/status.py
@@ -1,3 +1,4 @@
+import os.path
 from typing import (
     Iterable,
     List,
@@ -6,6 +7,7 @@ from typing import (
 )
 from xml.etree.ElementTree import Element
 
+from pcs import settings
 from pcs.common import file_type_codes
 from pcs.common.node_communicator import Communicator
 from pcs.common.reports import (
@@ -17,7 +19,7 @@ from pcs.common.tools import (
     indent,
 )
 from pcs.lib import reports
-from pcs.lib.cib import stonith
+from pcs.lib.cib import nvpair, stonith
 from pcs.lib.cib.tools import get_crm_config, get_resources
 from pcs.lib.communication.nodes import CheckReachability
 from pcs.lib.communication.tools import run as run_communication
@@ -57,6 +59,7 @@ def full_cluster_status_plaintext(
     """
     # pylint: disable=too-many-branches
     # pylint: disable=too-many-locals
+    # pylint: disable=too-many-statements
 
     # validation
     if not env.is_cib_live and env.is_corosync_conf_live:
@@ -84,7 +87,11 @@ def full_cluster_status_plaintext(
     status_text, warning_list = get_cluster_status_text(
         runner, hide_inactive_resources, verbose
     )
-    corosync_conf = env.get_corosync_conf()
+    corosync_conf = None
+    # If we are live on a remote node, we have no corosync.conf.
+    # TODO Use the new file framework so the path is not exposed.
+    if not live or os.path.exists(settings.corosync_conf_file):
+        corosync_conf = env.get_corosync_conf()
     cib = env.get_cib()
     if verbose:
         ticket_status_text, ticket_status_stderr, ticket_status_retval = (
@@ -97,7 +104,7 @@ def full_cluster_status_plaintext(
         except LibraryError:
             pass
         local_services_status = _get_local_services_status(runner)
-        if verbose:
+        if verbose and corosync_conf:
             node_name_list, node_names_report_list = get_existing_nodes_names(
                 corosync_conf
             )
@@ -117,8 +124,15 @@ def full_cluster_status_plaintext(
     if report_processor.has_errors:
         raise LibraryError()
 
+    cluster_name = (
+        corosync_conf.get_cluster_name()
+        if corosync_conf
+        else nvpair.get_value(
+            "cluster_property_set", get_crm_config(cib), "cluster-name", ""
+        )
+    )
     parts = []
-    parts.append(f"Cluster name: {corosync_conf.get_cluster_name()}")
+    parts.append(f"Cluster name: {cluster_name}")
     if warning_list:
         parts.extend(["", "WARNINGS:"] + warning_list + [""])
     parts.append(status_text)
@@ -136,7 +150,7 @@ def full_cluster_status_plaintext(
         else:
             parts.extend(indent(ticket_status_text.splitlines()))
     if live:
-        if verbose:
+        if verbose and corosync_conf:
             parts.extend(["", "PCSD Status:"])
             parts.extend(indent(
                 _format_node_reachability(node_name_list, node_reachability)
diff --git a/pcs_test/tier0/lib/commands/test_status.py b/pcs_test/tier0/lib/commands/test_status.py
index 06878668..7d54d579 100644
--- a/pcs_test/tier0/lib/commands/test_status.py
+++ b/pcs_test/tier0/lib/commands/test_status.py
@@ -1,6 +1,7 @@
 from textwrap import dedent
 from unittest import TestCase
 
+from pcs import settings
 from pcs.common import file_type_codes, report_codes
 from pcs.lib.commands import status
 from pcs_test.tools import fixture
@@ -9,16 +10,33 @@ from pcs_test.tools.misc import read_test_resource as rc_read
 
 
 class FullClusterStatusPlaintext(TestCase):
+    # pylint: disable=too-many-public-methods
     def setUp(self):
         self.env_assist, self.config = get_env_tools(self)
         self.node_name_list = ["node1", "node2", "node3"]
         self.maxDiff = None
 
+    @staticmethod
+    def _fixture_xml_clustername(name):
+        return """
+            <crm_config>
+                <cluster_property_set id="cib-bootstrap-options">
+                    <nvpair
+                        id="cib-bootstrap-options-cluster-name"
+                        name="cluster-name" value="{name}"
+                    />
+                </cluster_property_set>
+            </crm_config>
+            """.format(
+            name=name
+        )
+
     def _fixture_config_live_minimal(self):
         (self.config
             .runner.pcmk.load_state_plaintext(
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load()
             .runner.cib.load(resources="""
                 <resources>
@@ -30,6 +48,25 @@ class FullClusterStatusPlaintext(TestCase):
             )
         )
 
+    def _fixture_config_live_remote_minimal(self):
+        (
+            self.config.runner.pcmk.load_state_plaintext(
+                stdout="crm_mon cluster status",
+            )
+            .fs.exists(settings.corosync_conf_file, return_value=False)
+            .runner.cib.load(
+                optional_in_conf=self._fixture_xml_clustername("test-cib"),
+                resources="""
+                <resources>
+                    <primitive id="S" class="stonith" type="fence_dummy" />
+                </resources>
+            """,
+            )
+            .runner.systemctl.is_active(
+                "sbd", is_active=False, name="runner.systemctl.is_active.sbd"
+            )
+        )
+
     def _fixture_config_local_daemons(
         self,
         corosync_enabled=True, corosync_active=True,
@@ -150,6 +187,7 @@ class FullClusterStatusPlaintext(TestCase):
             .runner.pcmk.load_state_plaintext(
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load_content("invalid corosync conf")
         )
         self.env_assist.assert_raise_library_error(
@@ -170,6 +208,7 @@ class FullClusterStatusPlaintext(TestCase):
             .runner.pcmk.load_state_plaintext(
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load()
             .runner.cib.load_content(
                 "some stdout", stderr="cib load error", returncode=1
@@ -214,6 +253,7 @@ class FullClusterStatusPlaintext(TestCase):
                 verbose=True,
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load(node_name_list=self.node_name_list)
             .runner.cib.load(resources="""
                 <resources>
@@ -254,6 +294,82 @@ class FullClusterStatusPlaintext(TestCase):
             )
         )
 
+    def test_success_live_remote_node(self):
+        self._fixture_config_live_remote_minimal()
+        self._fixture_config_local_daemons(
+            corosync_enabled=False,
+            corosync_active=False,
+            pacemaker_enabled=False,
+            pacemaker_active=False,
+            pacemaker_remote_enabled=True,
+            pacemaker_remote_active=True,
+        )
+        self.assertEqual(
+            status.full_cluster_status_plaintext(self.env_assist.get_env()),
+            dedent(
+                """\
+                Cluster name: test-cib
+                crm_mon cluster status
+
+                Daemon Status:
+                  corosync: inactive/disabled
+                  pacemaker: inactive/disabled
+                  pacemaker_remote: active/enabled
+                  pcsd: active/enabled"""
+            ),
+        )
+
+    def test_success_live_remote_node_verbose(self):
+        (
+            self.config.runner.pcmk.can_fence_history_status(
+                stderr="not supported"
+            )
+            .runner.pcmk.load_state_plaintext(
+                verbose=True, stdout="crm_mon cluster status",
+            )
+            .fs.exists(settings.corosync_conf_file, return_value=False)
+            .runner.cib.load(
+                optional_in_conf=self._fixture_xml_clustername("test-cib"),
+                resources="""
+                <resources>
+                    <primitive id="S" class="stonith" type="fence_dummy" />
+                </resources>
+            """,
+            )
+            .runner.pcmk.load_ticket_state_plaintext(stdout="ticket status")
+            .runner.systemctl.is_active(
+                "sbd", is_active=False, name="runner.systemctl.is_active.sbd"
+            )
+        )
+        self._fixture_config_local_daemons(
+            corosync_enabled=False,
+            corosync_active=False,
+            pacemaker_enabled=False,
+            pacemaker_active=False,
+            pacemaker_remote_enabled=True,
+            pacemaker_remote_active=True,
+        )
+
+        self.assertEqual(
+            status.full_cluster_status_plaintext(
+                self.env_assist.get_env(), verbose=True
+            ),
+            dedent(
+                """\
+                Cluster name: test-cib
+                crm_mon cluster status
+
+                Tickets:
+                  ticket status
+
+                Daemon Status:
+                  corosync: inactive/disabled
+                  pacemaker: inactive/disabled
+                  pacemaker_remote: active/enabled
+                  pcsd: active/enabled"""
+            ),
+        )
+
     def test_succes_mocked(self):
         (self.config
             .env.set_corosync_conf_data(rc_read("corosync.conf"))
@@ -316,6 +432,7 @@ class FullClusterStatusPlaintext(TestCase):
                 fence_history=True,
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load(node_name_list=self.node_name_list)
             .runner.cib.load(resources="""
                 <resources>
@@ -365,6 +482,7 @@ class FullClusterStatusPlaintext(TestCase):
                 verbose=True,
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load(node_name_list=self.node_name_list)
             .runner.cib.load(resources="""
                 <resources>
@@ -421,6 +539,7 @@ class FullClusterStatusPlaintext(TestCase):
             .runner.pcmk.load_state_plaintext(
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load()
             .runner.cib.load()
             .runner.systemctl.is_active(
@@ -453,6 +572,7 @@ class FullClusterStatusPlaintext(TestCase):
             .runner.pcmk.load_state_plaintext(
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load()
             .runner.cib.load()
             .runner.systemctl.is_active(
@@ -481,6 +601,7 @@ class FullClusterStatusPlaintext(TestCase):
             .runner.pcmk.load_state_plaintext(
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load()
             .runner.cib.load(resources="""
                 <resources>
@@ -539,6 +660,7 @@ class FullClusterStatusPlaintext(TestCase):
                 verbose=True,
                 stdout="crm_mon cluster status",
             )
+            .fs.exists(settings.corosync_conf_file, return_value=True)
             .corosync_conf.load(node_name_list=self.node_name_list)
             .runner.cib.load(resources="""
                 <resources>
-- 
2.25.4