From f5f42f2df8f360cb71ee7f42a050a412cfc80f6b Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Feb 15 2022 11:24:28 +0000 Subject: import pcs-0.10.12-6.el8 --- diff --git a/SOURCES/bz2050274-01-process-invalid-OCF-agents-the-same-way-as-before.patch b/SOURCES/bz2050274-01-process-invalid-OCF-agents-the-same-way-as-before.patch new file mode 100644 index 0000000..43a3d38 --- /dev/null +++ b/SOURCES/bz2050274-01-process-invalid-OCF-agents-the-same-way-as-before.patch @@ -0,0 +1,934 @@ +From ae3435418f0af6e5f22f463871aa90a5c5b2d15f Mon Sep 17 00:00:00 2001 +From: Tomas Jelinek +Date: Fri, 4 Feb 2022 16:23:18 +0100 +Subject: [PATCH 1/3] process invalid OCF agents as if they complied with OCF + 1.0 + +--- + pcs/common/reports/codes.py | 4 +- + pcs/common/reports/messages.py | 13 +- + pcs/lib/commands/resource.py | 3 +- + pcs/lib/commands/resource_agent.py | 4 +- + pcs/lib/commands/stonith.py | 3 +- + pcs/lib/resource_agent/__init__.py | 1 - + pcs/lib/resource_agent/error.py | 14 -- + pcs/lib/resource_agent/facade.py | 37 ++- + pcs/lib/resource_agent/xml.py | 15 +- + .../tier0/common/reports/test_messages.py | 18 +- + .../tier0/lib/resource_agent/test_facade.py | 47 ++++ + pcs_test/tier0/lib/resource_agent/test_xml.py | 226 ++++++++---------- + 12 files changed, 201 insertions(+), 184 deletions(-) + +diff --git a/pcs/common/reports/codes.py b/pcs/common/reports/codes.py +index 3e0512d9..e8dee00f 100644 +--- a/pcs/common/reports/codes.py ++++ b/pcs/common/reports/codes.py +@@ -36,8 +36,8 @@ ADD_REMOVE_CANNOT_SPECIFY_ADJACENT_ITEM_WITHOUT_ITEMS_TO_ADD = M( + "ADD_REMOVE_CANNOT_SPECIFY_ADJACENT_ITEM_WITHOUT_ITEMS_TO_ADD" + ) + AGENT_GENERIC_ERROR = M("AGENT_GENERIC_ERROR") +-AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION = M( +- "AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION" ++AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION_ASSUMED_VERSION = M( ++ "AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION_ASSUMED_VERSION" + ) + AGENT_NAME_GUESS_FOUND_MORE_THAN_ONE = M("AGENT_NAME_GUESS_FOUND_MORE_THAN_ONE") + AGENT_NAME_GUESS_FOUND_NONE = M("AGENT_NAME_GUESS_FOUND_NONE") +diff --git a/pcs/common/reports/messages.py b/pcs/common/reports/messages.py +index 9d665e73..7df1e1eb 100644 +--- a/pcs/common/reports/messages.py ++++ b/pcs/common/reports/messages.py +@@ -3789,9 +3789,9 @@ class AgentNameGuessFoundNone(ReportItemMessage): + + + @dataclass(frozen=True) +-class AgentImplementsUnsupportedOcfVersion(ReportItemMessage): ++class AgentImplementsUnsupportedOcfVersionAssumedVersion(ReportItemMessage): + """ +- Specified agent implements OCF version not supported by pcs ++ Specified agent implements OCF version not supported by pcs, assumed OCF 1.0 + + agent -- name of the agent + ocf_version -- OCF version implemented by the agent +@@ -3801,7 +3801,8 @@ class AgentImplementsUnsupportedOcfVersion(ReportItemMessage): + agent: str + ocf_version: str + supported_versions: List[str] +- _code = codes.AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION ++ assumed_version: str ++ _code = codes.AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION_ASSUMED_VERSION + + @property + def message(self) -> str: +@@ -3809,9 +3810,9 @@ class AgentImplementsUnsupportedOcfVersion(ReportItemMessage): + _is = format_plural(self.supported_versions, "is") + _version_list = format_list(self.supported_versions) + return ( +- f"Unable to process agent '{self.agent}' as it implements " +- f"unsupported OCF version '{self.ocf_version}', supported " +- f"{_version} {_is}: {_version_list}" ++ f"Agent '{self.agent}' implements unsupported OCF version " ++ f"'{self.ocf_version}', supported {_version} {_is}: " ++ f"{_version_list}; assumed version '{self.assumed_version}'" + ) + + +diff --git a/pcs/lib/commands/resource.py b/pcs/lib/commands/resource.py +index 82ce73e0..c4b6252c 100644 +--- a/pcs/lib/commands/resource.py ++++ b/pcs/lib/commands/resource.py +@@ -84,7 +84,6 @@ from pcs.lib.resource_agent import ( + ResourceAgentName, + split_resource_agent_name, + UnableToGetAgentMetadata, +- UnsupportedOcfVersion, + ) + from pcs.lib.tools import get_tmp_cib + from pcs.lib.validate import ValueTimeInterval +@@ -162,7 +161,7 @@ def _get_agent_facade( + else find_one_resource_agent_by_type(runner, report_processor, name) + ) + return factory.facade_from_parsed_name(split_name) +- except (UnableToGetAgentMetadata, UnsupportedOcfVersion) as e: ++ except UnableToGetAgentMetadata as e: + if allow_absent_agent: + report_processor.report( + resource_agent_error_to_report_item( +diff --git a/pcs/lib/commands/resource_agent.py b/pcs/lib/commands/resource_agent.py +index e6167b13..4a1831c0 100644 +--- a/pcs/lib/commands/resource_agent.py ++++ b/pcs/lib/commands/resource_agent.py +@@ -139,7 +139,9 @@ def _complete_agent_list( + try: + split_name = split_resource_agent_name(name) + metadata = ( +- agent_factory.facade_from_parsed_name(split_name).metadata ++ agent_factory.facade_from_parsed_name( ++ split_name, report_warnings=False ++ ).metadata + if describe + else name_to_void_metadata(split_name) + ) +diff --git a/pcs/lib/commands/stonith.py b/pcs/lib/commands/stonith.py +index 093f5be9..2aa299d7 100644 +--- a/pcs/lib/commands/stonith.py ++++ b/pcs/lib/commands/stonith.py +@@ -45,7 +45,6 @@ from pcs.lib.resource_agent import ( + ResourceAgentFacadeFactory, + ResourceAgentName, + UnableToGetAgentMetadata, +- UnsupportedOcfVersion, + ) + from pcs.lib.validate import validate_add_remove_items + from pcs.lib.xml_tools import get_root +@@ -62,7 +61,7 @@ def _get_agent_facade( + raise InvalidResourceAgentName(name) + full_name = ResourceAgentName("stonith", None, name) + return factory.facade_from_parsed_name(full_name) +- except (UnableToGetAgentMetadata, UnsupportedOcfVersion) as e: ++ except UnableToGetAgentMetadata as e: + if allow_absent_agent: + report_processor.report( + resource_agent_error_to_report_item( +diff --git a/pcs/lib/resource_agent/__init__.py b/pcs/lib/resource_agent/__init__.py +index 4548017f..c6086331 100644 +--- a/pcs/lib/resource_agent/__init__.py ++++ b/pcs/lib/resource_agent/__init__.py +@@ -10,7 +10,6 @@ from .error import ( + ResourceAgentError, + resource_agent_error_to_report_item, + UnableToGetAgentMetadata, +- UnsupportedOcfVersion, + ) + from .facade import ResourceAgentFacade, ResourceAgentFacadeFactory + from .list import ( +diff --git a/pcs/lib/resource_agent/error.py b/pcs/lib/resource_agent/error.py +index d4178333..f1dd7f3d 100644 +--- a/pcs/lib/resource_agent/error.py ++++ b/pcs/lib/resource_agent/error.py +@@ -2,8 +2,6 @@ from typing import Iterable + + from pcs.common import reports + +-from . import const +- + + class ResourceAgentError(Exception): + def __init__(self, agent_name: str): +@@ -37,12 +35,6 @@ class UnableToGetAgentMetadata(ResourceAgentError): + self.message = message + + +-class UnsupportedOcfVersion(ResourceAgentError): +- def __init__(self, agent_name: str, ocf_version: str): +- super().__init__(agent_name) +- self.ocf_version = ocf_version +- +- + def resource_agent_error_to_report_item( + e: ResourceAgentError, + severity: reports.ReportItemSeverity = reports.ReportItemSeverity.error(), +@@ -69,10 +61,4 @@ def resource_agent_error_to_report_item( + message = reports.messages.UnableToGetAgentMetadata( + e.agent_name, e.message + ) +- elif isinstance(e, UnsupportedOcfVersion): +- message = reports.messages.AgentImplementsUnsupportedOcfVersion( +- e.agent_name, +- e.ocf_version, +- sorted(const.SUPPORTED_OCF_VERSIONS), +- ) + return reports.ReportItem(severity, message) +diff --git a/pcs/lib/resource_agent/facade.py b/pcs/lib/resource_agent/facade.py +index 4dbb59b8..dea59a1a 100644 +--- a/pcs/lib/resource_agent/facade.py ++++ b/pcs/lib/resource_agent/facade.py +@@ -188,18 +188,32 @@ class ResourceAgentFacadeFactory: + self._fenced_metadata = None + + def facade_from_parsed_name( +- self, name: ResourceAgentName ++ self, name: ResourceAgentName, report_warnings=True + ) -> ResourceAgentFacade: + """ + Create ResourceAgentFacade based on specified agent name + + name -- agent name to get a facade for + """ +- return self._facade_from_metadata( +- ocf_version_to_ocf_unified( +- parse_metadata(name, load_metadata(self._runner, name)) +- ) ++ metadata, raw_ocf_version = parse_metadata( ++ name, ++ load_metadata(self._runner, name), + ) ++ if ( ++ report_warnings ++ and raw_ocf_version not in const.SUPPORTED_OCF_VERSIONS ++ ): ++ self._report_processor.report( ++ reports.ReportItem.warning( ++ reports.messages.AgentImplementsUnsupportedOcfVersionAssumedVersion( ++ name.full_name, ++ raw_ocf_version, ++ sorted(const.SUPPORTED_OCF_VERSIONS), ++ const.OCF_1_0, ++ ) ++ ) ++ ) ++ return self._facade_from_metadata(ocf_version_to_ocf_unified(metadata)) + + def void_facade_from_parsed_name( + self, name: ResourceAgentName +@@ -232,15 +246,12 @@ class ResourceAgentFacadeFactory: + const.FAKE_AGENT_STANDARD, None, const.PACEMAKER_FENCED + ) + try: ++ metadata, _ = parse_metadata( ++ agent_name, ++ load_fake_agent_metadata(self._runner, agent_name.type), ++ ) + self._fenced_metadata = ocf_unified_to_pcs( +- ocf_version_to_ocf_unified( +- parse_metadata( +- agent_name, +- load_fake_agent_metadata( +- self._runner, agent_name.type +- ), +- ) +- ) ++ ocf_version_to_ocf_unified(metadata) + ) + except ResourceAgentError as e: + # If pcs is unable to load fenced metadata, cache an empty +diff --git a/pcs/lib/resource_agent/xml.py b/pcs/lib/resource_agent/xml.py +index 82f8fbfa..1ba97216 100644 +--- a/pcs/lib/resource_agent/xml.py ++++ b/pcs/lib/resource_agent/xml.py +@@ -8,7 +8,7 @@ from pcs.common.tools import xml_fromstring + from pcs.lib.external import CommandRunner + + from . import const +-from .error import UnableToGetAgentMetadata, UnsupportedOcfVersion ++from .error import UnableToGetAgentMetadata + from .types import ( + FakeAgentName, + ResourceAgentActionOcf1_0, +@@ -137,8 +137,11 @@ def load_fake_agent_metadata( + + + def parse_metadata( +- name: ResourceAgentName, metadata: _Element +-) -> Union[ResourceAgentMetadataOcf1_0, ResourceAgentMetadataOcf1_1]: ++ name: ResourceAgentName, ++ metadata: _Element, ++) -> Tuple[ ++ Union[ResourceAgentMetadataOcf1_0, ResourceAgentMetadataOcf1_1], str ++]: + """ + Parse XML metadata to a dataclass + +@@ -146,11 +149,9 @@ def parse_metadata( + metadata -- metadata XML document + """ + ocf_version = _get_ocf_version(metadata) +- if ocf_version == const.OCF_1_0: +- return _parse_agent_1_0(name, metadata) + if ocf_version == const.OCF_1_1: +- return _parse_agent_1_1(name, metadata) +- raise UnsupportedOcfVersion(name.full_name, ocf_version) ++ return _parse_agent_1_1(name, metadata), ocf_version ++ return _parse_agent_1_0(name, metadata), ocf_version + + + def _parse_agent_1_0( +diff --git a/pcs_test/tier0/common/reports/test_messages.py b/pcs_test/tier0/common/reports/test_messages.py +index 4a7b4945..b885a9eb 100644 +--- a/pcs_test/tier0/common/reports/test_messages.py ++++ b/pcs_test/tier0/common/reports/test_messages.py +@@ -2833,22 +2833,22 @@ class AgentNameGuessFoundNone(NameBuildTest): + ) + + +-class AgentImplementsUnsupportedOcfVersion(NameBuildTest): ++class AgentImplementsUnsupportedOcfVersionAssumedVersion(NameBuildTest): + def test_singular(self): + self.assert_message_from_report( +- "Unable to process agent 'agent-name' as it implements unsupported " +- "OCF version 'ocf-2.3', supported version is: 'v1'", +- reports.AgentImplementsUnsupportedOcfVersion( +- "agent-name", "ocf-2.3", ["v1"] ++ "Agent 'agent-name' implements unsupported OCF version 'ocf-2.3', " ++ "supported version is: 'v1'; assumed version 'v1'", ++ reports.AgentImplementsUnsupportedOcfVersionAssumedVersion( ++ "agent-name", "ocf-2.3", ["v1"], "v1" + ), + ) + + def test_plural(self): + self.assert_message_from_report( +- "Unable to process agent 'agent-name' as it implements unsupported " +- "OCF version 'ocf-2.3', supported versions are: 'v1', 'v2', 'v3'", +- reports.AgentImplementsUnsupportedOcfVersion( +- "agent-name", "ocf-2.3", ["v1", "v2", "v3"] ++ "Agent 'agent-name' implements unsupported OCF version 'ocf-2.3', " ++ "supported versions are: 'v1', 'v2', 'v3'; assumed version 'v1'", ++ reports.AgentImplementsUnsupportedOcfVersionAssumedVersion( ++ "agent-name", "ocf-2.3", ["v1", "v2", "v3"], "v1" + ), + ) + +diff --git a/pcs_test/tier0/lib/resource_agent/test_facade.py b/pcs_test/tier0/lib/resource_agent/test_facade.py +index 654eb35e..f6a9899c 100644 +--- a/pcs_test/tier0/lib/resource_agent/test_facade.py ++++ b/pcs_test/tier0/lib/resource_agent/test_facade.py +@@ -92,6 +92,14 @@ class ResourceAgentFacadeFactory(TestCase): + + + """ ++ _fixture_agent_bad_version_xml = """ ++ ++ 0.1.2 ++ ++ ++ ++ ++ """ + _fixture_fenced_xml = """ + + +@@ -125,6 +133,45 @@ class ResourceAgentFacadeFactory(TestCase): + self.assertEqual(facade.metadata.name, name) + self.assertTrue(facade.metadata.agent_exists) + ++ def test_facade_bad_ocf_version(self): ++ name = ra.ResourceAgentName("service", None, "daemon") ++ self.config.runner.pcmk.load_agent( ++ agent_name="service:daemon", ++ stdout=self._fixture_agent_bad_version_xml, ++ ) ++ ++ env = self.env_assist.get_env() ++ facade = ra.ResourceAgentFacadeFactory( ++ env.cmd_runner(), env.report_processor ++ ).facade_from_parsed_name(name) ++ self.assertEqual(facade.metadata.name, name) ++ self.assertTrue(facade.metadata.agent_exists) ++ self.env_assist.assert_reports( ++ [ ++ fixture.warn( ++ reports.codes.AGENT_IMPLEMENTS_UNSUPPORTED_OCF_VERSION_ASSUMED_VERSION, ++ agent=name.full_name, ++ ocf_version="0.1.2", ++ supported_versions=sorted(ra.const.SUPPORTED_OCF_VERSIONS), ++ assumed_version=ra.const.OCF_1_0, ++ ) ++ ] ++ ) ++ ++ def test_facade_bad_ocf_version_disabled_warning(self): ++ name = ra.ResourceAgentName("service", None, "daemon") ++ self.config.runner.pcmk.load_agent( ++ agent_name="service:daemon", ++ stdout=self._fixture_agent_bad_version_xml, ++ ) ++ ++ env = self.env_assist.get_env() ++ facade = ra.ResourceAgentFacadeFactory( ++ env.cmd_runner(), env.report_processor ++ ).facade_from_parsed_name(name, report_warnings=False) ++ self.assertEqual(facade.metadata.name, name) ++ self.assertTrue(facade.metadata.agent_exists) ++ + def test_facade_missing_agent(self): + name = ra.ResourceAgentName("service", None, "daemon") + self.config.runner.pcmk.load_agent( +diff --git a/pcs_test/tier0/lib/resource_agent/test_xml.py b/pcs_test/tier0/lib/resource_agent/test_xml.py +index c4176f32..26bbbb7d 100644 +--- a/pcs_test/tier0/lib/resource_agent/test_xml.py ++++ b/pcs_test/tier0/lib/resource_agent/test_xml.py +@@ -351,6 +351,7 @@ class LoadFakeAgentMetadata(TestCase): + class ParseOcfToolsMixin: + agent_name = ra.ResourceAgentName("ocf", "pacemaker", "Dummy") + ocf_version = None ++ parsed_ocf_version = None + + def parse(self, xml, agent_name=None): + agent_name = agent_name or self.agent_name +@@ -383,19 +384,17 @@ class ParseOcfToolsMixin: + version_el.text = ocf_version + return etree_to_str(dom) + +- +-class ParseOcfGeneric(ParseOcfToolsMixin, TestCase): +- def test_unsupported_ocf_version(self): +- with self.assertRaises(ra.UnsupportedOcfVersion) as cm: +- self.parse(self.xml("""""", ocf_version="1.2")) +- self.assertEqual(cm.exception.agent_name, self.agent_name.full_name) +- self.assertEqual(cm.exception.ocf_version, "1.2") ++ def assert_parse_result(self, xml, metadata): ++ self.assertEqual( ++ self.parse(xml), ++ (metadata, self.parsed_ocf_version or self.ocf_version), ++ ) + + + class ParseOcf10BaseMixin(ParseOcfToolsMixin): + def test_empty_agent(self): +- self.assertEqual( +- self.parse(self.xml("""""")), ++ self.assert_parse_result( ++ self.xml(""""""), + ResourceAgentMetadataOcf1_0( + self.agent_name, + shortdesc=None, +@@ -406,16 +405,14 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_desc_element(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + This is a shortdesc + This is a longdesc + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -427,16 +424,14 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_desc_element_empty(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -448,15 +443,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_desc_attribute(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -468,13 +461,11 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_desc_attribute_empty(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -486,15 +477,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_desc_element_and_attribute(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + shortdesc element + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -506,15 +495,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_desc_element_empty_and_attribute(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -526,15 +513,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_desc_element_empty_and_attribute_empty(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -546,15 +531,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_parameters_empty_list(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -581,17 +564,15 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_parameters_minimal(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -616,10 +597,9 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_parameters_all_settings(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -657,10 +636,9 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_parameters_content(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + +@@ -676,7 +654,6 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -713,15 +690,13 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_actions_empty_list(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -748,10 +723,9 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_actions_multiple(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + +@@ -764,7 +738,6 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + + + """ +- ) + ), + ResourceAgentMetadataOcf1_0( + self.agent_name, +@@ -808,7 +781,26 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + + + class ParseOcf10NoVersion(ParseOcf10BaseMixin, TestCase): +- pass ++ parsed_ocf_version = "1.0" ++ ++ ++class ParseOcf10UnsupportedVersion(ParseOcf10BaseMixin, TestCase): ++ ocf_version = "0.1.2" ++ ++ # These tests test that pcs raises an error if an agent doesn't conform to ++ # OCF schema. There is, however, no validation against OCF schema for ++ # agents with unsupported OCF version. That means no error message, pcs ++ # tries to process the agent and crashes. However bad that sounds, it's ++ # indended as that's how pcs behaved before OCF 1.1 was implemented. ++ # There's therefore no point in running these tests. ++ ++ def test_parameters_empty_parameter(self): ++ # parameters must have at least 'name' attribute ++ pass ++ ++ def test_actions_empty_action(self): ++ # actions must have at least 'name' attribute ++ pass + + + class ParseOcf10ExplicitVersion(ParseOcf10BaseMixin, TestCase): +@@ -819,8 +811,8 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ocf_version = "1.1" + + def test_empty_agent(self): +- self.assertEqual( +- self.parse(self.xml("""""")), ++ self.assert_parse_result( ++ self.xml(""""""), + ResourceAgentMetadataOcf1_1( + self.agent_name, + shortdesc=None, +@@ -831,16 +823,14 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_desc_element(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + This is a shortdesc + This is a longdesc + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +@@ -852,16 +842,14 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_desc_element_empty(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +@@ -873,15 +861,13 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_parameters_empty_list(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +@@ -908,17 +894,15 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_parameters_minimal(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +@@ -945,10 +929,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_parameters_deprecated_minimal(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + +@@ -957,7 +940,6 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +@@ -984,10 +966,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_parameters_deprecated_replaced_with(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + +@@ -999,7 +980,6 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +@@ -1026,10 +1006,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_parameters_all_settings(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +@@ -1075,10 +1053,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_parameters_content(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + +@@ -1094,7 +1071,6 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +@@ -1135,15 +1111,13 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_actions_empty_list(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +@@ -1170,10 +1144,9 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + ) + + def test_actions_multiple(self): +- self.assertEqual( +- self.parse( +- self.xml( +- """ ++ self.assert_parse_result( ++ self.xml( ++ """ + + + +@@ -1186,7 +1159,6 @@ class ParseOcf11(ParseOcfToolsMixin, TestCase): + + + """ +- ) + ), + ResourceAgentMetadataOcf1_1( + self.agent_name, +-- +2.34.1 + diff --git a/SOURCES/bz2050274-02-relax-OCF-1.0-parser.patch b/SOURCES/bz2050274-02-relax-OCF-1.0-parser.patch new file mode 100644 index 0000000..8e8c073 --- /dev/null +++ b/SOURCES/bz2050274-02-relax-OCF-1.0-parser.patch @@ -0,0 +1,587 @@ +From 65b30a04a234449cb4aa65606d47bf1d673592a4 Mon Sep 17 00:00:00 2001 +From: Tomas Jelinek +Date: Wed, 9 Feb 2022 11:16:49 +0100 +Subject: [PATCH 2/3] relax OCF 1.0 parser + +--- + pcs/lib/resource_agent/facade.py | 50 ++++-- + pcs/lib/resource_agent/ocf_transform.py | 51 +++++- + pcs/lib/resource_agent/xml.py | 8 +- + .../tier0/lib/resource_agent/test_facade.py | 44 +++++ + .../lib/resource_agent/test_ocf_transform.py | 48 +++++- + pcs_test/tier0/lib/resource_agent/test_xml.py | 155 ++++++++++-------- + 6 files changed, 256 insertions(+), 100 deletions(-) + +diff --git a/pcs/lib/resource_agent/facade.py b/pcs/lib/resource_agent/facade.py +index dea59a1a..8a65eb1c 100644 +--- a/pcs/lib/resource_agent/facade.py ++++ b/pcs/lib/resource_agent/facade.py +@@ -2,12 +2,19 @@ from collections import defaultdict + from dataclasses import replace as dc_replace + from typing import Dict, Iterable, List, Optional, Set + ++from lxml import etree ++ ++from pcs import settings + from pcs.common import reports + from pcs.lib import validate + from pcs.lib.external import CommandRunner + + from . import const +-from .error import ResourceAgentError, resource_agent_error_to_report_item ++from .error import ( ++ ResourceAgentError, ++ resource_agent_error_to_report_item, ++ UnableToGetAgentMetadata, ++) + from .name import name_to_void_metadata + from .ocf_transform import ocf_version_to_ocf_unified + from .pcs_transform import get_additional_trace_parameters, ocf_unified_to_pcs +@@ -195,24 +202,33 @@ class ResourceAgentFacadeFactory: + + name -- agent name to get a facade for + """ +- metadata, raw_ocf_version = parse_metadata( +- name, +- load_metadata(self._runner, name), +- ) +- if ( +- report_warnings +- and raw_ocf_version not in const.SUPPORTED_OCF_VERSIONS +- ): +- self._report_processor.report( +- reports.ReportItem.warning( +- reports.messages.AgentImplementsUnsupportedOcfVersionAssumedVersion( +- name.full_name, +- raw_ocf_version, +- sorted(const.SUPPORTED_OCF_VERSIONS), +- const.OCF_1_0, ++ dom_metadata = load_metadata(self._runner, name) ++ metadata, raw_ocf_version = parse_metadata(name, dom_metadata) ++ if report_warnings: ++ if raw_ocf_version not in const.SUPPORTED_OCF_VERSIONS: ++ self._report_processor.report( ++ reports.ReportItem.warning( ++ reports.messages.AgentImplementsUnsupportedOcfVersionAssumedVersion( ++ name.full_name, ++ raw_ocf_version, ++ sorted(const.SUPPORTED_OCF_VERSIONS), ++ const.OCF_1_0, ++ ) + ) + ) +- ) ++ if raw_ocf_version != const.OCF_1_1: ++ try: ++ etree.RelaxNG( ++ file=settings.path.ocf_1_0_schema ++ ).assertValid(dom_metadata) ++ except etree.DocumentInvalid as e: ++ self._report_processor.report( ++ resource_agent_error_to_report_item( ++ UnableToGetAgentMetadata(name.full_name, str(e)), ++ severity=reports.ReportItemSeverity.warning(), ++ is_stonith=name.is_stonith, ++ ) ++ ) + return self._facade_from_metadata(ocf_version_to_ocf_unified(metadata)) + + def void_facade_from_parsed_name( +diff --git a/pcs/lib/resource_agent/ocf_transform.py b/pcs/lib/resource_agent/ocf_transform.py +index e841b55e..7e6a14ad 100644 +--- a/pcs/lib/resource_agent/ocf_transform.py ++++ b/pcs/lib/resource_agent/ocf_transform.py +@@ -67,20 +67,42 @@ def _ocf_1_1_to_ocf_unified( + longdesc=metadata.longdesc, + parameters=_ocf_1_1_parameter_list_to_ocf_unified(metadata.parameters), + # OCF 1.1 actions are the same as in OCF 1.0 +- actions=_ocf_1_0_action_list_to_ocf_unified(metadata.actions), ++ actions=_ocf_1_1_action_list_to_ocf_unified(metadata.actions), + ) + + + def _ocf_1_0_action_list_to_ocf_unified( +- action_list: Iterable[ +- Union[ResourceAgentActionOcf1_0, ResourceAgentActionOcf1_1] +- ], ++ action_list: Iterable[ResourceAgentActionOcf1_0], + ) -> List[ResourceAgentAction]: + """ + Transform OCF 1.0 actions to a universal format + + action_list -- actions according OCF 1.0 + """ ++ return [ ++ ResourceAgentAction( ++ name=action.name, ++ timeout=action.timeout, ++ interval=action.interval, ++ role=action.role, ++ start_delay=action.start_delay, ++ depth=action.depth, ++ automatic=_bool_value_legacy(action.automatic), ++ on_target=_bool_value_legacy(action.on_target), ++ ) ++ for action in action_list ++ if action.name ++ ] ++ ++ ++def _ocf_1_1_action_list_to_ocf_unified( ++ action_list: Iterable[ResourceAgentActionOcf1_1], ++) -> List[ResourceAgentAction]: ++ """ ++ Transform OCF 1.1 actions to a universal format ++ ++ action_list -- actions according OCF 1.1 ++ """ + return [ + ResourceAgentAction( + name=action.name, +@@ -111,6 +133,8 @@ def _ocf_1_0_parameter_list_to_ocf_unified( + + result = [] + for parameter in parameter_list: ++ if not parameter.name: ++ continue + result.append( + ResourceAgentParameter( + name=parameter.name, +@@ -119,17 +143,17 @@ def _ocf_1_0_parameter_list_to_ocf_unified( + type=parameter.type, + default=parameter.default, + enum_values=parameter.enum_values, +- required=_bool_value(parameter.required), ++ required=_bool_value_legacy(parameter.required), + advanced=False, +- deprecated=_bool_value(parameter.deprecated), ++ deprecated=_bool_value_legacy(parameter.deprecated), + deprecated_by=sorted(deprecated_by_dict[parameter.name]), + deprecated_desc=None, + unique_group=( + f"{const.DEFAULT_UNIQUE_GROUP_PREFIX}{parameter.name}" +- if _bool_value(parameter.unique) ++ if _bool_value_legacy(parameter.unique) + else None + ), +- reloadable=_bool_value(parameter.unique), ++ reloadable=_bool_value_legacy(parameter.unique), + ) + ) + return result +@@ -170,3 +194,14 @@ def _bool_value(value: Optional[str]) -> bool: + value -- raw bool value + """ + return value == "1" ++ ++ ++def _bool_value_legacy(value: Optional[str]) -> bool: ++ """ ++ Transform raw bool value from metadata to bool type in backward compatible way ++ ++ value -- raw bool value ++ """ ++ return ( ++ False if not value else value.lower() in {"true", "on", "yes", "y", "1"} ++ ) +diff --git a/pcs/lib/resource_agent/xml.py b/pcs/lib/resource_agent/xml.py +index 1ba97216..0fc70527 100644 +--- a/pcs/lib/resource_agent/xml.py ++++ b/pcs/lib/resource_agent/xml.py +@@ -94,9 +94,7 @@ def _metadata_xml_to_dom(metadata: str) -> _Element: + """ + dom = xml_fromstring(metadata) + ocf_version = _get_ocf_version(dom) +- if ocf_version == const.OCF_1_0: +- etree.RelaxNG(file=settings.path.ocf_1_0_schema).assertValid(dom) +- elif ocf_version == const.OCF_1_1: ++ if ocf_version == const.OCF_1_1: + etree.RelaxNG(file=settings.path.ocf_1_1_schema).assertValid(dom) + return dom + +@@ -230,7 +228,7 @@ def _parse_parameters_1_0( + ) + result.append( + ResourceAgentParameterOcf1_0( +- name=str(parameter_el.attrib["name"]), ++ name=str(parameter_el.get("name", "")), + shortdesc=_get_shortdesc(parameter_el), + longdesc=_get_longdesc(parameter_el), + type=value_type, +@@ -286,7 +284,7 @@ def _parse_parameters_1_1( + def _parse_actions_1_0(element: _Element) -> List[ResourceAgentActionOcf1_0]: + return [ + ResourceAgentActionOcf1_0( +- name=str(action.attrib["name"]), ++ name=str(action.get("name", "")), + timeout=action.get("timeout"), + interval=action.get("interval"), + role=action.get("role"), +diff --git a/pcs_test/tier0/lib/resource_agent/test_facade.py b/pcs_test/tier0/lib/resource_agent/test_facade.py +index f6a9899c..313dfa2b 100644 +--- a/pcs_test/tier0/lib/resource_agent/test_facade.py ++++ b/pcs_test/tier0/lib/resource_agent/test_facade.py +@@ -100,6 +100,13 @@ class ResourceAgentFacadeFactory(TestCase): + + + """ ++ _fixture_agent_not_valid_xml = """ ++ ++ ++ ++ ++ ++ """ + _fixture_fenced_xml = """ + + +@@ -172,6 +179,43 @@ class ResourceAgentFacadeFactory(TestCase): + self.assertEqual(facade.metadata.name, name) + self.assertTrue(facade.metadata.agent_exists) + ++ def test_facade_ocf_1_0_not_valid(self): ++ name = ra.ResourceAgentName("service", None, "daemon") ++ self.config.runner.pcmk.load_agent( ++ agent_name="service:daemon", ++ stdout=self._fixture_agent_not_valid_xml, ++ ) ++ ++ env = self.env_assist.get_env() ++ facade = ra.ResourceAgentFacadeFactory( ++ env.cmd_runner(), env.report_processor ++ ).facade_from_parsed_name(name) ++ self.assertEqual(facade.metadata.name, name) ++ self.assertTrue(facade.metadata.agent_exists) ++ self.env_assist.assert_reports( ++ [ ++ fixture.warn( ++ reports.codes.UNABLE_TO_GET_AGENT_METADATA, ++ agent=name.full_name, ++ reason="Element parameter failed to validate attributes, line 3", ++ ) ++ ] ++ ) ++ ++ def test_facade_ocf_1_0_not_valid_disabled_warning(self): ++ name = ra.ResourceAgentName("service", None, "daemon") ++ self.config.runner.pcmk.load_agent( ++ agent_name="service:daemon", ++ stdout=self._fixture_agent_not_valid_xml, ++ ) ++ ++ env = self.env_assist.get_env() ++ facade = ra.ResourceAgentFacadeFactory( ++ env.cmd_runner(), env.report_processor ++ ).facade_from_parsed_name(name, report_warnings=False) ++ self.assertEqual(facade.metadata.name, name) ++ self.assertTrue(facade.metadata.agent_exists) ++ + def test_facade_missing_agent(self): + name = ra.ResourceAgentName("service", None, "daemon") + self.config.runner.pcmk.load_agent( +diff --git a/pcs_test/tier0/lib/resource_agent/test_ocf_transform.py b/pcs_test/tier0/lib/resource_agent/test_ocf_transform.py +index 9e41b6af..d0de86e5 100644 +--- a/pcs_test/tier0/lib/resource_agent/test_ocf_transform.py ++++ b/pcs_test/tier0/lib/resource_agent/test_ocf_transform.py +@@ -66,6 +66,18 @@ class OcfVersionToOcfUnified(TestCase): + obsoletes=None, + unique=None, + ), ++ ra.types.ResourceAgentParameterOcf1_0( ++ name="", ++ shortdesc="Parameters with no name are ignored", ++ longdesc=None, ++ type="string", ++ default=None, ++ enum_values=None, ++ required=None, ++ deprecated=None, ++ obsoletes=None, ++ unique=None, ++ ), + ra.types.ResourceAgentParameterOcf1_0( + name="param_2", + shortdesc="param_2 shortdesc", +@@ -109,10 +121,10 @@ class OcfVersionToOcfUnified(TestCase): + type="string", + default=None, + enum_values=None, +- required="1", +- deprecated="1", ++ required="yeS", ++ deprecated="True", + obsoletes="param_4", +- unique="1", ++ unique="on", + ), + ra.types.ResourceAgentParameterOcf1_0( + name="param_6", +@@ -138,6 +150,16 @@ class OcfVersionToOcfUnified(TestCase): + automatic=None, + on_target=None, + ), ++ ra.types.ResourceAgentActionOcf1_0( ++ name="", ++ timeout=None, ++ interval=None, ++ role=None, ++ start_delay=None, ++ depth=None, ++ automatic=None, ++ on_target=None, ++ ), + ra.types.ResourceAgentActionOcf1_0( + name="action_2", + timeout="12", +@@ -158,6 +180,16 @@ class OcfVersionToOcfUnified(TestCase): + automatic="1", + on_target="0", + ), ++ ra.types.ResourceAgentActionOcf1_0( ++ name="action_4", ++ timeout=None, ++ interval=None, ++ role=None, ++ start_delay=None, ++ depth=None, ++ automatic="yes", ++ on_target="True", ++ ), + ], + ) + metadata_out = ra.ResourceAgentMetadata( +@@ -289,6 +321,16 @@ class OcfVersionToOcfUnified(TestCase): + automatic=True, + on_target=False, + ), ++ ra.ResourceAgentAction( ++ name="action_4", ++ timeout=None, ++ interval=None, ++ role=None, ++ start_delay=None, ++ depth=None, ++ automatic=True, ++ on_target=True, ++ ), + ], + ) + self.assertEqual( +diff --git a/pcs_test/tier0/lib/resource_agent/test_xml.py b/pcs_test/tier0/lib/resource_agent/test_xml.py +index 26bbbb7d..ea055ee2 100644 +--- a/pcs_test/tier0/lib/resource_agent/test_xml.py ++++ b/pcs_test/tier0/lib/resource_agent/test_xml.py +@@ -164,8 +164,13 @@ class MetadataXmlToDom(TestCase): + ra.xml._metadata_xml_to_dom("not an xml") + + def test_no_version_not_valid(self): +- with self.assertRaises(etree.DocumentInvalid): +- ra.xml._metadata_xml_to_dom("") ++ # pylint: disable=no-self-use ++ metadata = """ ++ ++ """ ++ assert_xml_equal( ++ metadata, etree_to_str(ra.xml._metadata_xml_to_dom(metadata)) ++ ) + + def test_no_version_valid(self): + # pylint: disable=no-self-use +@@ -178,14 +183,15 @@ class MetadataXmlToDom(TestCase): + ) + + def test_ocf_1_0_not_valid(self): +- with self.assertRaises(etree.DocumentInvalid): +- ra.xml._metadata_xml_to_dom( +- """ +- +- 1.0 +- +- """ +- ) ++ # pylint: disable=no-self-use ++ metadata = """ ++ ++ 1.0 ++ ++ """ ++ assert_xml_equal( ++ metadata, etree_to_str(ra.xml._metadata_xml_to_dom(metadata)) ++ ) + + def test_ocf_1_0_valid(self): + # pylint: disable=no-self-use +@@ -273,19 +279,16 @@ class LoadMetadata(TestCase): + + def test_not_valid_xml(self): + agent_name = ra.ResourceAgentName("ocf", "pacemaker", "Dummy") ++ metadata = "" + self.config.runner.pcmk.load_agent( + agent_name="ocf:pacemaker:Dummy", +- stdout="", ++ stdout=metadata, + ) + + env = self.env_assist.get_env() +- with self.assertRaises(ra.UnableToGetAgentMetadata) as cm: +- ra.xml.load_metadata(env.cmd_runner(), agent_name) +- self.assertEqual(cm.exception.agent_name, "ocf:pacemaker:Dummy") +- self.assertTrue( +- cm.exception.message.startswith( +- "Element resource-agent failed to validate" +- ) ++ assert_xml_equal( ++ metadata, ++ etree_to_str(ra.xml.load_metadata(env.cmd_runner(), agent_name)), + ) + + +@@ -335,16 +338,15 @@ class LoadFakeAgentMetadata(TestCase): + + def test_not_valid_xml(self): + agent_name = ra.const.PACEMAKER_FENCED +- self.config.runner.pcmk.load_fenced_metadata(stdout="") ++ metadata = "" ++ self.config.runner.pcmk.load_fenced_metadata(stdout=metadata) + + env = self.env_assist.get_env() +- with self.assertRaises(ra.UnableToGetAgentMetadata) as cm: +- ra.xml.load_fake_agent_metadata(env.cmd_runner(), agent_name) +- self.assertEqual(cm.exception.agent_name, "pacemaker-fenced") +- self.assertTrue( +- cm.exception.message.startswith( +- "Element resource-agent failed to validate" +- ) ++ assert_xml_equal( ++ metadata, ++ etree_to_str( ++ ra.xml.load_fake_agent_metadata(env.cmd_runner(), agent_name) ++ ), + ) + + +@@ -549,19 +551,37 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_parameters_empty_parameter(self): +- # parameters must have at least 'name' attribute +- with self.assertRaises(ra.UnableToGetAgentMetadata): +- self.parse( +- self.xml( +- """ +- +- +- +- +- +- """ +- ) +- ) ++ self.assert_parse_result( ++ self.xml( ++ """ ++ ++ ++ ++ ++ ++ """ ++ ), ++ ResourceAgentMetadataOcf1_0( ++ self.agent_name, ++ shortdesc=None, ++ longdesc=None, ++ parameters=[ ++ ResourceAgentParameterOcf1_0( ++ name="", ++ shortdesc=None, ++ longdesc=None, ++ type="string", ++ default=None, ++ enum_values=None, ++ required=None, ++ deprecated=None, ++ obsoletes=None, ++ unique=None, ++ ) ++ ], ++ actions=[], ++ ), ++ ) + + def test_parameters_minimal(self): + self.assert_parse_result( +@@ -708,19 +728,35 @@ class ParseOcf10BaseMixin(ParseOcfToolsMixin): + ) + + def test_actions_empty_action(self): +- # actions must have at least 'name' attribute +- with self.assertRaises(ra.UnableToGetAgentMetadata): +- self.parse( +- self.xml( +- """ +- +- +- +- +- +- """ +- ) +- ) ++ self.assert_parse_result( ++ self.xml( ++ """ ++ ++ ++ ++ ++ ++ """ ++ ), ++ ResourceAgentMetadataOcf1_0( ++ self.agent_name, ++ shortdesc=None, ++ longdesc=None, ++ parameters=[], ++ actions=[ ++ ResourceAgentActionOcf1_0( ++ name="", ++ timeout=None, ++ interval=None, ++ role=None, ++ start_delay=None, ++ depth=None, ++ automatic=None, ++ on_target=None, ++ ), ++ ], ++ ), ++ ) + + def test_actions_multiple(self): + self.assert_parse_result( +@@ -787,21 +823,6 @@ class ParseOcf10NoVersion(ParseOcf10BaseMixin, TestCase): + class ParseOcf10UnsupportedVersion(ParseOcf10BaseMixin, TestCase): + ocf_version = "0.1.2" + +- # These tests test that pcs raises an error if an agent doesn't conform to +- # OCF schema. There is, however, no validation against OCF schema for +- # agents with unsupported OCF version. That means no error message, pcs +- # tries to process the agent and crashes. However bad that sounds, it's +- # indended as that's how pcs behaved before OCF 1.1 was implemented. +- # There's therefore no point in running these tests. +- +- def test_parameters_empty_parameter(self): +- # parameters must have at least 'name' attribute +- pass +- +- def test_actions_empty_action(self): +- # actions must have at least 'name' attribute +- pass +- + + class ParseOcf10ExplicitVersion(ParseOcf10BaseMixin, TestCase): + ocf_version = "1.0" +-- +2.34.1 + diff --git a/SOURCES/do-not-support-cluster-setup-with-udp-u-transport.patch b/SOURCES/do-not-support-cluster-setup-with-udp-u-transport.patch index a899160..a25b509 100644 --- a/SOURCES/do-not-support-cluster-setup-with-udp-u-transport.patch +++ b/SOURCES/do-not-support-cluster-setup-with-udp-u-transport.patch @@ -1,7 +1,7 @@ -From 5ea2b99f6bd32b74e20ad2f83d131a735df1cd24 Mon Sep 17 00:00:00 2001 +From f7230b92c946add84ed6072c20a4df5d97c77de2 Mon Sep 17 00:00:00 2001 From: Ivan Devat Date: Tue, 20 Nov 2018 15:03:56 +0100 -Subject: [PATCH 2/2] do not support cluster setup with udp(u) transport +Subject: [PATCH 3/3] do not support cluster setup with udp(u) transport --- pcs/pcs.8.in | 2 ++ diff --git a/SPECS/pcs.spec b/SPECS/pcs.spec index c045f3a..e5441aa 100644 --- a/SPECS/pcs.spec +++ b/SPECS/pcs.spec @@ -1,6 +1,6 @@ Name: pcs Version: 0.10.12 -Release: 5%{?dist} +Release: 6%{?dist} # https://docs.fedoraproject.org/en-US/packaging-guidelines/LicensingGuidelines/ # https://fedoraproject.org/wiki/Licensing:Main?rd=Licensing#Good_Licenses # GPLv2: pcs @@ -125,6 +125,8 @@ Patch4: bz2036633-01-Make-ocf-linbit-drbd-agent-pass-OCF-validation.patch Patch5: bz1990784-01-Multiple-fixes-of-pcs-resource-move-autodelete-comma.patch Patch6: bz2022463-01-fix-creating-empty-cib.patch Patch7: bz2047983-01-Fix-snmp-client.patch +Patch8: bz2050274-01-process-invalid-OCF-agents-the-same-way-as-before.patch +Patch9: bz2050274-02-relax-OCF-1.0-parser.patch # Downstream patches do not come from upstream. They adapt pcs for specific # RHEL needs. @@ -334,6 +336,8 @@ update_times_patch %{PATCH4} update_times_patch %{PATCH5} update_times_patch %{PATCH6} update_times_patch %{PATCH7} +update_times_patch %{PATCH8} +update_times_patch %{PATCH9} update_times_patch %{PATCH101} cp -f %SOURCE1 %{pcsd_public_dir}/images @@ -583,6 +587,10 @@ remove_all_tests %license pyagentx_LICENSE.txt %changelog +* Fri Feb 11 2022 Miroslav Lisik - 0.10.12-6 +- Fixed processing agents not conforming to OCF schema +- Resolves: rhbz#2050274 + * Tue Feb 01 2022 Miroslav Lisik - 0.10.12-5 - Fixed snmp client - Resolves: rhbz#2047983