Blame SOURCES/bz1488044-01-fix-pcs-cluster-cib-push-for-old-feature-set.patch

be1b1f
From e8d95b4ba03e62658ece669d6389b71b8553df1f Mon Sep 17 00:00:00 2001
be1b1f
From: Ivan Devat <idevat@redhat.com>
be1b1f
Date: Wed, 8 Aug 2018 13:48:24 +0200
be1b1f
Subject: [PATCH] fix pcs cluster cib-push for old feature set
be1b1f
be1b1f
---
be1b1f
 pcs/cluster.py                 | 56 +++++++++++++++++++++++++++++++++++++-----
be1b1f
 pcs/lib/cib/test/test_tools.py | 29 ++++++++++++++++++++++
be1b1f
 pcs/lib/cib/tools.py           |  6 ++---
be1b1f
 pcs/lib/env.py                 | 10 ++++++--
be1b1f
 4 files changed, 90 insertions(+), 11 deletions(-)
be1b1f
be1b1f
diff --git a/pcs/cluster.py b/pcs/cluster.py
be1b1f
index b4d49d27..e8c94ab8 100644
be1b1f
--- a/pcs/cluster.py
be1b1f
+++ b/pcs/cluster.py
be1b1f
@@ -35,6 +35,7 @@ from pcs import (
be1b1f
 )
be1b1f
 from pcs.utils import parallel_for_nodes
be1b1f
 from pcs.common import report_codes
