Blame SOURCES/bz2050274-02-relax-OCF-1.0-parser.patch

9e0fa3
From 65b30a04a234449cb4aa65606d47bf1d673592a4 Mon Sep 17 00:00:00 2001
9e0fa3
From: Tomas Jelinek <tojeline@redhat.com>
9e0fa3
Date: Wed, 9 Feb 2022 11:16:49 +0100
9e0fa3
Subject: [PATCH 2/3] relax OCF 1.0 parser
9e0fa3
9e0fa3
---
9e0fa3
 pcs/lib/resource_agent/facade.py              |  50 ++++--
9e0fa3
 pcs/lib/resource_agent/ocf_transform.py       |  51 +++++-
9e0fa3
 pcs/lib/resource_agent/xml.py                 |   8 +-
9e0fa3
 .../tier0/lib/resource_agent/test_facade.py   |  44 +++++
9e0fa3
 .../lib/resource_agent/test_ocf_transform.py  |  48 +++++-
9e0fa3
 pcs_test/tier0/lib/resource_agent/test_xml.py | 155 ++++++++++--------
9e0fa3
 6 files changed, 256 insertions(+), 100 deletions(-)
9e0fa3
9e0fa3
diff --git a/pcs/lib/resource_agent/facade.py b/pcs/lib/resource_agent/facade.py
9e0fa3
index dea59a1a..8a65eb1c 100644
9e0fa3
--- a/pcs/lib/resource_agent/facade.py
9e0fa3
+++ b/pcs/lib/resource_agent/facade.py
9e0fa3
@@ -2,12 +2,19 @@ from collections import defaultdict
9e0fa3
 from dataclasses import replace as dc_replace
9e0fa3
 from typing import Dict, Iterable, List, Optional, Set
9e0fa3
 
9e0fa3
+from lxml import etree
9e0fa3
+
9e0fa3
+from pcs import settings
9e0fa3
 from pcs.common import reports
9e0fa3
 from pcs.lib import validate
9e0fa3
 from pcs.lib.external import CommandRunner
9e0fa3
 
9e0fa3
 from . import const
9e0fa3
-from .error import ResourceAgentError, resource_agent_error_to_report_item
9e0fa3
+from .error import (
9e0fa3
+    ResourceAgentError,
9e0fa3
+    resource_agent_error_to_report_item,
9e0fa3
+    UnableToGetAgentMetadata,
9e0fa3
+)
9e0fa3
 from .name import name_to_void_metadata
9e0fa3
 from .ocf_transform import ocf_version_to_ocf_unified
9e0fa3
 from .pcs_transform import get_additional_trace_parameters, ocf_unified_to_pcs
9e0fa3
@@ -195,24 +202,33 @@ class ResourceAgentFacadeFactory:
9e0fa3
 
9e0fa3
         name -- agent name to get a facade for
