Blame SOURCES/bz2050274-01-process-invalid-OCF-agents-the-same-way-as-before.patch

f5f42f
From ae3435418f0af6e5f22f463871aa90a5c5b2d15f Mon Sep 17 00:00:00 2001
f5f42f
From: Tomas Jelinek <tojeline@redhat.com>
f5f42f
Date: Fri, 4 Feb 2022 16:23:18 +0100
f5f42f
Subject: [PATCH 1/3] process invalid OCF agents as if they complied with OCF
f5f42f
 1.0
f5f42f
f5f42f
---
f5f42f
 pcs/common/reports/codes.py                   |   4 +-
f5f42f
 pcs/common/reports/messages.py                |  13 +-
f5f42f
 pcs/lib/commands/resource.py                  |   3 +-
f5f42f
 pcs/lib/commands/resource_agent.py            |   4 +-
f5f42f
 pcs/lib/commands/stonith.py                   |   3 +-
f5f42f
 pcs/lib/resource_agent/__init__.py            |   1 -
f5f42f
 pcs/lib/resource_agent/error.py               |  14 --
f5f42f
 pcs/lib/resource_agent/facade.py              |  37 ++-
f5f42f
 pcs/lib/resource_agent/xml.py                 |  15 +-
f5f42f
 .../tier0/common/reports/test_messages.py     |  18 +-
f5f42f
 .../tier0/lib/resource_agent/test_facade.py   |  47 ++++
f5f42f
 pcs_test/tier0/lib/resource_agent/test_xml.py | 226 ++++++++----------
f5f42f
 12 files changed, 201 insertions(+), 184 deletions(-)
f5f42f
f5f42f
diff --git a/pcs/common/reports/codes.py b/pcs/common/reports/codes.py
f5f42f
index 3e0512d9..e8dee00f 100644
f5f42f
--- a/pcs/common/reports/codes.py
f5f42f
+++ b/pcs/common/reports/codes.py
f5f42f
@@ -36,8 +36,8 @@ ADD_REMOVE_CANNOT_SPECIFY_ADJACENT_ITEM_WITHOUT_ITEMS_TO_ADD = M(
f5f42f
     "ADD_REMOVE_CANNOT_SPECIFY_ADJACENT_ITEM_WITHOUT_ITEMS_TO_ADD"
f5f42f
 )
f5f42f
 AGENT_GENERIC_ERROR = M("AGENT_GENERIC_ERROR")
