Blame SOURCES/bz1857295-01-Fix-tag-removal-in-resource-unclone-ungroup-commands.patch

1f701a
From 4a986e8ee0610b1c85a04e38042e4073d41207a4 Mon Sep 17 00:00:00 2001
1f701a
From: Miroslav Lisik <mlisik@redhat.com>
1f701a
Date: Mon, 13 Jul 2020 12:59:09 +0200
1f701a
Subject: [PATCH 2/3] Fix tag removal in resource 'unclone/ungroup' commands
1f701a
 and extend test coverage
1f701a
1f701a
---
1f701a
 pcs/resource.py                               |   2 +-
1f701a
 .../tier1/cib_resource/test_clone_unclone.py  |  73 +++++++--
1f701a
 .../tier1/cib_resource/test_group_ungroup.py  | 143 +++++++++++++++---
1f701a
 pcs_test/tools/cib.py                         |  10 +-
1f701a
 4 files changed, 187 insertions(+), 41 deletions(-)
1f701a
1f701a
diff --git a/pcs/resource.py b/pcs/resource.py
1f701a
index 9a3bd0ee..49d28ef0 100644
1f701a
--- a/pcs/resource.py
1f701a
+++ b/pcs/resource.py
1f701a
@@ -2027,7 +2027,7 @@ def remove_resource_references(
1f701a
         if obj_ref.getAttribute("id") == resource_id:
1f701a
             tag = obj_ref.parentNode
1f701a
             tag.removeChild(obj_ref)
1f701a
-            if tag.getElementsByTagName(obj_ref).length == 0:
1f701a
+            if tag.getElementsByTagName("obj_ref").length == 0:
1f701a
                 remove_resource_references(
1f701a
                     dom, tag.getAttribute("id"), output=output,
1f701a
                 )
1f701a
diff --git a/pcs_test/tier1/cib_resource/test_clone_unclone.py b/pcs_test/tier1/cib_resource/test_clone_unclone.py
1f701a
index c9c6a29e..2633801a 100644
1f701a
--- a/pcs_test/tier1/cib_resource/test_clone_unclone.py
1f701a
+++ b/pcs_test/tier1/cib_resource/test_clone_unclone.py
1f701a
@@ -55,6 +55,38 @@ FIXTURE_RESOURCES = """
1f701a
 )
1f701a
 
1f701a
 
1f701a
+FIXTURE_CONSTRAINTS_CONFIG_XML = """
1f701a
+    <constraints>
1f701a
+        
1f701a
+            rsc="C-clone" score="INFINITY"/>
1f701a
+        
1f701a
+            node="rh7-1" rsc="TagCloneOnly" score="INFINITY"/>
1f701a
+    </constraints>
1f701a
+"""
1f701a
+
1f701a
+
1f701a
+FIXTURE_TAGS_CONFIG_XML = """
1f701a
+    <tags>
1f701a
+        <tag id="TagCloneOnly">
1f701a
+            <obj_ref id="C-clone"/>
1f701a
+        </tag>
1f701a
+        <tag id="TagNotCloneOnly">
1f701a
+            <obj_ref id="C-clone"/>
1f701a
+            <obj_ref id="Dummy"/>
1f701a
+        </tag>
1f701a
+    </tags>
1f701a
+"""
1f701a
+
1f701a
+
1f701a
+FIXTURE_TAGS_RESULT_XML = """
1f701a
+    <tags>
1f701a
+        <tag id="TagNotCloneOnly">
1f701a
+            <obj_ref id="Dummy"/>
1f701a
+        </tag>
1f701a
+    </tags>
1f701a
+"""
1f701a
+
1f701a
+
1f701a
 class Unclone(
1f701a
     TestCase,
1f701a
     get_assert_pcs_effect_mixin(
1f701a
@@ -66,6 +98,22 @@ class Unclone(
1f701a
 ):
1f701a
     empty_cib = rc("cib-empty.xml")
1f701a
 
1f701a
+    def assert_tags_xml(self, expected_xml):
1f701a
+        self.assert_resources_xml_in_cib(
1f701a
+            expected_xml,
1f701a
+            get_cib_part_func=lambda cib: etree.tostring(
1f701a
+                etree.parse(cib).findall(".//tags")[0],
1f701a
+            ),
1f701a
+        )
1f701a
+
1f701a
+    def assert_constraint_xml(self, expected_xml):
1f701a
+        self.assert_resources_xml_in_cib(
1f701a
+            expected_xml,
1f701a
+            get_cib_part_func=lambda cib: etree.tostring(
1f701a
+                etree.parse(cib).findall(".//constraints")[0],
1f701a
+            ),
1f701a
+        )
1f701a
+
1f701a
     def setUp(self):
1f701a
         # pylint: disable=invalid-name
1f701a
         self.temp_cib = get_tmp_file("tier1_cib_resource_group_ungroup")
1f701a
@@ -75,18 +123,7 @@ class Unclone(
1f701a
             "resources", FIXTURE_CLONE, FIXTURE_DUMMY,
1f701a
         )
1f701a
         xml_manip.append_to_first_tag_name(
1f701a
-            "configuration",
1f701a
-            """
1f701a
-            <tags>
1f701a
-                <tag id="T1">
1f701a
-                    <obj_ref id="C-clone"/>
1f701a
-                    <obj_ref id="Dummy"/>
1f701a
-                </tag>
1f701a
-                <tag id="T2">
1f701a
-                    <obj_ref id="C-clone"/>
1f701a
-                </tag>
1f701a
-            </tags>
1f701a
-            """,
1f701a
+            "configuration", FIXTURE_TAGS_CONFIG_XML,
1f701a
         )
1f701a
         xml_manip.append_to_first_tag_name(
1f701a
             "constraints",
1f701a
@@ -95,8 +132,8 @@ class Unclone(
1f701a
                 rsc="C-clone" score="INFINITY"/>
1f701a
             """,
1f701a
             """
1f701a
-            
1f701a
-                score="INFINITY"/>
1f701a
+            
1f701a
+                node="rh7-1" rsc="TagCloneOnly" score="INFINITY"/>
1f701a
             """,
1f701a
         )