9e0fa3
         """
9e0fa3
-        metadata, raw_ocf_version = parse_metadata(
9e0fa3
-            name,
9e0fa3
-            load_metadata(self._runner, name),
9e0fa3
-        )
9e0fa3
-        if (
9e0fa3
-            report_warnings
9e0fa3
-            and raw_ocf_version not in const.SUPPORTED_OCF_VERSIONS
9e0fa3
-        ):
9e0fa3
-            self._report_processor.report(
9e0fa3
-                reports.ReportItem.warning(
9e0fa3
-                    reports.messages.AgentImplementsUnsupportedOcfVersionAssumedVersion(
9e0fa3
-                        name.full_name,
9e0fa3
-                        raw_ocf_version,
9e0fa3
-                        sorted(const.SUPPORTED_OCF_VERSIONS),
9e0fa3
-                        const.OCF_1_0,
9e0fa3
+        dom_metadata = load_metadata(self._runner, name)
9e0fa3
+        metadata, raw_ocf_version = parse_metadata(name, dom_metadata)
9e0fa3
+        if report_warnings:
9e0fa3
+            if raw_ocf_version not in const.SUPPORTED_OCF_VERSIONS:
9e0fa3
+                self._report_processor.report(
9e0fa3
+                    reports.ReportItem.warning(
9e0fa3
+                        reports.messages.AgentImplementsUnsupportedOcfVersionAssumedVersion(
9e0fa3
+                            name.full_name,
9e0fa3
+                            raw_ocf_version,
9e0fa3
+                            sorted(const.SUPPORTED_OCF_VERSIONS),
9e0fa3
+                            const.OCF_1_0,
9e0fa3
+                        )
9e0fa3
                     )
9e0fa3
                 )
9e0fa3
-            )
9e0fa3
+            if raw_ocf_version != const.OCF_1_1:
9e0fa3
+                try:
9e0fa3
+                    etree.RelaxNG(
9e0fa3
+                        file=settings.path.ocf_1_0_schema
9e0fa3
+                    ).assertValid(dom_metadata)
9e0fa3
+                except etree.DocumentInvalid as e:
9e0fa3
+                    self._report_processor.report(
9e0fa3
+                        resource_agent_error_to_report_item(
9e0fa3
+                            UnableToGetAgentMetadata(name.full_name, str(e)),
9e0fa3
+                            severity=reports.ReportItemSeverity.warning(),
9e0fa3
+                            is_stonith=name.is_stonith,
9e0fa3
+                        )
9e0fa3
+                    )
9e0fa3
         return self._facade_from_metadata(ocf_version_to_ocf_unified(metadata))
9e0fa3
 
9e0fa3
     def void_facade_from_parsed_name(
9e0fa3
diff --git a/pcs/lib/resource_agent/ocf_transform.py b/pcs/lib/resource_agent/ocf_transform.py
9e0fa3
index e841b55e..7e6a14ad 100644
9e0fa3
--- a/pcs/lib/resource_agent/ocf_transform.py
9e0fa3
+++ b/pcs/lib/resource_agent/ocf_transform.py
9e0fa3
@@ -67,20 +67,42 @@ def _ocf_1_1_to_ocf_unified(
9e0fa3
         longdesc=metadata.longdesc,
9e0fa3
         parameters=_ocf_1_1_parameter_list_to_ocf_unified(metadata.parameters),
9e0fa3
         # OCF 1.1 actions are the same as in OCF 1.0
9e0fa3
-        actions=_ocf_1_0_action_list_to_ocf_unified(metadata.actions),
9e0fa3
+        actions=_ocf_1_1_action_list_to_ocf_unified(metadata.actions),
9e0fa3
     )
9e0fa3
 
9e0fa3
 
9e0fa3
 def _ocf_1_0_action_list_to_ocf_unified(
9e0fa3
-    action_list: Iterable[
9e0fa3
-        Union[ResourceAgentActionOcf1_0, ResourceAgentActionOcf1_1]
9e0fa3
-    ],
9e0fa3
+    action_list: Iterable[ResourceAgentActionOcf1_0],
9e0fa3
 ) -> List[ResourceAgentAction]:
9e0fa3
     """
9e0fa3
     Transform OCF 1.0 actions to a universal format
9e0fa3
 
9e0fa3
     action_list -- actions according OCF 1.0
