Blob Blame History Raw
From 5921099626e3afde044027ed493bdee905db4415 Mon Sep 17 00:00:00 2001
From: Tomas Jelinek <tojeline@redhat.com>
Date: Thu, 21 Jul 2016 13:58:41 +0200
Subject: [PATCH] fix filter by property name in "pcs property show"

---
 pcs/prop.py                 |  14 +--
 pcs/test/test_properties.py | 263 ++++++++++++++++++++++++++++++++++----------
 pcs/utils.py                |  13 ++-
 3 files changed, 223 insertions(+), 67 deletions(-)

diff --git a/pcs/prop.py b/pcs/prop.py
index 36eba60..92a953c 100644
--- a/pcs/prop.py
+++ b/pcs/prop.py
@@ -100,9 +100,7 @@ def unset_property(argv):
         utils.replace_cib_configuration(cib_dom)
 
 def list_property(argv):
-    print_all = False
-    if len(argv) == 0:
-        print_all = True
+    print_all = len(argv) == 0
 
     if "--all" in utils.pcs_options and "--defaults" in utils.pcs_options:
         utils.err("you cannot specify both --all and --defaults")
@@ -124,13 +122,15 @@ def list_property(argv):
     for prop,val in sorted(properties.items()):
         print(" " + prop + ": " + val)
 
-    node_attributes = utils.get_node_attributes()
+    node_attributes = utils.get_node_attributes(
+        filter_attr=(None if print_all else argv[0])
+    )
     if node_attributes:
         print("Node Attributes:")
-        for node in sorted(node_attributes):
+        for node in sorted(node_attributes.keys()):
             line_parts = [" " + node + ":"]
-            for attr in node_attributes[node]:
-                line_parts.append(attr)
+            for name, value in sorted(node_attributes[node].items()):
+                line_parts.append("{0}={1}".format(name, value))
             print(" ".join(line_parts))
 
 def get_default_properties():
