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