9e0fa3
     """
9e0fa3
+    return [
9e0fa3
+        ResourceAgentAction(
9e0fa3
+            name=action.name,
9e0fa3
+            timeout=action.timeout,
9e0fa3
+            interval=action.interval,
9e0fa3
+            role=action.role,
9e0fa3
+            start_delay=action.start_delay,
9e0fa3
+            depth=action.depth,
9e0fa3
+            automatic=_bool_value_legacy(action.automatic),
9e0fa3
+            on_target=_bool_value_legacy(action.on_target),
9e0fa3
+        )
9e0fa3
+        for action in action_list
9e0fa3
+        if action.name
9e0fa3
+    ]
9e0fa3
+
9e0fa3
+
9e0fa3
+def _ocf_1_1_action_list_to_ocf_unified(
9e0fa3
+    action_list: Iterable[ResourceAgentActionOcf1_1],
9e0fa3
+) -> List[ResourceAgentAction]:
9e0fa3
+    """
9e0fa3
+    Transform OCF 1.1 actions to a universal format
9e0fa3
+
9e0fa3
+    action_list -- actions according OCF 1.1
9e0fa3
+    """
9e0fa3
     return [
9e0fa3
         ResourceAgentAction(
9e0fa3
             name=action.name,
9e0fa3
@@ -111,6 +133,8 @@ def _ocf_1_0_parameter_list_to_ocf_unified(
9e0fa3
 
9e0fa3
     result = []
9e0fa3
     for parameter in parameter_list:
9e0fa3
+        if not parameter.name:
9e0fa3
+            continue
9e0fa3
         result.append(
9e0fa3
             ResourceAgentParameter(
9e0fa3
                 name=parameter.name,
9e0fa3
@@ -119,17 +143,17 @@ def _ocf_1_0_parameter_list_to_ocf_unified(
9e0fa3
                 type=parameter.type,
9e0fa3
                 default=parameter.default,
9e0fa3
                 enum_values=parameter.enum_values,
9e0fa3
-                required=_bool_value(parameter.required),
9e0fa3
+                required=_bool_value_legacy(parameter.required),
9e0fa3
                 advanced=False,
9e0fa3
-                deprecated=_bool_value(parameter.deprecated),
9e0fa3
+                deprecated=_bool_value_legacy(parameter.deprecated),
9e0fa3
                 deprecated_by=sorted(deprecated_by_dict[parameter.name]),
9e0fa3
                 deprecated_desc=None,
9e0fa3
                 unique_group=(
9e0fa3
                     f"{const.DEFAULT_UNIQUE_GROUP_PREFIX}{parameter.name}"
9e0fa3
-                    if _bool_value(parameter.unique)
9e0fa3
+                    if _bool_value_legacy(parameter.unique)
9e0fa3
                     else None
9e0fa3
                 ),
9e0fa3
-                reloadable=_bool_value(parameter.unique),
9e0fa3
+                reloadable=_bool_value_legacy(parameter.unique),
9e0fa3
             )
9e0fa3
         )
9e0fa3
     return result
9e0fa3
@@ -170,3 +194,14 @@ def _bool_value(value: Optional[str]) -> bool:
9e0fa3
     value -- raw bool value
9e0fa3
     """
9e0fa3
     return value == "1"
9e0fa3
+
9e0fa3
+
9e0fa3
+def _bool_value_legacy(value: Optional[str]) -> bool:
9e0fa3
+    """
9e0fa3
+    Transform raw bool value from metadata to bool type in backward compatible way
9e0fa3
+
9e0fa3
+    value -- raw bool value
9e0fa3
+    """
9e0fa3
+    return (
9e0fa3
+        False if not value else value.lower() in {"true", "on", "yes", "y", "1"}
9e0fa3
+    )
9e0fa3
diff --git a/pcs/lib/resource_agent/xml.py b/pcs/lib/resource_agent/xml.py
9e0fa3
index 1ba97216..0fc70527 100644
9e0fa3
--- a/pcs/lib/resource_agent/xml.py
9e0fa3
+++ b/pcs/lib/resource_agent/xml.py
9e0fa3
@@ -94,9 +94,7 @@ def _metadata_xml_to_dom(metadata: str) -> _Element:
9e0fa3
     """
9e0fa3
     dom = xml_fromstring(metadata)
9e0fa3
     ocf_version = _get_ocf_version(dom)
9e0fa3
-    if ocf_version == const.OCF_1_0:
9e0fa3
-        etree.RelaxNG(file=settings.path.ocf_1_0_schema).assertValid(dom)
9e0fa3
-    elif ocf_version == const.OCF_1_1:
9e0fa3
+    if ocf_version == const.OCF_1_1:
9e0fa3
         etree.RelaxNG(file=settings.path.ocf_1_1_schema).assertValid(dom)
9e0fa3
     return dom
9e0fa3
 
9e0fa3
@@ -230,7 +228,7 @@ def _parse_parameters_1_0(
9e0fa3
         )
9e0fa3
         result.append(
9e0fa3
             ResourceAgentParameterOcf1_0(
9e0fa3
-                name=str(parameter_el.attrib["name"]),
9e0fa3
+                name=str(parameter_el.get("name", "")),
9e0fa3
                 shortdesc=_get_shortdesc(parameter_el),
9e0fa3
                 longdesc=_get_longdesc(parameter_el),
9e0fa3
                 type=value_type,
9e0fa3
@@ -286,7 +284,7 @@ def _parse_parameters_1_1(
9e0fa3
 def _parse_actions_1_0(element: _Element) -> List[ResourceAgentActionOcf1_0]:
9e0fa3
     return [
9e0fa3
         ResourceAgentActionOcf1_0(
9e0fa3
-            name=str(action.attrib["name"]),
9e0fa3
+            name=str(action.get("name", "")),
9e0fa3
             timeout=action.get("timeout"),
9e0fa3
             interval=action.get("interval"),
9e0fa3
             role=action.get("role"),
9e0fa3
diff --git a/pcs_test/tier0/lib/resource_agent/test_facade.py b/pcs_test/tier0/lib/resource_agent/test_facade.py
9e0fa3
index f6a9899c..313dfa2b 100644
9e0fa3
--- a/pcs_test/tier0/lib/resource_agent/test_facade.py
9e0fa3
+++ b/pcs_test/tier0/lib/resource_agent/test_facade.py
9e0fa3
@@ -100,6 +100,13 @@ class ResourceAgentFacadeFactory(TestCase):
9e0fa3
             </parameters>
9e0fa3
         </resource-agent>
9e0fa3
     """