1f701a
         write_data_to_tmpfile(str(xml_manip), self.temp_cib)
1f701a
@@ -111,6 +148,8 @@ class Unclone(
1f701a
             "Error: could not find resource: NonExistentClone\n",
1f701a
         )
1f701a
         self.assert_resources_xml_in_cib(FIXTURE_CLONE_AND_RESOURCE)
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
1f701a
+        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)
1f701a
 
1f701a
     def test_not_clone_resource(self):
1f701a
         self.assert_pcs_fail(
1f701a
@@ -118,9 +157,15 @@ class Unclone(
1f701a
             "Error: 'Dummy' is not a clone resource\n",
1f701a
         )
1f701a
         self.assert_resources_xml_in_cib(FIXTURE_CLONE_AND_RESOURCE)
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
1f701a
+        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)
1f701a
 
1f701a
     def test_unclone_clone_id(self):
1f701a
         self.assert_effect("resource unclone C-clone", FIXTURE_RESOURCES)
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
1f701a
+        self.assert_constraint_xml("<constraints/>")
1f701a
 
1f701a
     def test_unclone_resoruce_id(self):
1f701a
         self.assert_effect("resource unclone C", FIXTURE_RESOURCES)
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
1f701a
+        self.assert_constraint_xml("<constraints/>")
1f701a
diff --git a/pcs_test/tier1/cib_resource/test_group_ungroup.py b/pcs_test/tier1/cib_resource/test_group_ungroup.py
1f701a
index f86e9890..88cc315d 100644
1f701a
--- a/pcs_test/tier1/cib_resource/test_group_ungroup.py
1f701a
+++ b/pcs_test/tier1/cib_resource/test_group_ungroup.py
1f701a
@@ -64,14 +64,63 @@ FIXTURE_AGROUP_XML = fixture_group_xml(
1f701a
 )