be1b1f
+from pcs.common.tools import Version
be1b1f
 from pcs.cli.common.errors import (
be1b1f
     CmdLineInputError,
be1b1f
     ERR_NODE_LIST_AND_ALL_MUTUALLY_EXCLUSIVE,
be1b1f
@@ -46,6 +47,7 @@ from pcs.lib import (
be1b1f
     reports as lib_reports,
be1b1f
 )
be1b1f
 from pcs.lib.booth import sync as booth_sync
be1b1f
+from pcs.lib.cib.tools import VERSION_FORMAT
be1b1f
 from pcs.lib.commands.remote_node import _share_authkey, _destroy_pcmk_remote_env
be1b1f
 from pcs.lib.commands.quorum import _add_device_model_net
be1b1f
 from pcs.lib.communication.corosync import CheckCorosyncOffline
be1b1f
@@ -74,6 +76,7 @@ from pcs.lib.external import (
be1b1f
     NodeCommunicationException,
be1b1f
     node_communicator_exception_to_report_item,
be1b1f
 )
be1b1f
+from pcs.lib.env import  MIN_FEATURE_SET_VERSION_FOR_DIFF
be1b1f
 from pcs.lib.env_tools import get_nodes
be1b1f
 from pcs.lib.node import NodeAddresses
be1b1f
 from pcs.lib import node_communication_format
be1b1f
@@ -1566,21 +1569,62 @@ def cluster_push(argv):
be1b1f
 
be1b1f
     if diff_against:
be1b1f
         try:
be1b1f
-            xml.dom.minidom.parse(diff_against)
be1b1f
+            original_cib = xml.dom.minidom.parse(diff_against)
be1b1f
         except (EnvironmentError, xml.parsers.expat.ExpatError) as e:
be1b1f
             utils.err("unable to parse original cib: %s" % e)
be1b1f
+
be1b1f
+        def unable_to_diff(reason):
be1b1f
+            return error(
be1b1f
+                "unable to diff against original cib '{0}': {1}"
be1b1f
+                .format(diff_against, reason)
be1b1f
+            )
be1b1f
+
be1b1f
+        cib_element_list = original_cib.getElementsByTagName("cib")
be1b1f
+
be1b1f
+        if len(cib_element_list) != 1:
be1b1f
+            raise unable_to_diff("there is not exactly one 'cib' element")
be1b1f
+
be1b1f
+        crm_feature_set = cib_element_list[0].getAttribute("crm_feature_set")
be1b1f
+        if not crm_feature_set:
be1b1f
+            raise unable_to_diff(
be1b1f
+                "the 'cib' element is missing 'crm_feature_set' value"
be1b1f
+            )
be1b1f
+
be1b1f
+        match = re.match(VERSION_FORMAT, crm_feature_set)
be1b1f
+        if not match:
be1b1f
+            raise unable_to_diff(
be1b1f
+                "the attribute 'crm_feature_set' of the element 'cib' has an"
be1b1f
+                " invalid value: '{0}'".format(crm_feature_set)
be1b1f
+            )
be1b1f
+        crm_feature_set_version = Version(
be1b1f
+            int(match.group("major")),
be1b1f
+            int(match.group("minor")),
be1b1f
+            int(match.group("rev")) if match.group("rev") else None
be1b1f
+        )
be1b1f
+
be1b1f
+        if crm_feature_set_version < MIN_FEATURE_SET_VERSION_FOR_DIFF:
be1b1f
+            raise unable_to_diff(
be1b1f
+                (
be1b1f
+                    "the 'crm_feature_set' version is '{0}'"
be1b1f
+                    " but at least version '{1}' is required"
be1b1f
+                ).format(
be1b1f
+                    crm_feature_set_version,
be1b1f
+                    MIN_FEATURE_SET_VERSION_FOR_DIFF,
be1b1f
+                )
be1b1f
+            )
be1b1f
+
be1b1f
         runner = utils.cmd_runner()
be1b1f
         command = [
be1b1f
             "crm_diff", "--original", diff_against, "--new", filename,
be1b1f
             "--no-version"
be1b1f
         ]
be1b1f
-        patch, error, dummy_retval = runner.run(command)
be1b1f
+        patch, stderr, dummy_retval = runner.run(command)
be1b1f
         # dummy_retval == 1 means one of two things:
be1b1f
         # a) an error has occured
be1b1f
         # b) --original and --new differ
be1b1f
         # therefore it's of no use to see if an error occurred
be1b1f
-        if error.strip():
be1b1f
-            utils.err("unable to diff the CIBs:\n" + error)
be1b1f
+        if stderr.strip():
be1b1f
+            utils.err("unable to diff the CIBs:\n" + stderr)
be1b1f
         if not patch.strip():
be1b1f
             print(
be1b1f
                 "The new CIB is the same as the original CIB, nothing to push."
be1b1f
@@ -1588,9 +1632,9 @@ def cluster_push(argv):
be1b1f
             sys.exit(0)
be1b1f
 
be1b1f
         command = ["cibadmin", "--patch", "--xml-pipe"]
be1b1f
-        output, error, retval = runner.run(command, patch)
be1b1f
+        output, stderr, retval = runner.run(command, patch)
be1b1f
         if retval != 0:
be1b1f
-            utils.err("unable to push cib\n" + error + output)
be1b1f
+            utils.err("unable to push cib\n" + stderr + output)
be1b1f
 
be1b1f
     else:
be1b1f
         command = ["cibadmin", "--replace", "--xml-file", filename]
be1b1f
diff --git a/pcs/lib/cib/test/test_tools.py b/pcs/lib/cib/test/test_tools.py
be1b1f
index fab39ce7..2bdc7695 100644
be1b1f
--- a/pcs/lib/cib/test/test_tools.py
be1b1f
+++ b/pcs/lib/cib/test/test_tools.py
be1b1f
@@ -436,6 +436,21 @@ class GetPacemakerVersionByWhichCibWasValidatedTest(TestCase):
be1b1f
             )
be1b1f
         )
be1b1f
 
be1b1f
+    def test_invalid_version_at_end(self):
be1b1f
+        assert_raise_library_error(
be1b1f
+            lambda: lib.get_pacemaker_version_by_which_cib_was_validated(
be1b1f
+                etree.XML('<cib validate-with="pacemaker-1.2.3x"/>')
be1b1f
+            ),
be1b1f
+            (
be1b1f
+                severities.ERROR,
be1b1f
+                report_codes.CIB_LOAD_ERROR_BAD_FORMAT,
be1b1f
+                {
be1b1f
+                    "reason": "the attribute 'validate-with' of the element"
be1b1f
+                        " 'cib' has an invalid value: 'pacemaker-1.2.3x'"
be1b1f
+                }
be1b1f
+            )
be1b1f
+        )
be1b1f
+
be1b1f
     def test_no_revision(self):
be1b1f
         self.assertEqual(
be1b1f
             Version(1, 2),
be1b1f
@@ -507,6 +522,20 @@ class getCibCrmFeatureSet(TestCase):
be1b1f
             )
be1b1f
         )
be1b1f
 