9e0fa3
+    _fixture_agent_not_valid_xml = """
9e0fa3
+        <resource-agent name="agent">
9e0fa3
+            <parameters>
9e0fa3
+                <parameter label="something wrong"/>
9e0fa3
+            </parameters>
9e0fa3
+        </resource-agent>
9e0fa3
+    """
9e0fa3
     _fixture_fenced_xml = """
9e0fa3
         <resource-agent name="pacemaker-fenced">
9e0fa3
             <parameters>
9e0fa3
@@ -172,6 +179,43 @@ class ResourceAgentFacadeFactory(TestCase):
9e0fa3
         self.assertEqual(facade.metadata.name, name)
9e0fa3
         self.assertTrue(facade.metadata.agent_exists)
9e0fa3
 
9e0fa3
+    def test_facade_ocf_1_0_not_valid(self):
9e0fa3
+        name = ra.ResourceAgentName("service", None, "daemon")
9e0fa3
+        self.config.runner.pcmk.load_agent(
9e0fa3
+            agent_name="service:daemon",
9e0fa3
+            stdout=self._fixture_agent_not_valid_xml,
9e0fa3
+        )
9e0fa3
+
9e0fa3
+        env = self.env_assist.get_env()
9e0fa3
+        facade = ra.ResourceAgentFacadeFactory(
9e0fa3
+            env.cmd_runner(), env.report_processor
9e0fa3
+        ).facade_from_parsed_name(name)
9e0fa3
+        self.assertEqual(facade.metadata.name, name)
9e0fa3
+        self.assertTrue(facade.metadata.agent_exists)
9e0fa3
+        self.env_assist.assert_reports(
9e0fa3
+            [
9e0fa3
+                fixture.warn(
9e0fa3
+                    reports.codes.UNABLE_TO_GET_AGENT_METADATA,
9e0fa3
+                    agent=name.full_name,
9e0fa3
+                    reason="Element parameter failed to validate attributes, line 3",
9e0fa3
+                )
9e0fa3
+            ]
9e0fa3
+        )
9e0fa3
+
9e0fa3
+    def test_facade_ocf_1_0_not_valid_disabled_warning(self):
9e0fa3
+        name = ra.ResourceAgentName("service", None, "daemon")
9e0fa3
+        self.config.runner.pcmk.load_agent(
9e0fa3
+            agent_name="service:daemon",
9e0fa3
+            stdout=self._fixture_agent_not_valid_xml,
9e0fa3
+        )
9e0fa3
+
9e0fa3
+        env = self.env_assist.get_env()
9e0fa3
+        facade = ra.ResourceAgentFacadeFactory(
9e0fa3
+            env.cmd_runner(), env.report_processor
9e0fa3
+        ).facade_from_parsed_name(name, report_warnings=False)
9e0fa3
+        self.assertEqual(facade.metadata.name, name)
9e0fa3
+        self.assertTrue(facade.metadata.agent_exists)
9e0fa3
+
9e0fa3
     def test_facade_missing_agent(self):
9e0fa3
         name = ra.ResourceAgentName("service", None, "daemon")
9e0fa3
         self.config.runner.pcmk.load_agent(
9e0fa3
diff --git a/pcs_test/tier0/lib/resource_agent/test_ocf_transform.py b/pcs_test/tier0/lib/resource_agent/test_ocf_transform.py
9e0fa3
index 9e41b6af..d0de86e5 100644
9e0fa3
--- a/pcs_test/tier0/lib/resource_agent/test_ocf_transform.py
9e0fa3
+++ b/pcs_test/tier0/lib/resource_agent/test_ocf_transform.py
9e0fa3
@@ -66,6 +66,18 @@ class OcfVersionToOcfUnified(TestCase):
9e0fa3
                     obsoletes=None,
9e0fa3
                     unique=None,
9e0fa3
                 ),
9e0fa3
+                ra.types.ResourceAgentParameterOcf1_0(
9e0fa3
+                    name="",
9e0fa3
+                    shortdesc="Parameters with no name are ignored",
9e0fa3
+                    longdesc=None,
9e0fa3
+                    type="string",
9e0fa3
+                    default=None,
9e0fa3
+                    enum_values=None,
9e0fa3
+                    required=None,
9e0fa3
+                    deprecated=None,
9e0fa3
+                    obsoletes=None,
9e0fa3
+                    unique=None,
9e0fa3
+                ),
9e0fa3
                 ra.types.ResourceAgentParameterOcf1_0(
9e0fa3
                     name="param_2",
9e0fa3
                     shortdesc="param_2 shortdesc",
9e0fa3
@@ -109,10 +121,10 @@ class OcfVersionToOcfUnified(TestCase):
9e0fa3
                     type="string",
9e0fa3
                     default=None,
9e0fa3
                     enum_values=None,
9e0fa3
-                    required="1",
9e0fa3
-                    deprecated="1",
9e0fa3
+                    required="yeS",
9e0fa3
+                    deprecated="True",
9e0fa3
                     obsoletes="param_4",
9e0fa3
-                    unique="1",
9e0fa3
+                    unique="on",
9e0fa3
                 ),
9e0fa3
                 ra.types.ResourceAgentParameterOcf1_0(
9e0fa3
                     name="param_6",
9e0fa3
@@ -138,6 +150,16 @@ class OcfVersionToOcfUnified(TestCase):
9e0fa3
                     automatic=None,
9e0fa3
                     on_target=None,
9e0fa3
                 ),
9e0fa3
+                ra.types.ResourceAgentActionOcf1_0(
9e0fa3
+                    name="",
9e0fa3
+                    timeout=None,
9e0fa3
+                    interval=None,
9e0fa3
+                    role=None,
9e0fa3
+                    start_delay=None,
9e0fa3
+                    depth=None,
9e0fa3
+                    automatic=None,
9e0fa3
+                    on_target=None,
9e0fa3
+                ),
9e0fa3
                 ra.types.ResourceAgentActionOcf1_0(
9e0fa3
                     name="action_2",
9e0fa3
                     timeout="12",
9e0fa3
@@ -158,6 +180,16 @@ class OcfVersionToOcfUnified(TestCase):
9e0fa3
                     automatic="1",
9e0fa3
                     on_target="0",
9e0fa3
                 ),
9e0fa3
+                ra.types.ResourceAgentActionOcf1_0(
9e0fa3
+                    name="action_4",
9e0fa3
+                    timeout=None,
9e0fa3
+                    interval=None,
9e0fa3
+                    role=None,
9e0fa3
+                    start_delay=None,
9e0fa3
+                    depth=None,
9e0fa3
+                    automatic="yes",
9e0fa3
+                    on_target="True",
9e0fa3
+                ),
9e0fa3
             ],
9e0fa3
         )
9e0fa3
         metadata_out = ra.ResourceAgentMetadata(
9e0fa3
@@ -289,6 +321,16 @@ class OcfVersionToOcfUnified(TestCase):
9e0fa3
                     automatic=True,
9e0fa3
                     on_target=False,
9e0fa3
                 ),
9e0fa3
+                ra.ResourceAgentAction(
9e0fa3
+                    name="action_4",
9e0fa3
+                    timeout=None,
9e0fa3
+                    interval=None,
9e0fa3
+                    role=None,
9e0fa3
+                    start_delay=None,
9e0fa3
+                    depth=None,
9e0fa3
+                    automatic=True,
9e0fa3
+                    on_target=True,
9e0fa3
+                ),
9e0fa3
             ],
9e0fa3
         )
9e0fa3
         self.assertEqual(
9e0fa3
diff --git a/pcs_test/tier0/lib/resource_agent/test_xml.py b/pcs_test/tier0/lib/resource_agent/test_xml.py
9e0fa3
index 26bbbb7d..ea055ee2 100644
9e0fa3
--- a/pcs_test/tier0/lib/resource_agent/test_xml.py
9e0fa3
+++ b/pcs_test/tier0/lib/resource_agent/test_xml.py
9e0fa3
@@ -164,8 +164,13 @@ class MetadataXmlToDom(TestCase):
9e0fa3
             ra.xml._metadata_xml_to_dom("not an xml")
9e0fa3
 
9e0fa3
     def test_no_version_not_valid(self):
9e0fa3
-        with self.assertRaises(etree.DocumentInvalid):
9e0fa3
-            ra.xml._metadata_xml_to_dom("<resource-agent/>")
9e0fa3
+        # pylint: disable=no-self-use
9e0fa3
+        metadata = """
9e0fa3
+            <resource-agent/>
9e0fa3
+        """
9e0fa3
+        assert_xml_equal(
9e0fa3
+            metadata, etree_to_str(ra.xml._metadata_xml_to_dom(metadata))
9e0fa3
+        )
9e0fa3
 
9e0fa3
     def test_no_version_valid(self):
9e0fa3
         # pylint: disable=no-self-use
9e0fa3
@@ -178,14 +183,15 @@ class MetadataXmlToDom(TestCase):
9e0fa3
         )
9e0fa3
 
9e0fa3
     def test_ocf_1_0_not_valid(self):
9e0fa3
-        with self.assertRaises(etree.DocumentInvalid):
9e0fa3
-            ra.xml._metadata_xml_to_dom(
9e0fa3
-                """
9e0fa3
-                    <resource-agent>
9e0fa3
-                        <version>1.0</version>
9e0fa3
-                    </resource-agent>
9e0fa3
-                """
9e0fa3
-            )
9e0fa3
+        # pylint: disable=no-self-use
9e0fa3
+        metadata = """
9e0fa3
+            <resource-agent>
9e0fa3
+                <version>1.0</version>
9e0fa3
+            </resource-agent>
9e0fa3
+        """
9e0fa3
+        assert_xml_equal(
9e0fa3
+            metadata, etree_to_str(ra.xml._metadata_xml_to_dom(metadata))
9e0fa3
+        )
9e0fa3
 
9e0fa3
     def test_ocf_1_0_valid(self):
9e0fa3
         # pylint: disable=no-self-use
9e0fa3
@@ -273,19 +279,16 @@ class LoadMetadata(TestCase):
9e0fa3
 
9e0fa3
     def test_not_valid_xml(self):
9e0fa3
         agent_name = ra.ResourceAgentName("ocf", "pacemaker", "Dummy")
9e0fa3
+        metadata = "<resource-agent/>"
9e0fa3
         self.config.runner.pcmk.load_agent(
9e0fa3
             agent_name="ocf:pacemaker:Dummy",
9e0fa3
-            stdout="<resource-agent/>",
9e0fa3
+            stdout=metadata,
9e0fa3
         )
9e0fa3
 
9e0fa3
         env = self.env_assist.get_env()
9e0fa3
-        with self.assertRaises(ra.UnableToGetAgentMetadata) as cm:
9e0fa3
-            ra.xml.load_metadata(env.cmd_runner(), agent_name)
9e0fa3
-        self.assertEqual(cm.exception.agent_name, "ocf:pacemaker:Dummy")
9e0fa3
-        self.assertTrue(
9e0fa3
-            cm.exception.message.startswith(
9e0fa3
-                "Element resource-agent failed to validate"
9e0fa3
-            )
9e0fa3
+        assert_xml_equal(
9e0fa3
+            metadata,
9e0fa3
+            etree_to_str(ra.xml.load_metadata(env.cmd_runner(), agent_name)),
9e0fa3
         )
9e0fa3
 
9e0fa3
 
9e0fa3
@@ -335,16 +338,15 @@ class LoadFakeAgentMetadata(TestCase):
9e0fa3
 
9e0fa3
     def test_not_valid_xml(self):
9e0fa3
         agent_name = ra.const.PACEMAKER_FENCED
9e0fa3
-        self.config.runner.pcmk.load_fenced_metadata(stdout="<resource-agent/>")
9e0fa3
+        metadata = "<resource-agent/>"
9e0fa3
+        self.config.runner.pcmk.load_fenced_metadata(stdout=metadata)
9e0fa3
 
9e0fa3
         env = self.env_assist.get_env()
9e0fa3
-        with self.assertRaises(ra.UnableToGetAgentMetadata) as cm:
9e0fa3
-            ra.xml.load_fake_agent_metadata(env.cmd_runner(), agent_name)
9e0fa3
-        self.assertEqual(cm.exception.agent_name, "pacemaker-fenced")
9e0fa3
-        self.assertTrue(
9e0fa3
-            cm.exception.message.startswith(
9e0fa3
-                "Element resource-agent failed to validate"
9e0fa3
-            )
9e0fa3
+        assert_xml_equal(
9e0fa3
+            metadata,
9e0fa3
+            etree_to_str(
9e0fa3
+                ra.xml.load_fake_agent_metadata(env.cmd_runner(), agent_name)
9e0fa3
+            ),
9e0fa3
         )
9e0fa3
 
9e0fa3
 
9e0fa3
@@ -549,19 +551,37 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
9e0fa3
         )
9e0fa3
 
9e0fa3
     def test_parameters_empty_parameter(self):
9e0fa3
-        # parameters must have at least 'name' attribute
9e0fa3
-        with self.assertRaises(ra.UnableToGetAgentMetadata):
9e0fa3
-            self.parse(
9e0fa3
-                self.xml(
9e0fa3
-                    """
9e0fa3
-                        <resource-agent>
9e0fa3
-                            <parameters>
9e0fa3
-                                <parameter/>
9e0fa3
-                            </parameters>
9e0fa3
-                        </resource-agent>
9e0fa3
-                    """
9e0fa3
-                )
9e0fa3
-            )
9e0fa3
+        self.assert_parse_result(
9e0fa3
+            self.xml(
9e0fa3
+                """
9e0fa3
+                    <resource-agent>
9e0fa3
+                        <parameters>
9e0fa3
+                            <parameter/>
9e0fa3
+                        </parameters>
9e0fa3
+                    </resource-agent>
9e0fa3
+                """
9e0fa3
+            ),
9e0fa3
+            ResourceAgentMetadataOcf1_0(
9e0fa3
+                self.agent_name,
9e0fa3
+                shortdesc=None,
9e0fa3
+                longdesc=None,
9e0fa3
+                parameters=[
9e0fa3
+                    ResourceAgentParameterOcf1_0(
9e0fa3
+                        name="",
9e0fa3
+                        shortdesc=None,
9e0fa3
+                        longdesc=None,
9e0fa3
+                        type="string",
9e0fa3
+                        default=None,
9e0fa3
+                        enum_values=None,
9e0fa3
+                        required=None,
9e0fa3
+                        deprecated=None,
9e0fa3
+                        obsoletes=None,
9e0fa3
+                        unique=None,
9e0fa3
+                    )
9e0fa3
+                ],
9e0fa3
+                actions=[],
9e0fa3
+            ),
9e0fa3
+        )
9e0fa3
 
9e0fa3
     def test_parameters_minimal(self):
9e0fa3
         self.assert_parse_result(
9e0fa3
@@ -708,19 +728,35 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin):
9e0fa3
         )
9e0fa3
 
9e0fa3
     def test_actions_empty_action(self):
9e0fa3
-        # actions must have at least 'name' attribute
9e0fa3
-        with self.assertRaises(ra.UnableToGetAgentMetadata):
9e0fa3
-            self.parse(
9e0fa3
-                self.xml(
9e0fa3
-                    """
9e0fa3
-                        <resource-agent>
9e0fa3
-                            <actions>
9e0fa3
-                                <action/>
9e0fa3
-                            </actions>
9e0fa3
-                        </resource-agent>
9e0fa3
-                    """
9e0fa3
-                )
9e0fa3
-            )
9e0fa3
+        self.assert_parse_result(
9e0fa3
+            self.xml(
9e0fa3
+                """
9e0fa3
+                    <resource-agent>
9e0fa3
+                        <actions>
9e0fa3
+                            <action/>
9e0fa3
+                        </actions>
9e0fa3
+                    </resource-agent>
9e0fa3
+                """
9e0fa3
+            ),
9e0fa3
+            ResourceAgentMetadataOcf1_0(
9e0fa3
+                self.agent_name,
9e0fa3
+                shortdesc=None,
9e0fa3
+                longdesc=None,
9e0fa3
+                parameters=[],
9e0fa3
+                actions=[
9e0fa3
+                    ResourceAgentActionOcf1_0(
9e0fa3
+                        name="",
9e0fa3
+                        timeout=None,
9e0fa3
+                        interval=None,
9e0fa3
+                        role=None,
9e0fa3
+                        start_delay=None,
9e0fa3
+                        depth=None,
9e0fa3
+                        automatic=None,
9e0fa3
+                        on_target=None,
9e0fa3
+                    ),
9e0fa3
+                ],
9e0fa3
+            ),
9e0fa3
+        )
9e0fa3
 
9e0fa3
     def test_actions_multiple(self):
9e0fa3
         self.assert_parse_result(
9e0fa3
@@ -787,21 +823,6 @@ class ParseOcf10NoVersion(ParseOcf10BaseMixin, TestCase):
9e0fa3
 class ParseOcf10UnsupportedVersion(ParseOcf10BaseMixin, TestCase):
9e0fa3
     ocf_version = "0.1.2"
9e0fa3
 
9e0fa3
-    # These tests test that pcs raises an error if an agent doesn't conform to
9e0fa3
-    # OCF schema. There is, however, no validation against OCF schema for
9e0fa3
-    # agents with unsupported OCF version. That means no error message, pcs
9e0fa3
-    # tries to process the agent and crashes. However bad that sounds, it's
9e0fa3
-    # indended as that's how pcs behaved before OCF 1.1 was implemented.
9e0fa3
-    # There's therefore no point in running these tests.
9e0fa3
-
9e0fa3
-    def test_parameters_empty_parameter(self):
9e0fa3
-        # parameters must have at least 'name' attribute
9e0fa3
-        pass
9e0fa3
-
9e0fa3
-    def test_actions_empty_action(self):
9e0fa3
-        # actions must have at least 'name' attribute
9e0fa3
-        pass
9e0fa3
-
9e0fa3
 
9e0fa3
 class ParseOcf10ExplicitVersion(ParseOcf10BaseMixin, TestCase):
9e0fa3
     ocf_version = "1.0"
9e0fa3
-- 
9e0fa3
2.34.1
9e0fa3