diff --git a/pcs/test/test_properties.py b/pcs/test/test_properties.py
index 6cdd2e5..fbaf880 100644
--- a/pcs/test/test_properties.py
+++ b/pcs/test/test_properties.py
@@ -8,11 +8,15 @@ from __future__ import (
 import shutil
 import unittest
 
+from pcs.test.tools.assertions import AssertPcsMixin
 from pcs.test.tools.misc import (
     ac,
     get_test_resource as rc,
 )
-from pcs.test.tools.pcs_runner import pcs
+from pcs.test.tools.pcs_runner import (
+    pcs,
+    PcsRunner,
+)
 
 from pcs import utils
 
@@ -66,61 +70,6 @@ class PropertyTest(unittest.TestCase):
         assert "stonith-enabled: false" in output
         assert output.startswith('Cluster Properties:\n batch-limit')
 
-    def testNodeProperties(self):
-        utils.usefile = True
-        utils.filename = temp_cib
-        o,r = utils.run(["cibadmin","-M", '--xml-text', '<nodes><node id="1" uname="rh7-1"><instance_attributes id="nodes-1"/></node><node id="2" uname="rh7-2"><instance_attributes id="nodes-2"/></node></nodes>'])
-        ac(o,"")
-        assert r == 0
-
-        o,r = pcs("property set --node=rh7-1 IP=192.168.1.1")
-        ac(o,"")
-        assert r==0
-
-        o,r = pcs("property set --node=rh7-2 IP=192.168.2.2")
-        ac(o,"")
-        assert r==0
-
-        o,r = pcs("property")
-        ac(o,"Cluster Properties:\nNode Attributes:\n rh7-1: IP=192.168.1.1\n rh7-2: IP=192.168.2.2\n")
-        assert r==0
-
-        o,r = pcs("property set --node=rh7-2 IP=")
-        ac(o,"")
-        assert r==0
-
-        o,r = pcs("property")
-        ac(o,"Cluster Properties:\nNode Attributes:\n rh7-1: IP=192.168.1.1\n")
-        assert r==0
-
-        o,r = pcs("property set --node=rh7-1 IP=192.168.1.1")
-        ac(o,"")
-        assert r==0
-
-        o,r = pcs("property set --node=rh7-2 IP=192.168.2.2")
-        ac(o,"")
-        assert r==0
-
-        o,r = pcs("property")
-        ac(o,"Cluster Properties:\nNode Attributes:\n rh7-1: IP=192.168.1.1\n rh7-2: IP=192.168.2.2\n")
-        assert r==0
-
-        o,r = pcs("property unset --node=rh7-1 IP")
-        ac(o,"")
-        assert r==0
-
-        o,r = pcs("property")
-        ac(o,"Cluster Properties:\nNode Attributes:\n rh7-2: IP=192.168.2.2\n")
-        assert r==0
-
-        o,r = pcs("property unset --node=rh7-1 IP")
-        ac(o,"Error: attribute: 'IP' doesn't exist for node: 'rh7-1'\n")
-        assert r==2
-
-        o,r = pcs("property unset --node=rh7-1 IP --force")
-        ac(o,"")
-        assert r==0
-
     def testBadProperties(self):
         o,r = pcs(temp_cib, "property set xxxx=zzzz")
         self.assertEqual(r, 1)
@@ -329,3 +278,205 @@ class PropertyTest(unittest.TestCase):
  default-resource-stickiness: 0.1
 """
         )
+
+
+class NodePropertyTestBase(unittest.TestCase, AssertPcsMixin):
+    def setUp(self):
+        shutil.copy(empty_cib, temp_cib)
+        self.pcs_runner = PcsRunner(temp_cib)
+
+    def fixture_nodes(self, nodes, attrs=None):
+        attrs = dict() if attrs is None else attrs
+        xml_lines = ['<nodes>']
+        for node_id, node_name in enumerate(nodes, 1):
+            xml_lines.extend([
+                '<node id="{0}" uname="{1}">'.format(node_id, node_name),
+                '<instance_attributes id="nodes-{0}">'.format(node_id),
+            ])
+            nv = '<nvpair id="nodes-{id}-{name}" name="{name}" value="{val}"/>'
+            for name, value in attrs.get(node_name, dict()).items():
+                xml_lines.append(nv.format(id=node_id, name=name, val=value))
+            xml_lines.extend([
+                '</instance_attributes>',
+                '</node>'
+            ])
+        xml_lines.append('</nodes>')
+
+        utils.usefile = True
+        utils.filename = temp_cib
+        output, retval = utils.run([
+            "cibadmin", "--modify", '--xml-text', "\n".join(xml_lines)
+        ])
+        assert output == ""
+        assert retval == 0
+
+class NodePropertyShowTest(NodePropertyTestBase):
+    def test_empty(self):
+        self.fixture_nodes(["rh7-1", "rh7-2"])
+        self.assert_pcs_success(
+            "property",
+            "Cluster Properties:\n"
+        )
+
+    def test_nonempty(self):
+        self.fixture_nodes(
+            ["rh7-1", "rh7-2"],
+            {
+                "rh7-1": {"IP": "192.168.1.1", },
+                "rh7-2": {"IP": "192.168.1.2", },
+            }
+        )
+        self.assert_pcs_success(
+            "property",
+            """\
+Cluster Properties:
+Node Attributes:
+ rh7-1: IP=192.168.1.1
+ rh7-2: IP=192.168.1.2
+"""
+        )
+
+    def test_multiple_per_node(self):
+        self.fixture_nodes(
+            ["rh7-1", "rh7-2"],
+            {
+                "rh7-1": {"IP": "192.168.1.1", "alias": "node1", },
+                "rh7-2": {"IP": "192.168.1.2", "alias": "node2", },
+            }
+        )
+        self.assert_pcs_success(
+            "property",
+            """\
+Cluster Properties:
+Node Attributes:
+ rh7-1: IP=192.168.1.1 alias=node1
+ rh7-2: IP=192.168.1.2 alias=node2
+"""
+        )
+
+    def test_name_filter_not_exists(self):
+        self.fixture_nodes(
+            ["rh7-1", "rh7-2"],
+            {
+                "rh7-1": {"IP": "192.168.1.1", },
+                "rh7-2": {"IP": "192.168.1.2", },
+            }
+        )
+        self.assert_pcs_success(
+            "property show alias",
+            """\
+Cluster Properties:
+"""
+        )
+
+    def test_name_filter_exists(self):
+        self.fixture_nodes(
+            ["rh7-1", "rh7-2"],
+            {
+                "rh7-1": {"IP": "192.168.1.1", "alias": "node1", },
+                "rh7-2": {"IP": "192.168.1.2", },
+            }
+        )
+        self.assert_pcs_success(
+            "property show alias",
+            """\
+Cluster Properties:
+Node Attributes:
+ rh7-1: alias=node1
+"""
+        )
+
+class NodePropertySetTest(NodePropertyTestBase):
+    def test_set_new(self):
+        self.fixture_nodes(["rh7-1", "rh7-2"])
+        self.assert_pcs_success(
+            "property set --node=rh7-1 IP=192.168.1.1"
+        )
+        self.assert_pcs_success(
+            "property",
+            """\
+Cluster Properties:
+Node Attributes:
+ rh7-1: IP=192.168.1.1
+"""
+        )
+        self.assert_pcs_success(
+            "property set --node=rh7-2 IP=192.168.1.2"
+        )
+        self.assert_pcs_success(
+            "property",
+            """\
+Cluster Properties:
+Node Attributes:
+ rh7-1: IP=192.168.1.1
+ rh7-2: IP=192.168.1.2
+"""
+        )
+
+    def test_set_existing(self):
+        self.fixture_nodes(
+            ["rh7-1", "rh7-2"],
+            {
+                "rh7-1": {"IP": "192.168.1.1", },
+                "rh7-2": {"IP": "192.168.1.2", },
+            }
+        )
+        self.assert_pcs_success(
+            "property set --node=rh7-2 IP=192.168.2.2"
+        )
+        self.assert_pcs_success(
+            "property",
+            """\
+Cluster Properties:
+Node Attributes:
+ rh7-1: IP=192.168.1.1
+ rh7-2: IP=192.168.2.2
+"""
+        )
+
+    def test_unset(self):
+        self.fixture_nodes(
+            ["rh7-1", "rh7-2"],
+            {
+                "rh7-1": {"IP": "192.168.1.1", },
+                "rh7-2": {"IP": "192.168.1.2", },
+            }
+        )
+        self.assert_pcs_success(
+            "property set --node=rh7-2 IP="
+        )
+        self.assert_pcs_success(
+            "property",
+            """\
+Cluster Properties:
+Node Attributes:
+ rh7-1: IP=192.168.1.1
+"""
+        )
+
+    def test_unset_nonexisting(self):
+        self.fixture_nodes(
+            ["rh7-1", "rh7-2"],
+            {
+                "rh7-1": {"IP": "192.168.1.1", },
+                "rh7-2": {"IP": "192.168.1.2", },
+            }
+        )
+        self.assert_pcs_result(
+            "property unset --node=rh7-1 missing",
+            "Error: attribute: 'missing' doesn't exist for node: 'rh7-1'\n",
+            returncode=2
+        )
+
+    def test_unset_nonexisting_forced(self):
+        self.fixture_nodes(
+            ["rh7-1", "rh7-2"],
+            {
+                "rh7-1": {"IP": "192.168.1.1", },
+                "rh7-2": {"IP": "192.168.1.2", },
+            }
+        )
+        self.assert_pcs_success(
+            "property unset --node=rh7-1 missing --force",
+            ""
+        )
diff --git a/pcs/utils.py b/pcs/utils.py
index 981a186..c7d1759 100644
--- a/pcs/utils.py
+++ b/pcs/utils.py
@@ -1659,19 +1659,24 @@ def set_unmanaged(resource):
             "is-managed", "--meta", "--parameter-value", "false"]
     return run(args)
 
-def get_node_attributes():
+def get_node_attributes(filter_node=None, filter_attr=None):
     node_config = get_cib_xpath("//nodes")
-    nas = {}
     if (node_config == ""):
         err("unable to get crm_config, is pacemaker running?")
     dom = parseString(node_config).documentElement
+    nas = dict()
     for node in dom.getElementsByTagName("node"):
         nodename = node.getAttribute("uname")
+        if filter_node is not None and nodename != filter_node:
+            continue
         for attributes in node.getElementsByTagName("instance_attributes"):
             for nvp in attributes.getElementsByTagName("nvpair"):
+                attr_name = nvp.getAttribute("name")
+                if filter_attr is not None and attr_name != filter_attr:
+                    continue
                 if nodename not in nas:
-                    nas[nodename] = []
-                nas[nodename].append(nvp.getAttribute("name") + "=" + nvp.getAttribute("value"))
+                    nas[nodename] = dict()
+                nas[nodename][attr_name] = nvp.getAttribute("value")
             break
     return nas
 
-- 
1.8.3.1