1f701a
 
1f701a
 
1f701a
-class TestGroupMixin(
1f701a
-    get_assert_pcs_effect_mixin(
1f701a
-        lambda cib: etree.tostring(
1f701a
-            # pylint:disable=undefined-variable
1f701a
-            etree.parse(cib).findall(".//resources")[0]
1f701a
-        )
1f701a
-    ),
1f701a
-):
1f701a
+FIXTURE_CONSTRAINTS_CONFIG_XML = """
1f701a
+    <constraints>
1f701a
+        
1f701a
+            rsc="AGroup" score="INFINITY"/>
1f701a
+        
1f701a
+            node="rh7-1" rsc="TagGroupOnly" score="INFINITY"/>
1f701a
+    </constraints>
1f701a
+"""
1f701a
+
1f701a
+FIXTURE_CLONE_TAG_CONSTRAINTS = """
1f701a
+    <constraints>
1f701a
+        
1f701a
+            rsc="AGroup-clone" score="INFINITY"
1f701a
+        />
1f701a
+        
1f701a
+            node="rh7-1" rsc="TagGroupOnly" score="INFINITY"
1f701a
+        />
1f701a
+    </constraints>
1f701a
+"""
1f701a
+
1f701a
+
1f701a
+FIXTURE_CLONE_CONSTRAINT = """
1f701a
+    <constraints>
1f701a
+        
1f701a
+            rsc="AGroup-clone" score="INFINITY"
1f701a
+        />
1f701a
+    </constraints>
1f701a
+"""
1f701a
+
1f701a
+
1f701a
+FIXTURE_TAGS_CONFIG_XML = """
1f701a
+    <tags>
1f701a
+        <tag id="TagGroupOnly">
1f701a
+            <obj_ref id="AGroup"/>
1f701a
+        </tag>
1f701a
+        <tag id="TagNotGroupOnly">
1f701a
+            <obj_ref id="AGroup"/>
1f701a
+            <obj_ref id="A1"/>
1f701a
+            <obj_ref id="A2"/>
1f701a
+            <obj_ref id="A3"/>
1f701a
+        </tag>
1f701a
+    </tags>
1f701a
+"""
1f701a
+
1f701a
+
1f701a
+FIXTURE_TAGS_RESULT_XML = """
1f701a
+    <tags>
1f701a
+        <tag id="TagNotGroupOnly">
1f701a
+            <obj_ref id="A1"/>
1f701a
+            <obj_ref id="A2"/>
1f701a
+            <obj_ref id="A3"/>
1f701a
+        </tag>
1f701a
+    </tags>
1f701a
+"""
1f701a
+
1f701a
+
1f701a
+class TestGroupMixin:
1f701a
     empty_cib = rc("cib-empty.xml")
1f701a
 
1f701a
     def setUp(self):