be1b1f
+    def test_invalid_version_at_end(self):
be1b1f
+        assert_raise_library_error(
be1b1f
+            lambda: lib.get_cib_crm_feature_set(
be1b1f
+                etree.XML('<cib crm_feature_set="3.0.9x" />')
be1b1f
+            ),
be1b1f
+            fixture.error(
be1b1f
+                report_codes.CIB_LOAD_ERROR_BAD_FORMAT,
be1b1f
+                reason=(
be1b1f
+                    "the attribute 'crm_feature_set' of the element 'cib' has "
be1b1f
+                    "an invalid value: '3.0.9x'"
be1b1f
+                )
be1b1f
+            )
be1b1f
+        )
be1b1f
+
be1b1f
 
be1b1f
 find_group = partial(lib.find_element_by_tag_and_id, "group")
be1b1f
 class FindTagWithId(TestCase):
be1b1f
diff --git a/pcs/lib/cib/tools.py b/pcs/lib/cib/tools.py
be1b1f
index 2cff96f3..ab2a9df5 100644
be1b1f
--- a/pcs/lib/cib/tools.py
be1b1f
+++ b/pcs/lib/cib/tools.py
be1b1f
@@ -16,7 +16,7 @@ from pcs.lib.pacemaker.values import (
be1b1f
 )
be1b1f
 from pcs.lib.xml_tools import get_root, get_sub_element
be1b1f
 
be1b1f
-_VERSION_FORMAT = r"(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<rev>\d+))?"
be1b1f
+VERSION_FORMAT = r"(?P<major>\d+)\.(?P<minor>\d+)(\.(?P<rev>\d+))?$"
be1b1f
 
be1b1f
 class IdProvider(object):
be1b1f
     """
be1b1f
@@ -289,7 +289,7 @@ def get_pacemaker_version_by_which_cib_was_validated(cib):
be1b1f
     return _get_cib_version(
be1b1f
         cib,
be1b1f
         "validate-with",
be1b1f
-        re.compile(r"pacemaker-{0}".format(_VERSION_FORMAT))
be1b1f
+        re.compile(r"pacemaker-{0}".format(VERSION_FORMAT))
be1b1f
     )
be1b1f
 
be1b1f
 def get_cib_crm_feature_set(cib, none_if_missing=False):
be1b1f
@@ -303,6 +303,6 @@ def get_cib_crm_feature_set(cib, none_if_missing=False):
be1b1f
     return _get_cib_version(
be1b1f
         cib,
be1b1f
         "crm_feature_set",
be1b1f
-        re.compile(_VERSION_FORMAT),
be1b1f
+        re.compile(r"^{0}".format(VERSION_FORMAT)),
be1b1f
         none_if_missing=none_if_missing
be1b1f
     )
be1b1f
diff --git a/pcs/lib/env.py b/pcs/lib/env.py
be1b1f
index 86f67b64..3b2c06b6 100644
be1b1f
--- a/pcs/lib/env.py
be1b1f
+++ b/pcs/lib/env.py
be1b1f
@@ -57,6 +57,8 @@ from pcs.lib.pacemaker.values import get_valid_timeout_seconds
be1b1f
 from pcs.lib.tools import write_tmpfile
be1b1f
 from pcs.lib.xml_tools import etree_to_str
be1b1f
 
be1b1f
+MIN_FEATURE_SET_VERSION_FOR_DIFF = Version(3, 0, 9)
be1b1f
+
be1b1f
 class LibraryEnvironment(object):
be1b1f
     # pylint: disable=too-many-instance-attributes
be1b1f
 
be1b1f
@@ -211,10 +213,14 @@ class LibraryEnvironment(object):
be1b1f
         # only check the version if a CIB has been loaded, otherwise the push
be1b1f
         # fails anyway. By my testing it seems that only the source CIB's
be1b1f
         # version matters.
be1b1f
-        if self.__loaded_cib_diff_source_feature_set < Version(3, 0, 9):
be1b1f
+        if(
be1b1f
+            self.__loaded_cib_diff_source_feature_set
be1b1f
+            <
be1b1f
+            MIN_FEATURE_SET_VERSION_FOR_DIFF
be1b1f
+        ):
be1b1f
             self.report_processor.process(
be1b1f
                 reports.cib_push_forced_full_due_to_crm_feature_set(
be1b1f
-                    Version(3, 0, 9),
be1b1f
+                    MIN_FEATURE_SET_VERSION_FOR_DIFF,
be1b1f
                     self.__loaded_cib_diff_source_feature_set
be1b1f
                 )
be1b1f
             )
be1b1f
-- 
be1b1f
2.13.6
be1b1f