f5f42f
-AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION = M(
f5f42f
-    "AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION"
f5f42f
+AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION_ASSUMED_VERSION = M(
f5f42f
+    "AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION_ASSUMED_VERSION"
f5f42f
 )
f5f42f
 AGENT_NAME_GUESS_FOUND_MORE_THAN_ONE = M("AGENT_NAME_GUESS_FOUND_MORE_THAN_ONE")
f5f42f
 AGENT_NAME_GUESS_FOUND_NONE = M("AGENT_NAME_GUESS_FOUND_NONE")
f5f42f
diff --git a/pcs/common/reports/messages.py b/pcs/common/reports/messages.py
f5f42f
index 9d665e73..7df1e1eb 100644
f5f42f
--- a/pcs/common/reports/messages.py
f5f42f
+++ b/pcs/common/reports/messages.py
f5f42f
@@ -3789,9 +3789,9 @@ class AgentNameGuessFoundNone(ReportItemMessage):
f5f42f
 
f5f42f
 
f5f42f
 @dataclass(frozen=True)
f5f42f
-class AgentImplementsUnsupportedOcfVersion(ReportItemMessage):
f5f42f
+class AgentImplementsUnsupportedOcfVersionAssumedVersion(ReportItemMessage):
f5f42f
     """
f5f42f
-    Specified agent implements OCF version not supported by pcs
f5f42f
+    Specified agent implements OCF version not supported by pcs, assumed OCF 1.0
f5f42f
 
f5f42f
     agent -- name of the agent
f5f42f
     ocf_version -- OCF version implemented by the agent
f5f42f
@@ -3801,7 +3801,8 @@ class AgentImplementsUnsupportedOcfVersion(ReportItemMessage):
f5f42f
     agent: str
f5f42f
     ocf_version: str
f5f42f
     supported_versions: List[str]
f5f42f
-    _code = codes.AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION
f5f42f
+    assumed_version: str
f5f42f
+    _code = codes.AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION_ASSUMED_VERSION
f5f42f
 
f5f42f
     @property
f5f42f
     def message(self) -> str:
f5f42f
@@ -3809,9 +3810,9 @@ class AgentImplementsUnsupportedOcfVersion(ReportItemMessage):
f5f42f
         _is = format_plural(self.supported_versions, "is")
f5f42f
         _version_list = format_list(self.supported_versions)
f5f42f
         return (
f5f42f
-            f"Unable to process agent '{self.agent}' as it implements "
f5f42f
-            f"unsupported OCF version '{self.ocf_version}', supported "
f5f42f
-            f"{_version} {_is}: {_version_list}"
f5f42f
+            f"Agent '{self.agent}' implements unsupported OCF version "
f5f42f
+            f"'{self.ocf_version}', supported {_version} {_is}: "
f5f42f
+            f"{_version_list}; assumed version '{self.assumed_version}'"
f5f42f
         )
f5f42f
 
f5f42f
 
f5f42f
diff --git a/pcs/lib/commands/resource.py b/pcs/lib/commands/resource.py
f5f42f
index 82ce73e0..c4b6252c 100644
f5f42f
--- a/pcs/lib/commands/resource.py
f5f42f
+++ b/pcs/lib/commands/resource.py
f5f42f
@@ -84,7 +84,6 @@ from pcs.lib.resource_agent import (
f5f42f
     ResourceAgentName,
f5f42f
     split_resource_agent_name,
f5f42f
     UnableToGetAgentMetadata,
f5f42f
-    UnsupportedOcfVersion,
f5f42f
 )
f5f42f
 from pcs.lib.tools import get_tmp_cib
f5f42f
 from pcs.lib.validate import ValueTimeInterval
f5f42f
@@ -162,7 +161,7 @@ def _get_agent_facade(
f5f42f
             else find_one_resource_agent_by_type(runner, report_processor, name)
f5f42f
         )
f5f42f
         return factory.facade_from_parsed_name(split_name)
f5f42f
-    except (UnableToGetAgentMetadata, UnsupportedOcfVersion) as e:
f5f42f
+    except UnableToGetAgentMetadata as e:
f5f42f
         if allow_absent_agent:
f5f42f
             report_processor.report(
f5f42f
                 resource_agent_error_to_report_item(
f5f42f
diff --git a/pcs/lib/commands/resource_agent.py b/pcs/lib/commands/resource_agent.py
f5f42f
index e6167b13..4a1831c0 100644
f5f42f
--- a/pcs/lib/commands/resource_agent.py
f5f42f
+++ b/pcs/lib/commands/resource_agent.py
f5f42f
@@ -139,7 +139,9 @@ def _complete_agent_list(
f5f42f
         try:
f5f42f
             split_name = split_resource_agent_name(name)
f5f42f
             metadata = (
f5f42f
-                agent_factory.facade_from_parsed_name(split_name).metadata
f5f42f
+                agent_factory.facade_from_parsed_name(
f5f42f
+                    split_name, report_warnings=False
f5f42f
+                ).metadata
f5f42f
                 if describe
f5f42f
                 else name_to_void_metadata(split_name)
f5f42f
             )
f5f42f
diff --git a/pcs/lib/commands/stonith.py b/pcs/lib/commands/stonith.py
f5f42f
index 093f5be9..2aa299d7 100644
f5f42f
--- a/pcs/lib/commands/stonith.py
f5f42f
+++ b/pcs/lib/commands/stonith.py
f5f42f
@@ -45,7 +45,6 @@ from pcs.lib.resource_agent import (
f5f42f
     ResourceAgentFacadeFactory,
f5f42f
     ResourceAgentName,
f5f42f
     UnableToGetAgentMetadata,
f5f42f
-    UnsupportedOcfVersion,
f5f42f
 )
f5f42f
 from pcs.lib.validate import validate_add_remove_items
f5f42f
 from pcs.lib.xml_tools import get_root
f5f42f
@@ -62,7 +61,7 @@ def _get_agent_facade(
f5f42f
             raise InvalidResourceAgentName(name)
f5f42f
         full_name = ResourceAgentName("stonith", None, name)
f5f42f
         return factory.facade_from_parsed_name(full_name)
f5f42f
-    except (UnableToGetAgentMetadata, UnsupportedOcfVersion) as e:
f5f42f
+    except UnableToGetAgentMetadata as e:
f5f42f
         if allow_absent_agent:
f5f42f
             report_processor.report(
f5f42f
                 resource_agent_error_to_report_item(
f5f42f
diff --git a/pcs/lib/resource_agent/__init__.py b/pcs/lib/resource_agent/__init__.py
f5f42f
index 4548017f..c6086331 100644
f5f42f
--- a/pcs/lib/resource_agent/__init__.py
f5f42f
+++ b/pcs/lib/resource_agent/__init__.py
f5f42f
@@ -10,7 +10,6 @@ from .error import (
f5f42f
     ResourceAgentError,
f5f42f
     resource_agent_error_to_report_item,
f5f42f
     UnableToGetAgentMetadata,
f5f42f
-    UnsupportedOcfVersion,
f5f42f
 )
f5f42f
 from .facade import ResourceAgentFacade, ResourceAgentFacadeFactory
f5f42f
 from .list import (
f5f42f
diff --git a/pcs/lib/resource_agent/error.py b/pcs/lib/resource_agent/error.py
f5f42f
index d4178333..f1dd7f3d 100644
f5f42f
--- a/pcs/lib/resource_agent/error.py
f5f42f
+++ b/pcs/lib/resource_agent/error.py
f5f42f
@@ -2,8 +2,6 @@ from typing import Iterable
f5f42f
 
f5f42f
 from pcs.common import reports
f5f42f
 
f5f42f
-from . import const
f5f42f
-
f5f42f
 
f5f42f
 class ResourceAgentError(Exception):
f5f42f
     def __init__(self, agent_name: str):
f5f42f
@@ -37,12 +35,6 @@ class UnableToGetAgentMetadata(ResourceAgentError):
f5f42f
         self.message = message
f5f42f
 
f5f42f
 
f5f42f
-class UnsupportedOcfVersion(ResourceAgentError):
f5f42f
-    def __init__(self, agent_name: str, ocf_version: str):
f5f42f
-        super().__init__(agent_name)
f5f42f
-        self.ocf_version = ocf_version
f5f42f
-
f5f42f
-
f5f42f
 def resource_agent_error_to_report_item(
f5f42f
     e: ResourceAgentError,
f5f42f
     severity: reports.ReportItemSeverity = reports.ReportItemSeverity.error(),
f5f42f
@@ -69,10 +61,4 @@ def resource_agent_error_to_report_item(
f5f42f
         message = reports.messages.UnableToGetAgentMetadata(
f5f42f
             e.agent_name, e.message
f5f42f
         )
f5f42f
-    elif isinstance(e, UnsupportedOcfVersion):
f5f42f
-        message = reports.messages.AgentImplementsUnsupportedOcfVersion(
f5f42f
-            e.agent_name,
f5f42f
-            e.ocf_version,
f5f42f
-            sorted(const.SUPPORTED_OCF_VERSIONS),
f5f42f
-        )
f5f42f
     return reports.ReportItem(severity, message)
f5f42f
diff --git a/pcs/lib/resource_agent/facade.py b/pcs/lib/resource_agent/facade.py
f5f42f
index 4dbb59b8..dea59a1a 100644
f5f42f
--- a/pcs/lib/resource_agent/facade.py
f5f42f
+++ b/pcs/lib/resource_agent/facade.py
f5f42f
@@ -188,18 +188,32 @@ class ResourceAgentFacadeFactory:
f5f42f
         self._fenced_metadata = None
f5f42f
 
f5f42f
     def facade_from_parsed_name(
f5f42f
-        self, name: ResourceAgentName
f5f42f
+        self, name: ResourceAgentName, report_warnings=True
f5f42f
     ) -> ResourceAgentFacade:
f5f42f
         """
f5f42f
         Create ResourceAgentFacade based on specified agent name
f5f42f
 
f5f42f
         name -- agent name to get a facade for
f5f42f
         """
f5f42f
-        return self._facade_from_metadata(
f5f42f
-            ocf_version_to_ocf_unified(
f5f42f
-                parse_metadata(name, load_metadata(self._runner, name))
f5f42f
-            )
f5f42f
+        metadata, raw_ocf_version = parse_metadata(
f5f42f
+            name,
f5f42f
+            load_metadata(self._runner, name),
f5f42f
         )
f5f42f
+        if (
f5f42f
+            report_warnings
f5f42f
+            and raw_ocf_version not in const.SUPPORTED_OCF_VERSIONS
f5f42f
+        ):
f5f42f
+            self._report_processor.report(
f5f42f
+                reports.ReportItem.warning(
f5f42f
+                    reports.messages.AgentImplementsUnsupportedOcfVersionAssumedVersion(
f5f42f
+                        name.full_name,
f5f42f
+                        raw_ocf_version,
f5f42f
+                        sorted(const.SUPPORTED_OCF_VERSIONS),
f5f42f
+                        const.OCF_1_0,
f5f42f
+                    )
f5f42f
+                )
f5f42f
+            )
f5f42f
+        return self._facade_from_metadata(ocf_version_to_ocf_unified(metadata))
f5f42f
 
f5f42f
     def void_facade_from_parsed_name(
f5f42f
         self, name: ResourceAgentName
f5f42f
@@ -232,15 +246,12 @@ class ResourceAgentFacadeFactory:
f5f42f
                 const.FAKE_AGENT_STANDARD, None, const.PACEMAKER_FENCED
f5f42f
             )
f5f42f
             try:
f5f42f
+                metadata, _ = parse_metadata(
f5f42f
+                    agent_name,
f5f42f
+                    load_fake_agent_metadata(self._runner, agent_name.type),
f5f42f
+                )
f5f42f
                 self._fenced_metadata = ocf_unified_to_pcs(
f5f42f
-                    ocf_version_to_ocf_unified(
f5f42f
-                        parse_metadata(
f5f42f
-                            agent_name,
f5f42f
-                            load_fake_agent_metadata(
f5f42f
-                                self._runner, agent_name.type
f5f42f
-                            ),
f5f42f
-                        )
f5f42f
-                    )
f5f42f
+                    ocf_version_to_ocf_unified(metadata)
f5f42f
                 )
f5f42f
             except ResourceAgentError as e:
f5f42f
                 # If pcs is unable to load fenced metadata, cache an empty
f5f42f
diff --git a/pcs/lib/resource_agent/xml.py b/pcs/lib/resource_agent/xml.py
f5f42f
index 82f8fbfa..1ba97216 100644
f5f42f
--- a/pcs/lib/resource_agent/xml.py
f5f42f
+++ b/pcs/lib/resource_agent/xml.py
f5f42f
@@ -8,7 +8,7 @@ from pcs.common.tools import xml_fromstring
f5f42f
 from pcs.lib.external import CommandRunner
f5f42f
 
f5f42f
 from . import const
f5f42f
-from .error import UnableToGetAgentMetadata, UnsupportedOcfVersion
f5f42f
+from .error import UnableToGetAgentMetadata
f5f42f
 from .types import (
f5f42f
     FakeAgentName,
f5f42f
     ResourceAgentActionOcf1_0,
f5f42f
@@ -137,8 +137,11 @@ def load_fake_agent_metadata(
f5f42f
 
f5f42f
 
f5f42f
 def parse_metadata(
f5f42f
-    name: ResourceAgentName, metadata: _Element
f5f42f
-) -> Union[ResourceAgentMetadataOcf1_0, ResourceAgentMetadataOcf1_1]:
f5f42f
+    name: ResourceAgentName,
f5f42f
+    metadata: _Element,
f5f42f
+) -> Tuple[
f5f42f
+    Union[ResourceAgentMetadataOcf1_0, ResourceAgentMetadataOcf1_1], str
f5f42f
+]:
f5f42f
     """
f5f42f
     Parse XML metadata to a dataclass
f5f42f
 
f5f42f
@@ -146,11 +149,9 @@ def parse_metadata(
f5f42f
     metadata -- metadata XML document
f5f42f
     """
f5f42f
     ocf_version = _get_ocf_version(metadata)
f5f42f
-    if ocf_version == const.OCF_1_0:
f5f42f
-        return _parse_agent_1_0(name, metadata)
f5f42f
     if ocf_version == const.OCF_1_1:
f5f42f
-        return _parse_agent_1_1(name, metadata)
f5f42f
-    raise UnsupportedOcfVersion(name.full_name, ocf_version)
f5f42f
+        return _parse_agent_1_1(name, metadata), ocf_version
f5f42f
+    return _parse_agent_1_0(name, metadata), ocf_version
f5f42f
 
f5f42f
 
f5f42f
 def _parse_agent_1_0(
f5f42f
diff --git a/pcs_test/tier0/common/reports/test_messages.py b/pcs_test/tier0/common/reports/test_messages.py
f5f42f
index 4a7b4945..b885a9eb 100644
f5f42f
--- a/pcs_test/tier0/common/reports/test_messages.py
f5f42f
+++ b/pcs_test/tier0/common/reports/test_messages.py
f5f42f
@@ -2833,22 +2833,22 @@ class AgentNameGuessFoundNone(NameBuildTest):
f5f42f
         )
f5f42f
 
f5f42f
 
f5f42f
-class AgentImplementsUnsupportedOcfVersion(NameBuildTest):
f5f42f
+class AgentImplementsUnsupportedOcfVersionAssumedVersion(NameBuildTest):
f5f42f
     def test_singular(self):
f5f42f
         self.assert_message_from_report(
f5f42f
-            "Unable to process agent 'agent-name' as it implements unsupported "
f5f42f
-            "OCF version 'ocf-2.3', supported version is: 'v1'",
f5f42f
-            reports.AgentImplementsUnsupportedOcfVersion(
f5f42f
-                "agent-name", "ocf-2.3", ["v1"]
f5f42f
+            "Agent 'agent-name' implements unsupported OCF version 'ocf-2.3', "
f5f42f
+            "supported version is: 'v1'; assumed version 'v1'",
f5f42f
+            reports.AgentImplementsUnsupportedOcfVersionAssumedVersion(
f5f42f
+                "agent-name", "ocf-2.3", ["v1"], "v1"
f5f42f
             ),
f5f42f
         )
f5f42f
 
f5f42f
     def test_plural(self):
f5f42f
         self.assert_message_from_report(
f5f42f
-            "Unable to process agent 'agent-name' as it implements unsupported "
f5f42f
-            "OCF version 'ocf-2.3', supported versions are: 'v1', 'v2', 'v3'",
f5f42f
-            reports.AgentImplementsUnsupportedOcfVersion(
f5f42f
-                "agent-name", "ocf-2.3", ["v1", "v2", "v3"]
f5f42f
+            "Agent 'agent-name' implements unsupported OCF version 'ocf-2.3', "
f5f42f
+            "supported versions are: 'v1', 'v2', 'v3'; assumed version 'v1'",
f5f42f
+            reports.AgentImplementsUnsupportedOcfVersionAssumedVersion(
f5f42f
+                "agent-name", "ocf-2.3", ["v1", "v2", "v3"], "v1"
f5f42f
             ),
f5f42f
         )
f5f42f
 
f5f42f
diff --git a/pcs_test/tier0/lib/resource_agent/test_facade.py b/pcs_test/tier0/lib/resource_agent/test_facade.py
f5f42f
index 654eb35e..f6a9899c 100644
f5f42f
--- a/pcs_test/tier0/lib/resource_agent/test_facade.py
f5f42f
+++ b/pcs_test/tier0/lib/resource_agent/test_facade.py
f5f42f
@@ -92,6 +92,14 @@ class ResourceAgentFacadeFactory(TestCase):
f5f42f
             </parameters>
f5f42f
         </resource-agent>
f5f42f
     """
f5f42f
+    _fixture_agent_bad_version_xml = """
f5f42f
+        <resource-agent name="agent">
f5f42f
+            <version>0.1.2</version>
f5f42f
+            <parameters>
f5f42f
+                <parameter name="agent-param"/>
f5f42f
+            </parameters>
f5f42f
+        </resource-agent>
f5f42f
+    """
f5f42f
     _fixture_fenced_xml = """
f5f42f
         <resource-agent name="pacemaker-fenced">
f5f42f
             <parameters>
f5f42f
@@ -125,6 +133,45 @@ class ResourceAgentFacadeFactory(TestCase):
f5f42f
         self.assertEqual(facade.metadata.name, name)
f5f42f
         self.assertTrue(facade.metadata.agent_exists)
f5f42f
 
f5f42f
+    def test_facade_bad_ocf_version(self):
f5f42f
+        name = ra.ResourceAgentName("service", None, "daemon")
f5f42f
+        self.config.runner.pcmk.load_agent(
f5f42f
+            agent_name="service:daemon",
f5f42f
+            stdout=self._fixture_agent_bad_version_xml,
f5f42f
+        )
f5f42f
+
f5f42f
+        env = self.env_assist.get_env()
f5f42f
+        facade = ra.ResourceAgentFacadeFactory(
f5f42f
+            env.cmd_runner(), env.report_processor
f5f42f
+        ).facade_from_parsed_name(name)
f5f42f
+        self.assertEqual(facade.metadata.name, name)
f5f42f
+        self.assertTrue(facade.metadata.agent_exists)
f5f42f
+        self.env_assist.assert_reports(
f5f42f
+            [
f5f42f
+                fixture.warn(
f5f42f
+                    reports.codes.AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION_ASSUMED_VERSION,
f5f42f
+                    agent=name.full_name,
f5f42f
+                    ocf_version="0.1.2",
f5f42f
+                    supported_versions=sorted(ra.const.SUPPORTED_OCF_VERSIONS),
f5f42f
+                    assumed_version=ra.const.OCF_1_0,
f5f42f
+                )
f5f42f
+            ]
f5f42f
+        )
f5f42f
+
f5f42f
+    def test_facade_bad_ocf_version_disabled_warning(self):
f5f42f
+        name = ra.ResourceAgentName("service", None, "daemon")
f5f42f
+        self.config.runner.pcmk.load_agent(
f5f42f
+            agent_name="service:daemon",
f5f42f
+            stdout=self._fixture_agent_bad_version_xml,
f5f42f
+        )
f5f42f
+
f5f42f
+        env = self.env_assist.get_env()
f5f42f
+        facade = ra.ResourceAgentFacadeFactory(
f5f42f
+            env.cmd_runner(), env.report_processor
f5f42f
+        ).facade_from_parsed_name(name, report_warnings=False)
f5f42f
+        self.assertEqual(facade.metadata.name, name)
f5f42f
+        self.assertTrue(facade.metadata.agent_exists)
f5f42f
+
f5f42f
     def test_facade_missing_agent(self):
f5f42f
         name = ra.ResourceAgentName("service", None, "daemon")
f5f42f
         self.config.runner.pcmk.load_agent(
f5f42f
diff --git a/pcs_test/tier0/lib/resource_agent/test_xml.py b/pcs_test/tier0/lib/resource_agent/test_xml.py
f5f42f
index c4176f32..26bbbb7d 100644
f5f42f
--- a/pcs_test/tier0/lib/resource_agent/test_xml.py
f5f42f
+++ b/pcs_test/tier0/lib/resource_agent/test_xml.py
f5f42f
@@ -351,6 +351,7 @@ class LoadFakeAgentMetadata(TestCase):
f5f42f
 class ParseOcfToolsMixin:
f5f42f
     agent_name = ra.ResourceAgentName("ocf", "pacemaker", "Dummy")
f5f42f
     ocf_version = None
f5f42f
+    parsed_ocf_version = None
f5f42f
 
f5f42f
     def parse(self, xml, agent_name=None):
f5f42f
         agent_name = agent_name or self.agent_name
f5f42f
@@ -383,19 +384,17 @@ class ParseOcfToolsMixin:
f5f42f
             version_el.text = ocf_version
f5f42f
         return etree_to_str(dom)
f5f42f
 
f5f42f
-
f5f42f
-class ParseOcfGeneric(ParseOcfToolsMixin, TestCase):
f5f42f
-    def test_unsupported_ocf_version(self):
f5f42f
-        with self.assertRaises(ra.UnsupportedOcfVersion) as cm:
f5f42f
-            self.parse(self.xml("""<resource-agent/>""", ocf_version="1.2"))
f5f42f
-        self.assertEqual(cm.exception.agent_name, self.agent_name.full_name)
f5f42f
-        self.assertEqual(cm.exception.ocf_version, "1.2")
f5f42f
+    def assert_parse_result(self, xml, metadata):
f5f42f
+        self.assertEqual(
f5f42f
+            self.parse(xml),
f5f42f
+            (metadata, self.parsed_ocf_version or self.ocf_version),
f5f42f
+        )
f5f42f
 
f5f42f
 
f5f42f
 class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
     def test_empty_agent(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(self.xml("""<resource-agent/>""")),
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml("""<resource-agent/>"""),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
                 shortdesc=None,
f5f42f
@@ -406,16 +405,14 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_desc_element(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <shortdesc>This is a shortdesc</shortdesc>
f5f42f
                             <longdesc>This is a longdesc</longdesc>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -427,16 +424,14 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_desc_element_empty(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <longdesc/>
f5f42f
                             <shortdesc/>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -448,15 +443,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_desc_attribute(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent shortdesc="This is a shortdesc">
f5f42f
                             <longdesc></longdesc>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -468,13 +461,11 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_desc_attribute_empty(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent shortdesc=""/>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -486,15 +477,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_desc_element_and_attribute(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent shortdesc="shortdesc attribute">
f5f42f
                             <shortdesc>shortdesc element</shortdesc>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -506,15 +495,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_desc_element_empty_and_attribute(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent shortdesc="shortdesc attribute">
f5f42f
                             <shortdesc></shortdesc>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -526,15 +513,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_desc_element_empty_and_attribute_empty(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent shortdesc="">
f5f42f
                             <shortdesc></shortdesc>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -546,15 +531,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_parameters_empty_list(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters/>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -581,17 +564,15 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
             )
f5f42f
 
f5f42f
     def test_parameters_minimal(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters>
f5f42f
                                 <parameter name="a_parameter"/>
f5f42f
                             </parameters>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -616,10 +597,9 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_parameters_all_settings(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters>
f5f42f
                                 
f5f42f
@@ -632,7 +612,6 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
                             </parameters>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -657,10 +636,9 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_parameters_content(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters>
f5f42f
                                 <parameter name="with_type">
f5f42f
@@ -676,7 +654,6 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
                             </parameters>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -713,15 +690,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
         )
f5f42f
 
f5f42f
     def test_actions_empty_list(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <actions/>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -748,10 +723,9 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
             )
f5f42f
 
f5f42f
     def test_actions_multiple(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <actions>
f5f42f
                                 <action name="minimal"/>
f5f42f
@@ -764,7 +738,6 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
                             </actions>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_0(
f5f42f
                 self.agent_name,
f5f42f
@@ -808,7 +781,26 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
f5f42f
 
f5f42f
 
f5f42f
 class ParseOcf10NoVersion(ParseOcf10BaseMixin, TestCase):
f5f42f
-    pass
f5f42f
+    parsed_ocf_version = "1.0"
f5f42f
+
f5f42f
+
f5f42f
+class ParseOcf10UnsupportedVersion(ParseOcf10BaseMixin, TestCase):
f5f42f
+    ocf_version = "0.1.2"
f5f42f
+
f5f42f
+    # These tests test that pcs raises an error if an agent doesn't conform to
f5f42f
+    # OCF schema. There is, however, no validation against OCF schema for
f5f42f
+    # agents with unsupported OCF version. That means no error message, pcs
f5f42f
+    # tries to process the agent and crashes. However bad that sounds, it's
f5f42f
+    # indended as that's how pcs behaved before OCF 1.1 was implemented.
f5f42f
+    # There's therefore no point in running these tests.
f5f42f
+
f5f42f
+    def test_parameters_empty_parameter(self):
f5f42f
+        # parameters must have at least 'name' attribute
f5f42f
+        pass
f5f42f
+
f5f42f
+    def test_actions_empty_action(self):
f5f42f
+        # actions must have at least 'name' attribute
f5f42f
+        pass
f5f42f
 
f5f42f
 
f5f42f
 class ParseOcf10ExplicitVersion(ParseOcf10BaseMixin, TestCase):
f5f42f
@@ -819,8 +811,8 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
     ocf_version = "1.1"
f5f42f
 
f5f42f
     def test_empty_agent(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(self.xml("""<resource-agent/>""")),
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml("""<resource-agent/>"""),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
                 shortdesc=None,
f5f42f
@@ -831,16 +823,14 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
         )
f5f42f
 
f5f42f
     def test_desc_element(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <shortdesc>This is a shortdesc</shortdesc>
f5f42f
                             <longdesc>This is a longdesc</longdesc>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
@@ -852,16 +842,14 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
         )
f5f42f
 
f5f42f
     def test_desc_element_empty(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <longdesc/>
f5f42f
                             <shortdesc/>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
@@ -873,15 +861,13 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
         )
f5f42f
 
f5f42f
     def test_parameters_empty_list(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters/>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
@@ -908,17 +894,15 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
             )
f5f42f
 
f5f42f
     def test_parameters_minimal(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters>
f5f42f
                                 <parameter name="a_parameter"/>
f5f42f
                             </parameters>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
@@ -945,10 +929,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
         )
f5f42f
 
f5f42f
     def test_parameters_deprecated_minimal(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters>
f5f42f
                                 <parameter name="a_parameter">
f5f42f
@@ -957,7 +940,6 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
                             </parameters>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
@@ -984,10 +966,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
         )
f5f42f
 
f5f42f
     def test_parameters_deprecated_replaced_with(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters>
f5f42f
                                 <parameter name="a_parameter">
f5f42f
@@ -999,7 +980,6 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
                             </parameters>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
@@ -1026,10 +1006,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
         )
f5f42f
 
f5f42f
     def test_parameters_all_settings(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters>
f5f42f
                                 
f5f42f
@@ -1048,7 +1027,6 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
                             </parameters>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
@@ -1075,10 +1053,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
         )
f5f42f
 
f5f42f
     def test_parameters_content(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <parameters>
f5f42f
                                 <parameter name="with_type">
f5f42f
@@ -1094,7 +1071,6 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
                             </parameters>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
@@ -1135,15 +1111,13 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
         )
f5f42f
 
f5f42f
     def test_actions_empty_list(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <actions/>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
@@ -1170,10 +1144,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
             )
f5f42f
 
f5f42f
     def test_actions_multiple(self):
f5f42f
-        self.assertEqual(
f5f42f
-            self.parse(
f5f42f
-                self.xml(
f5f42f
-                    """
f5f42f
+        self.assert_parse_result(
f5f42f
+            self.xml(
f5f42f
+                """
f5f42f
                         <resource-agent>
f5f42f
                             <actions>
f5f42f
                                 <action name="minimal"/>
f5f42f
@@ -1186,7 +1159,6 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase):
f5f42f
                             </actions>
f5f42f
                         </resource-agent>
f5f42f
                     """
f5f42f
-                )
f5f42f
             ),
f5f42f
             ResourceAgentMetadataOcf1_1(
f5f42f
                 self.agent_name,
f5f42f
-- 
f5f42f
2.34.1
f5f42f