1f701a
@@ -81,17 +130,7 @@ class TestGroupMixin(
1f701a
         xml_manip = XmlManipulation.from_file(self.empty_cib)
1f701a
         xml_manip.append_to_first_tag_name("resources", FIXTURE_AGROUP_XML)
1f701a
         xml_manip.append_to_first_tag_name(
1f701a
-            "configuration",
1f701a
-            """
1f701a
-            <tags>
1f701a
-                <tag id="T1">
1f701a
-                    <obj_ref id="AGroup"/>
1f701a
-                </tag>
1f701a
-                <tag id="T2">
1f701a
-                    <obj_ref id="AGroup"/>
1f701a
-                </tag>
1f701a
-            </tags>
1f701a
-            """,
1f701a
+            "configuration", FIXTURE_TAGS_CONFIG_XML,
1f701a
         )
1f701a
         xml_manip.append_to_first_tag_name(
1f701a
             "constraints",
1f701a
@@ -100,8 +139,8 @@ class TestGroupMixin(
1f701a
                 rsc="AGroup" score="INFINITY"/>
1f701a
             """,
1f701a
             """
1f701a
-            
1f701a
-                score="INFINITY"/>
1f701a
+            
1f701a
+                node="rh7-1" rsc="TagGroupOnly" score="INFINITY"/>
1f701a
             """,
1f701a
         )
1f701a
         write_data_to_tmpfile(str(xml_manip), self.temp_cib)
1f701a
@@ -111,9 +150,33 @@ class TestGroupMixin(
1f701a
         self.temp_cib.close()
1f701a
 
1f701a
 
1f701a
-class GroupDeleteRemoveUngroupBase(TestGroupMixin):
1f701a
+class GroupDeleteRemoveUngroupBase(
1f701a
+    get_assert_pcs_effect_mixin(
1f701a
+        lambda cib: etree.tostring(
1f701a
+            # pylint:disable=undefined-variable
1f701a
+            etree.parse(cib).findall(".//resources")[0]
1f701a
+        )
1f701a
+    ),
1f701a
+    TestGroupMixin,
1f701a
+):
1f701a
     command = None
1f701a
 
1f701a
+    def assert_tags_xml(self, expected_xml):
1f701a
+        self.assert_resources_xml_in_cib(
1f701a
+            expected_xml,
1f701a
+            get_cib_part_func=lambda cib: etree.tostring(
1f701a
+                etree.parse(cib).findall(".//tags")[0],
1f701a
+            ),
1f701a
+        )
1f701a
+
1f701a
+    def assert_constraint_xml(self, expected_xml):
1f701a
+        self.assert_resources_xml_in_cib(
1f701a
+            expected_xml,
1f701a
+            get_cib_part_func=lambda cib: etree.tostring(
1f701a
+                etree.parse(cib).findall(".//constraints")[0],
1f701a
+            ),
1f701a
+        )
1f701a
+
1f701a
     def test_nonexistent_group(self):
1f701a
         self.assert_pcs_fail(
1f701a
             f"resource {self.command} NonExistentGroup",
1f701a
@@ -122,6 +185,8 @@ class GroupDeleteRemoveUngroupBase(TestGroupMixin):
1f701a
         self.assert_resources_xml_in_cib(
1f701a
             fixture_resources_xml([FIXTURE_AGROUP_XML]),
1f701a
         )
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
1f701a
+        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)
1f701a
 
1f701a
     def test_not_a_group_id(self):
1f701a
         self.assert_pcs_fail(
1f701a
@@ -130,6 +195,8 @@ class GroupDeleteRemoveUngroupBase(TestGroupMixin):
1f701a
         self.assert_resources_xml_in_cib(
1f701a
             fixture_resources_xml([FIXTURE_AGROUP_XML]),
1f701a
         )
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
1f701a
+        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)
1f701a
 
1f701a
     def test_whole_group(self):
1f701a
         self.assert_effect(
1f701a
@@ -142,10 +209,12 @@ class GroupDeleteRemoveUngroupBase(TestGroupMixin):
1f701a
                 ],
1f701a
             ),
1f701a
             output=(
1f701a
-                "Removing Constraint - location-T1-rh7-1-INFINITY\n"
1f701a
+                "Removing Constraint - location-TagGroupOnly-rh7-1-INFINITY\n"
1f701a
                 "Removing Constraint - location-AGroup-rh7-1-INFINITY\n"
1f701a
             ),
1f701a
         )
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
1f701a
+        self.assert_constraint_xml("<constraints/>")
1f701a
 
1f701a
     def test_specified_resources(self):
1f701a
         self.assert_effect(
1f701a
@@ -160,6 +229,26 @@ class GroupDeleteRemoveUngroupBase(TestGroupMixin):
1f701a
                 ],
1f701a
             ),
1f701a
         )
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
1f701a
+        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)
1f701a
+
1f701a
+    def test_all_resources(self):
1f701a
+        self.assert_effect(
1f701a
+            f"resource {self.command} AGroup A1 A2 A3",
1f701a
+            fixture_resources_xml(
1f701a
+                [
1f701a
+                    fixture_primitive_xml("A1"),
1f701a
+                    fixture_primitive_xml("A2"),
1f701a
+                    fixture_primitive_xml("A3"),
1f701a
+                ],
1f701a
+            ),
1f701a
+            output=(
1f701a
+                "Removing Constraint - location-TagGroupOnly-rh7-1-INFINITY\n"
1f701a
+                "Removing Constraint - location-AGroup-rh7-1-INFINITY\n"
1f701a
+            ),
1f701a
+        )
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
1f701a
+        self.assert_constraint_xml("<constraints/>")
1f701a
 
1f701a
     def test_cloned_group(self):
1f701a
         self.assert_pcs_success("resource clone AGroup")
1f701a
@@ -172,6 +261,8 @@ class GroupDeleteRemoveUngroupBase(TestGroupMixin):
1f701a
                 [fixture_clone_xml("AGroup-clone", FIXTURE_AGROUP_XML)],
1f701a
             )
1f701a
         )
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
1f701a
+        self.assert_constraint_xml(FIXTURE_CLONE_TAG_CONSTRAINTS)
1f701a
 
1f701a
     def test_cloned_group_all_resorces_specified(self):
1f701a
         self.assert_pcs_success("resource clone AGroup")
1f701a
@@ -184,6 +275,8 @@ class GroupDeleteRemoveUngroupBase(TestGroupMixin):
1f701a
                 [fixture_clone_xml("AGroup-clone", FIXTURE_AGROUP_XML)],
1f701a
             )
1f701a
         )
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
1f701a
+        self.assert_constraint_xml(FIXTURE_CLONE_TAG_CONSTRAINTS)
1f701a
 
1f701a
     def test_cloned_group_with_one_resource(self):
1f701a
         self.assert_pcs_success("resource clone AGroup")
1f701a
@@ -199,8 +292,10 @@ class GroupDeleteRemoveUngroupBase(TestGroupMixin):
1f701a
                     fixture_primitive_xml("A2"),
1f701a
                 ],
1f701a
             ),
1f701a
-            output="Removing Constraint - location-T1-rh7-1-INFINITY\n",
1f701a
+            output="Removing Constraint - location-TagGroupOnly-rh7-1-INFINITY\n",
1f701a
         )
1f701a
+        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
1f701a
+        self.assert_constraint_xml(FIXTURE_CLONE_CONSTRAINT)
1f701a
 
1f701a
 
1f701a
 class ResourceUngroup(GroupDeleteRemoveUngroupBase, TestCase):
1f701a
diff --git a/pcs_test/tools/cib.py b/pcs_test/tools/cib.py
1f701a
index d52176cf..5eaaa92e 100644
1f701a
--- a/pcs_test/tools/cib.py
1f701a
+++ b/pcs_test/tools/cib.py
1f701a
@@ -30,8 +30,14 @@ def xml_format(xml_string):
1f701a
 
1f701a
 def get_assert_pcs_effect_mixin(get_cib_part):
1f701a
     class AssertPcsEffectMixin(AssertPcsMixin):
1f701a
-        def assert_resources_xml_in_cib(self, expected_xml_resources):
1f701a
-            xml = get_cib_part(self.temp_cib)
1f701a
+        def assert_resources_xml_in_cib(
1f701a
+            self, expected_xml_resources, get_cib_part_func=None,
1f701a
+        ):
1f701a
+            self.temp_cib.seek(0)
1f701a
+            if get_cib_part_func is not None:
1f701a
+                xml = get_cib_part_func(self.temp_cib)
1f701a
+            else:
1f701a
+                xml = get_cib_part(self.temp_cib)
1f701a
             try:
1f701a
                 assert_xml_equal(expected_xml_resources, xml.decode())
1f701a
             except AssertionError as e:
1f701a
-- 
1f701a
2.25.4
1f701a