From 999fa2ad70728df100d2e8bc6df13fe937b0f66a Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 29 Mar 2022 16:24:37 -0400 Subject: [PATCH] import pcs-0.10.12-6.el8 --- .gitignore | 6 +- .pcs.metadata | 6 +- ...md-when-unable-to-get-agent-metadata.patch | 73 ++ ...f-pcs-resource-move-autodelete-comma.patch | 1031 +++++++++++++++++ ...ources-with-depth-operation-attribut.patch | 45 - .../bz2022463-01-fix-creating-empty-cib.patch | 94 ++ ...902-01-fix-enabling-corosync-qdevice.patch | 25 + ...ecking-of-scsi-devices-to-be-removed.patch | 86 ++ ...inbit-drbd-agent-pass-OCF-validation.patch | 41 + ...end-parameter-all-in-cluster-destroy.patch | 23 + SOURCES/bz2047983-01-Fix-snmp-client.patch | 25 + ...id-OCF-agents-the-same-way-as-before.patch | 934 +++++++++++++++ .../bz2050274-02-relax-OCF-1.0-parser.patch | 587 ++++++++++ ...t-cluster-setup-with-udp-u-transport.patch | 14 +- SOURCES/simplify-ternar-expression.patch | 26 + SPECS/pcs.spec | 118 +- 16 files changed, 3048 insertions(+), 86 deletions(-) create mode 100644 SOURCES/bz1384485-01-fix-rsc-update-cmd-when-unable-to-get-agent-metadata.patch create mode 100644 SOURCES/bz1990784-01-Multiple-fixes-of-pcs-resource-move-autodelete-comma.patch delete mode 100644 SOURCES/bz1998454-01-fix-creating-resources-with-depth-operation-attribut.patch create mode 100644 SOURCES/bz2022463-01-fix-creating-empty-cib.patch create mode 100644 SOURCES/bz2028902-01-fix-enabling-corosync-qdevice.patch create mode 100644 SOURCES/bz2032997-01-skip-checking-of-scsi-devices-to-be-removed.patch create mode 100644 SOURCES/bz2036633-01-Make-ocf-linbit-drbd-agent-pass-OCF-validation.patch create mode 100644 SOURCES/bz2044409-01-fix-backend-parameter-all-in-cluster-destroy.patch create mode 100644 SOURCES/bz2047983-01-Fix-snmp-client.patch create mode 100644 SOURCES/bz2050274-01-process-invalid-OCF-agents-the-same-way-as-before.patch create mode 100644 SOURCES/bz2050274-02-relax-OCF-1.0-parser.patch create mode 100644 SOURCES/simplify-ternar-expression.patch diff --git a/.gitignore b/.gitignore index d3a23d4..4d90c03 100644 --- a/.gitignore +++ b/.gitignore @@ -9,9 +9,9 @@ SOURCES/ffi-1.13.1.gem SOURCES/json-2.3.0.gem SOURCES/mustermann-1.1.1.gem SOURCES/open4-1.3.4-1.gem -SOURCES/pcs-0.10.10.tar.gz -SOURCES/pcs-web-ui-0.1.7.tar.gz -SOURCES/pcs-web-ui-node-modules-0.1.7.tar.xz +SOURCES/pcs-0.10.12.tar.gz +SOURCES/pcs-web-ui-0.1.12.tar.gz +SOURCES/pcs-web-ui-node-modules-0.1.12.tar.xz SOURCES/pyagentx-0.4.pcs.2.tar.gz SOURCES/python-dateutil-2.8.1.tar.gz SOURCES/rack-2.2.3.gem diff --git a/.pcs.metadata b/.pcs.metadata index 6167c6c..b16fa68 100644 --- a/.pcs.metadata +++ b/.pcs.metadata @@ -9,9 +9,9 @@ cfa25e7a3760c3ec16723cb8263d9b7a52d0eadf SOURCES/ffi-1.13.1.gem 0230e8c5a37f1543982e5b04be503dd5f9004b47 SOURCES/json-2.3.0.gem 50a4e37904485810cb05e27d75c9783e5a8f3402 SOURCES/mustermann-1.1.1.gem 41a7fe9f8e3e02da5ae76c821b89c5b376a97746 SOURCES/open4-1.3.4-1.gem -a1c0585455b7e050c33598598a045ccd2776cb28 SOURCES/pcs-0.10.10.tar.gz -b9ed12ca957c2f204ec37ea2836b924c36fab379 SOURCES/pcs-web-ui-0.1.7.tar.gz -8824285e6f1c2807d9222d573c6e6df1e50d8410 SOURCES/pcs-web-ui-node-modules-0.1.7.tar.xz +1937b826a36bb8396da227361d13f4c25830929c SOURCES/pcs-0.10.12.tar.gz +a29bfd22130ac978c5d4a6a82108ce37ad2a5db9 SOURCES/pcs-web-ui-0.1.12.tar.gz +c9723466d7bfb353899307a5700177f47e7e6cff SOURCES/pcs-web-ui-node-modules-0.1.12.tar.xz 3176b2f2b332c2b6bf79fe882e83feecf3d3f011 SOURCES/pyagentx-0.4.pcs.2.tar.gz bd26127e57f83a10f656b62c46524c15aeb844dd SOURCES/python-dateutil-2.8.1.tar.gz 345b7169d4d2d62176a225510399963bad62b68f SOURCES/rack-2.2.3.gem diff --git a/SOURCES/bz1384485-01-fix-rsc-update-cmd-when-unable-to-get-agent-metadata.patch b/SOURCES/bz1384485-01-fix-rsc-update-cmd-when-unable-to-get-agent-metadata.patch new file mode 100644 index 0000000..2960f32 --- /dev/null +++ b/SOURCES/bz1384485-01-fix-rsc-update-cmd-when-unable-to-get-agent-metadata.patch @@ -0,0 +1,73 @@ +From e5fc48f45a60228a82980dcd6d68ca01cf447eac Mon Sep 17 00:00:00 2001 +From: Ondrej Mular +Date: Tue, 7 Dec 2021 11:58:09 +0100 +Subject: [PATCH 2/3] fix rsc update cmd when unable to get agent metadata + +`resource update` command failed with a traceback when updating a +resource with a non-existing resource agent +--- + pcs/resource.py | 14 ++++++++------ + pcs_test/tier1/legacy/test_resource.py | 21 +++++++++++++++++++++ + 2 files changed, 29 insertions(+), 6 deletions(-) + +diff --git a/pcs/resource.py b/pcs/resource.py +index c0e8b0d9..4514338d 100644 +--- a/pcs/resource.py ++++ b/pcs/resource.py +@@ -1049,13 +1049,15 @@ def resource_update(lib, args, modifiers, deal_with_guest_change=True): + if report_list: + process_library_reports(report_list) + except lib_ra.ResourceAgentError as e: +- severity = ( +- reports.ReportItemSeverity.WARNING +- if modifiers.get("--force") +- else reports.ReportItemSeverity.ERROR +- ) + process_library_reports( +- [lib_ra.resource_agent_error_to_report_item(e, severity)] ++ [ ++ lib_ra.resource_agent_error_to_report_item( ++ e, ++ reports.get_severity( ++ reports.codes.FORCE, modifiers.get("--force") ++ ), ++ ) ++ ] + ) + except LibraryError as e: + process_library_reports(e.args) +diff --git a/pcs_test/tier1/legacy/test_resource.py b/pcs_test/tier1/legacy/test_resource.py +index 3f0e08b9..bae0587a 100644 +--- a/pcs_test/tier1/legacy/test_resource.py ++++ b/pcs_test/tier1/legacy/test_resource.py +@@ -4879,6 +4879,27 @@ class UpdateInstanceAttrs( + ), + ) + ++ def test_nonexisting_agent(self): ++ agent = "ocf:pacemaker:nonexistent" ++ message = ( ++ f"Agent '{agent}' is not installed or does " ++ "not provide valid metadata: Metadata query for " ++ f"{agent} failed: Input/output error" ++ ) ++ self.assert_pcs_success( ++ f"resource create --force D0 {agent}".split(), ++ f"Warning: {message}\n", ++ ) ++ ++ self.assert_pcs_fail( ++ "resource update D0 test=testA".split(), ++ f"Error: {message}, use --force to override\n", ++ ) ++ self.assert_pcs_success( ++ "resource update --force D0 test=testA".split(), ++ f"Warning: {message}\n", ++ ) ++ + def test_update_existing(self): + xml = """ + +-- +2.31.1 + diff --git a/SOURCES/bz1990784-01-Multiple-fixes-of-pcs-resource-move-autodelete-comma.patch b/SOURCES/bz1990784-01-Multiple-fixes-of-pcs-resource-move-autodelete-comma.patch new file mode 100644 index 0000000..ae32aae --- /dev/null +++ b/SOURCES/bz1990784-01-Multiple-fixes-of-pcs-resource-move-autodelete-comma.patch @@ -0,0 +1,1031 @@ +From fe1ad27f32e69e3e7c046b51e5406a0693ea1c35 Mon Sep 17 00:00:00 2001 +From: Ondrej Mular +Date: Tue, 11 Jan 2022 08:01:10 +0100 +Subject: [PATCH 3/5] Multiple fixes of `pcs resource move --autodelete` + command + +--- + pcs/common/reports/codes.py | 1 + + pcs/common/reports/messages.py | 21 ++ + pcs/lib/cib/node.py | 14 +- + pcs/lib/commands/resource.py | 105 ++++++- + pcs/lib/node.py | 7 +- + .../tier0/common/reports/test_messages.py | 12 + + .../resource/test_resource_move_autoclean.py | 280 +++++++++++++++++- + .../resource/test_resource_move_ban.py | 45 ++- + .../tools/command_env/config_runner_pcmk.py | 2 + + pcs_test/tools/command_env/mock_runner.py | 2 +- + pcs_test/tools/fixture_cib.py | 1 + + 11 files changed, 456 insertions(+), 34 deletions(-) + +diff --git a/pcs/common/reports/codes.py b/pcs/common/reports/codes.py +index 5bae7170..3e0512d9 100644 +--- a/pcs/common/reports/codes.py ++++ b/pcs/common/reports/codes.py +@@ -418,6 +418,7 @@ RESOURCE_UNMOVE_UNBAN_PCMK_EXPIRED_NOT_SUPPORTED = M( + ) + RESOURCE_MOVE_CONSTRAINT_CREATED = M("RESOURCE_MOVE_CONSTRAINT_CREATED") + RESOURCE_MOVE_CONSTRAINT_REMOVED = M("RESOURCE_MOVE_CONSTRAINT_REMOVED") ++RESOURCE_MOVE_NOT_AFFECTING_RESOURCE = M("RESOURCE_MOVE_NOT_AFFECTING_RESOURCE") + RESOURCE_MOVE_AFFECTS_OTRHER_RESOURCES = M( + "RESOURCE_MOVE_AFFECTS_OTRHER_RESOURCES" + ) +diff --git a/pcs/common/reports/messages.py b/pcs/common/reports/messages.py +index 43ce38e1..9d665e73 100644 +--- a/pcs/common/reports/messages.py ++++ b/pcs/common/reports/messages.py +@@ -6110,6 +6110,27 @@ class ResourceMoveConstraintRemoved(ReportItemMessage): + ) + + ++@dataclass(frozen=True) ++class ResourceMoveNotAffectingResource(ReportItemMessage): ++ """ ++ Creating a location constraint to move a resource has no effect on the ++ resource. ++ ++ resource_id -- id of the resource to be moved ++ """ ++ ++ resource_id: str ++ _code = codes.RESOURCE_MOVE_NOT_AFFECTING_RESOURCE ++ ++ @property ++ def message(self) -> str: ++ return ( ++ f"Unable to move resource '{self.resource_id}' using a location " ++ "constraint. Current location of the resource may be affected by " ++ "some other constraint." ++ ) ++ ++ + @dataclass(frozen=True) + class ResourceMoveAffectsOtherResources(ReportItemMessage): + """ +diff --git a/pcs/lib/cib/node.py b/pcs/lib/cib/node.py +index 20a41ca0..df2ffbaa 100644 +--- a/pcs/lib/cib/node.py ++++ b/pcs/lib/cib/node.py +@@ -1,12 +1,17 @@ + from collections import namedtuple ++from typing import Set + from lxml import etree ++from lxml.etree import _Element + + from pcs.common import reports + from pcs.common.reports.item import ReportItem + from pcs.lib.cib.nvpair import update_nvset + from pcs.lib.cib.tools import get_nodes + from pcs.lib.errors import LibraryError +-from pcs.lib.xml_tools import append_when_useful ++from pcs.lib.xml_tools import ( ++ append_when_useful, ++ get_root, ++) + + + class PacemakerNode(namedtuple("PacemakerNode", "name addr")): +@@ -58,6 +63,13 @@ def update_node_instance_attrs( + append_when_useful(cib_nodes, node_el) + + ++def get_node_names(cib: _Element) -> Set[str]: ++ return { ++ str(node.attrib["uname"]) ++ for node in get_nodes(get_root(cib)).iterfind("./node") ++ } ++ ++ + def _ensure_node_exists(tree, node_name, state_nodes=None): + """ + Make sure node with specified name exists +diff --git a/pcs/lib/commands/resource.py b/pcs/lib/commands/resource.py +index d0e8f4db..82ce73e0 100644 +--- a/pcs/lib/commands/resource.py ++++ b/pcs/lib/commands/resource.py +@@ -50,12 +50,16 @@ from pcs.lib.cib.tools import ( + from pcs.lib.env import LibraryEnvironment, WaitType + from pcs.lib.errors import LibraryError + from pcs.lib.external import CommandRunner +-from pcs.lib.node import get_existing_nodes_names_addrs ++from pcs.lib.node import ( ++ get_existing_nodes_names_addrs, ++ get_pacemaker_node_names, ++) + from pcs.lib.pacemaker import simulate as simulate_tools + from pcs.lib.pacemaker.live import ( + diff_cibs_xml, + get_cib, + get_cib_xml, ++ get_cluster_status_dom, + has_resource_unmove_unban_expired_support, + push_cib_diff_xml, + resource_ban, +@@ -1589,6 +1593,16 @@ def move( + ) + + ++def _nodes_exist_reports( ++ cib: _Element, node_names: Iterable[str] ++) -> ReportItemList: ++ existing_node_names = get_pacemaker_node_names(cib) ++ return [ ++ reports.ReportItem.error(reports.messages.NodeNotFound(node_name)) ++ for node_name in (set(node_names) - existing_node_names) ++ ] ++ ++ + def move_autoclean( + env: LibraryEnvironment, + resource_id: str, +@@ -1626,6 +1640,9 @@ def move_autoclean( + if resource_el is not None: + report_list.extend(resource.common.validate_move(resource_el, master)) + ++ if node: ++ report_list.extend(_nodes_exist_reports(cib, [node])) ++ + if env.report_processor.report_list(report_list).has_errors: + raise LibraryError() + +@@ -1659,8 +1676,32 @@ def move_autoclean( + add_constraint_cib_diff = diff_cibs_xml( + env.cmd_runner(), env.report_processor, cib_xml, rsc_moved_cib_xml + ) ++ with get_tmp_cib( ++ env.report_processor, rsc_moved_cib_xml ++ ) as rsc_moved_constraint_cleared_cib_file: ++ stdout, stderr, retval = resource_unmove_unban( ++ env.cmd_runner( ++ dict(CIB_file=rsc_moved_constraint_cleared_cib_file.name) ++ ), ++ resource_id, ++ node, ++ master, ++ ) ++ if retval != 0: ++ raise LibraryError( ++ ReportItem.error( ++ reports.messages.ResourceUnmoveUnbanPcmkError( ++ resource_id, stdout, stderr ++ ) ++ ) ++ ) ++ rsc_moved_constraint_cleared_cib_file.seek(0) ++ constraint_removed_cib = rsc_moved_constraint_cleared_cib_file.read() + remove_constraint_cib_diff = diff_cibs_xml( +- env.cmd_runner(), env.report_processor, rsc_moved_cib_xml, cib_xml ++ env.cmd_runner(), ++ env.report_processor, ++ rsc_moved_cib_xml, ++ constraint_removed_cib, + ) + + if not (add_constraint_cib_diff and remove_constraint_cib_diff): +@@ -1689,13 +1730,15 @@ def move_autoclean( + ) + ) + ) +- _ensure_resource_is_not_moved( ++ _ensure_resource_moved_and_not_moved_back( + env.cmd_runner, + env.report_processor, + etree_to_str(after_move_simulated_cib), + remove_constraint_cib_diff, + resource_id, + strict, ++ resource_state_before, ++ node, + ) + push_cib_diff_xml(env.cmd_runner(), add_constraint_cib_diff) + env.report_processor.report( +@@ -1704,13 +1747,15 @@ def move_autoclean( + ) + ) + env.wait_for_idle(wait_timeout) +- _ensure_resource_is_not_moved( ++ _ensure_resource_moved_and_not_moved_back( + env.cmd_runner, + env.report_processor, + get_cib_xml(env.cmd_runner()), + remove_constraint_cib_diff, + resource_id, + strict, ++ resource_state_before, ++ node, + ) + push_cib_diff_xml(env.cmd_runner(), remove_constraint_cib_diff) + env.report_processor.report( +@@ -1730,16 +1775,35 @@ def move_autoclean( + raise LibraryError() + + +-def _ensure_resource_is_not_moved( ++def _ensure_resource_moved_and_not_moved_back( + runner_factory: Callable[[Optional[Mapping[str, str]]], CommandRunner], + report_processor: reports.ReportProcessor, + cib_xml: str, + remove_constraint_cib_diff: str, + resource_id: str, + strict: bool, ++ resource_state_before: Dict[str, List[str]], ++ node: Optional[str], + ) -> None: + # pylint: disable=too-many-locals + with get_tmp_cib(report_processor, cib_xml) as rsc_unmove_cib_file: ++ if not _was_resource_moved( ++ node, ++ resource_state_before, ++ get_resource_state( ++ get_cluster_status_dom( ++ runner_factory(dict(CIB_file=rsc_unmove_cib_file.name)) ++ ), ++ resource_id, ++ ), ++ ): ++ raise LibraryError( ++ reports.ReportItem.error( ++ reports.messages.ResourceMoveNotAffectingResource( ++ resource_id ++ ) ++ ) ++ ) + push_cib_diff_xml( + runner_factory(dict(CIB_file=rsc_unmove_cib_file.name)), + remove_constraint_cib_diff, +@@ -1809,20 +1873,31 @@ def _resource_running_on_nodes( + return frozenset() + + ++def _was_resource_moved( ++ node: Optional[str], ++ resource_state_before: Dict[str, List[str]], ++ resource_state_after: Dict[str, List[str]], ++) -> bool: ++ running_on_nodes = _resource_running_on_nodes(resource_state_after) ++ return not bool( ++ resource_state_before ++ and ( # running resource moved ++ not running_on_nodes ++ or (node and node not in running_on_nodes) ++ or (resource_state_before == resource_state_after) ++ ) ++ ) ++ ++ + def _move_wait_report( + resource_id: str, + node: Optional[str], + resource_state_before: Dict[str, List[str]], + resource_state_after: Dict[str, List[str]], + ) -> ReportItem: +- allowed_nodes = frozenset([node] if node else []) +- running_on_nodes = _resource_running_on_nodes(resource_state_after) +- + severity = reports.item.ReportItemSeverity.info() +- if resource_state_before and ( # running resource moved +- not running_on_nodes +- or (allowed_nodes and allowed_nodes.isdisjoint(running_on_nodes)) +- or (resource_state_before == resource_state_after) ++ if not _was_resource_moved( ++ node, resource_state_before, resource_state_after + ): + severity = reports.item.ReportItemSeverity.error() + if not resource_state_after: +@@ -1873,14 +1948,18 @@ class _MoveBanTemplate: + lifetime=None, + wait: WaitType = False, + ): ++ # pylint: disable=too-many-locals + # validate + wait_timeout = env.ensure_wait_satisfiable(wait) # raises on error + ++ cib = env.get_cib() + resource_el, report_list = resource.common.find_one_resource( +- get_resources(env.get_cib()), resource_id ++ get_resources(cib), resource_id + ) + if resource_el is not None: + report_list.extend(self._validate(resource_el, master)) ++ if node: ++ report_list.extend(_nodes_exist_reports(cib, [node])) + if env.report_processor.report_list(report_list).has_errors: + raise LibraryError() + +diff --git a/pcs/lib/node.py b/pcs/lib/node.py +index ff08f747..3a7f236e 100644 +--- a/pcs/lib/node.py ++++ b/pcs/lib/node.py +@@ -3,6 +3,7 @@ from typing import ( + List, + Optional, + Tuple, ++ Set, + ) + + from lxml.etree import _Element +@@ -11,7 +12,7 @@ from pcs.common import reports + from pcs.common.reports import ReportItemList + from pcs.common.reports import ReportItemSeverity + from pcs.common.reports.item import ReportItem +-from pcs.lib.cib.node import PacemakerNode ++from pcs.lib.cib.node import PacemakerNode, get_node_names + from pcs.lib.cib.resource import remote_node, guest_node + from pcs.lib.corosync.config_facade import ConfigFacade as CorosyncConfigFacade + from pcs.lib.corosync.node import CorosyncNode +@@ -28,6 +29,10 @@ def get_existing_nodes_names( + ) + + ++def get_pacemaker_node_names(cib: _Element) -> Set[str]: ++ return get_node_names(cib) | set(get_existing_nodes_names(None, cib)[0]) ++ ++ + def get_existing_nodes_names_addrs( + corosync_conf=None, cib=None, error_on_missing_name=False + ): +diff --git a/pcs_test/tier0/common/reports/test_messages.py b/pcs_test/tier0/common/reports/test_messages.py +index c85aaa9c..4a7b4945 100644 +--- a/pcs_test/tier0/common/reports/test_messages.py ++++ b/pcs_test/tier0/common/reports/test_messages.py +@@ -4515,6 +4515,18 @@ class ResourceMoveConstraintRemoved(NameBuildTest): + ) + + ++class ResourceMoveNotAffectingResource(NameBuildTest): ++ def test_success(self): ++ self.assert_message_from_report( ++ ( ++ "Unable to move resource 'R1' using a location constraint. " ++ "Current location of the resource may be affected by some " ++ "other constraint." ++ ), ++ reports.ResourceMoveNotAffectingResource("R1"), ++ ) ++ ++ + class ResourceMoveAffectsOtherResources(NameBuildTest): + def test_multiple(self): + self.assert_message_from_report( +diff --git a/pcs_test/tier0/lib/commands/resource/test_resource_move_autoclean.py b/pcs_test/tier0/lib/commands/resource/test_resource_move_autoclean.py +index 32d758de..1bd4ee82 100644 +--- a/pcs_test/tier0/lib/commands/resource/test_resource_move_autoclean.py ++++ b/pcs_test/tier0/lib/commands/resource/test_resource_move_autoclean.py +@@ -20,6 +20,25 @@ from pcs_test.tools.command_env import get_env_tools + from pcs_test.tools.misc import get_test_resource as rc + + ++def _node_fixture(name, node_id): ++ return f'' ++ ++ ++def _node_list_fixture(nodes): ++ return "\n".join( ++ _node_fixture(node_name, node_id) ++ for node_id, node_name in enumerate(nodes) ++ ) ++ ++ ++def _nodes_section_fixture(content): ++ return f""" ++ ++ {content} ++ ++ """ ++ ++ + def _rsc_primitive_fixture(res_id): + return f'' + +@@ -145,11 +164,17 @@ class MoveAutocleanSuccess(MoveAutocleanCommonSetup): + resources=_resources_tag( + _resource_primitive + _resource_promotable_clone + ), ++ nodes=_nodes_section_fixture( ++ _node_list_fixture([self.orig_node, self.new_node]) ++ ), + ) + self.orig_cib = etree_to_str( + xml_fromstring(self.config.calls.get(config_load_cib_name).stdout) + ) + self.cib_with_constraint = '' ++ self.cib_without_constraint = ( ++ '' ++ ) + self.cib_simulate_constraint = ( + '' + ) +@@ -160,6 +185,9 @@ class MoveAutocleanSuccess(MoveAutocleanCommonSetup): + self.cib_diff_add_constraint_updated_tmp_file_name = ( + "cib_diff_add_constraint_updated" + ) ++ self.cib_constraint_removed_by_unmove_file_name = ( ++ "cib_constraint_removed_by_unmove" ++ ) + self.cib_diff_remove_constraint_orig_tmp_file_name = ( + "cib_diff_remove_constraint_orig" + ) +@@ -220,13 +248,18 @@ class MoveAutocleanSuccess(MoveAutocleanCommonSetup): + self.cib_diff_add_constraint_updated_tmp_file_name, + orig_content=self.cib_with_constraint, + ), ++ TmpFileCall( ++ self.cib_constraint_removed_by_unmove_file_name, ++ orig_content=self.cib_with_constraint, ++ new_content=self.cib_without_constraint, ++ ), + TmpFileCall( + self.cib_diff_remove_constraint_orig_tmp_file_name, + orig_content=self.cib_with_constraint, + ), + TmpFileCall( + self.cib_diff_remove_constraint_updated_tmp_file_name, +- orig_content=self.orig_cib, ++ orig_content=self.cib_without_constraint, + ), + TmpFileCall( + self.simulated_cib_add_constraint_tmp_file_name, +@@ -296,6 +329,12 @@ class MoveAutocleanSuccess(MoveAutocleanCommonSetup): + stdout=self.cib_diff_add_constraint, + name="runner.cib.diff.add_constraint", + ) ++ self.config.runner.pcmk.resource_clear( ++ resource=resource_id, ++ master=is_promotable, ++ node=self.new_node if with_node else None, ++ env=dict(CIB_file=self.cib_constraint_removed_by_unmove_file_name), ++ ) + self.config.runner.cib.diff( + self.cib_diff_remove_constraint_orig_tmp_file_name, + self.cib_diff_remove_constraint_updated_tmp_file_name, +@@ -308,6 +347,13 @@ class MoveAutocleanSuccess(MoveAutocleanCommonSetup): + cib_xml=self.cib_with_constraint, + name="pcmk.simulate.rsc.move", + ) ++ self.config.runner.pcmk.load_state( ++ resources=status_after, ++ name="runner.pcmk.load_state.mid_simulation", ++ env=dict( ++ CIB_file=self.cib_apply_diff_remove_constraint_from_simulated_cib_tmp_file_name ++ ), ++ ) + self.config.runner.cib.push_diff( + cib_diff=self.cib_diff_remove_constraint, + name="pcmk.push_cib_diff.simulation.remove_constraint", +@@ -335,6 +381,13 @@ class MoveAutocleanSuccess(MoveAutocleanCommonSetup): + self.cib_with_constraint, + name="load_cib_after_move", + ) ++ self.config.runner.pcmk.load_state( ++ resources=status_after, ++ name="runner.pcmk.load_state.after_push", ++ env=dict( ++ CIB_file=self.cib_apply_diff_remove_constraint_after_push_tmp_file_name ++ ), ++ ) + self.config.runner.cib.push_diff( + cib_diff=self.cib_diff_remove_constraint, + name="pcmk.push_cib_diff.simulation.remove_constraint_after_move", +@@ -380,6 +433,11 @@ class MoveAutocleanSuccess(MoveAutocleanCommonSetup): + file_path=self.cib_diff_add_constraint_updated_tmp_file_name, + content=self.cib_with_constraint, + ), ++ fixture.debug( ++ reports.codes.TMP_FILE_WRITE, ++ file_path=self.cib_constraint_removed_by_unmove_file_name, ++ content=self.cib_with_constraint, ++ ), + fixture.debug( + reports.codes.TMP_FILE_WRITE, + file_path=self.cib_diff_remove_constraint_orig_tmp_file_name, +@@ -388,7 +446,7 @@ class MoveAutocleanSuccess(MoveAutocleanCommonSetup): + fixture.debug( + reports.codes.TMP_FILE_WRITE, + file_path=self.cib_diff_remove_constraint_updated_tmp_file_name, +- content=self.orig_cib, ++ content=self.cib_without_constraint, + ), + fixture.debug( + reports.codes.TMP_FILE_WRITE, +@@ -758,9 +816,7 @@ class MoveAutocleanValidations(MoveAutocleanCommonSetup): + resources=_state_resource_fixture(resource_id, "Stopped"), + ) + self.env_assist.assert_raise_library_error( +- lambda: move_autoclean( +- self.env_assist.get_env(), resource_id, node="node" +- ), ++ lambda: move_autoclean(self.env_assist.get_env(), resource_id), + [ + fixture.error( + reports.codes.CANNOT_MOVE_RESOURCE_NOT_RUNNING, +@@ -770,11 +826,33 @@ class MoveAutocleanValidations(MoveAutocleanCommonSetup): + expected_in_processor=False, + ) + ++ def test_node_not_found(self): ++ resource_id = "A" ++ node = "non_existing_node" ++ self.config.runner.cib.load( ++ resources=_resources_tag(_rsc_primitive_fixture(resource_id)), ++ ) ++ self.env_assist.assert_raise_library_error( ++ lambda: move_autoclean( ++ self.env_assist.get_env(), resource_id, node ++ ), ++ ) ++ self.env_assist.assert_reports( ++ [ ++ fixture.error( ++ reports.codes.NODE_NOT_FOUND, ++ node=node, ++ searched_types=[], ++ ) ++ ], ++ ) ++ + def test_constraint_already_exist(self): + resource_id = "A" + config_load_cib_name = "load_cib" + node = "node1" + cib_with_constraint = '' ++ cib_without_constraint = '' + cib_rsc_move_tmp_file_name = "cib_rsc_move_tmp_file" + cib_diff_add_constraint_orig_tmp_file_name = ( + "cib_diff_add_constraint_orig" +@@ -788,6 +866,9 @@ class MoveAutocleanValidations(MoveAutocleanCommonSetup): + cib_diff_remove_constraint_updated_tmp_file_name = ( + "cib_diff_remove_constraint_updated" + ) ++ cib_constraint_removed_by_unmove_file_name = ( ++ "cib_constraint_removed_by_unmove" ++ ) + self.config.runner.cib.load( + resources=_resources_tag(_rsc_primitive_fixture(resource_id)), + constraints=f""" +@@ -795,6 +876,7 @@ class MoveAutocleanValidations(MoveAutocleanCommonSetup): + + + """, ++ nodes=_nodes_section_fixture(_node_list_fixture([node])), + name=config_load_cib_name, + ) + orig_cib = etree_to_str( +@@ -815,13 +897,18 @@ class MoveAutocleanValidations(MoveAutocleanCommonSetup): + cib_diff_add_constraint_updated_tmp_file_name, + orig_content=cib_with_constraint, + ), ++ TmpFileCall( ++ cib_constraint_removed_by_unmove_file_name, ++ orig_content=cib_with_constraint, ++ new_content=cib_without_constraint, ++ ), + TmpFileCall( + cib_diff_remove_constraint_orig_tmp_file_name, + orig_content=cib_with_constraint, + ), + TmpFileCall( + cib_diff_remove_constraint_updated_tmp_file_name, +- orig_content=orig_cib, ++ orig_content=cib_without_constraint, + ), + ] + ) +@@ -839,6 +926,11 @@ class MoveAutocleanValidations(MoveAutocleanCommonSetup): + stdout="", + name="runner.cib.diff.add_constraint", + ) ++ self.config.runner.pcmk.resource_clear( ++ resource=resource_id, ++ node=node, ++ env=dict(CIB_file=cib_constraint_removed_by_unmove_file_name), ++ ) + self.config.runner.cib.diff( + cib_diff_remove_constraint_orig_tmp_file_name, + cib_diff_remove_constraint_updated_tmp_file_name, +@@ -863,6 +955,11 @@ class MoveAutocleanValidations(MoveAutocleanCommonSetup): + file_path=cib_diff_add_constraint_updated_tmp_file_name, + content=cib_with_constraint, + ), ++ fixture.debug( ++ reports.codes.TMP_FILE_WRITE, ++ file_path=cib_constraint_removed_by_unmove_file_name, ++ content=cib_with_constraint, ++ ), + fixture.debug( + reports.codes.TMP_FILE_WRITE, + file_path=cib_diff_remove_constraint_orig_tmp_file_name, +@@ -871,7 +968,7 @@ class MoveAutocleanValidations(MoveAutocleanCommonSetup): + fixture.debug( + reports.codes.TMP_FILE_WRITE, + file_path=cib_diff_remove_constraint_updated_tmp_file_name, +- content=orig_cib, ++ content=cib_without_constraint, + ), + fixture.info( + reports.codes.NO_ACTION_NECESSARY, +@@ -896,6 +993,9 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + self.cib_diff_add_constraint = "diff_add_constraint" + self.cib_diff_remove_constraint = "diff_remove_constraint" + self.cib_with_constraint = '' ++ self.cib_without_constraint = ( ++ '' ++ ) + self.cib_rsc_move_tmp_file_name = "cib_rsc_move_tmp_file" + self.cib_diff_add_constraint_orig_tmp_file_name = ( + "cib_diff_add_constraint_orig" +@@ -903,6 +1003,9 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + self.cib_diff_add_constraint_updated_tmp_file_name = ( + "cib_diff_add_constraint_updated" + ) ++ self.cib_constraint_removed_by_unmove_file_name = ( ++ "cib_constraint_removed_by_unmove" ++ ) + self.cib_diff_remove_constraint_orig_tmp_file_name = ( + "cib_diff_remove_constraint_orig" + ) +@@ -951,6 +1054,9 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + + self.config.runner.cib.load( + resources=_resources_tag(_rsc_primitive_fixture(self.resource_id)), ++ nodes=_nodes_section_fixture( ++ _node_list_fixture(["node1", "node2"]) ++ ), + name=self.config_load_cib_name, + ) + self.orig_cib = etree_to_str( +@@ -979,13 +1085,18 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + self.cib_diff_add_constraint_updated_tmp_file_name, + orig_content=self.cib_with_constraint, + ), ++ TmpFileCall( ++ self.cib_constraint_removed_by_unmove_file_name, ++ orig_content=self.cib_with_constraint, ++ new_content=self.cib_without_constraint, ++ ), + TmpFileCall( + self.cib_diff_remove_constraint_orig_tmp_file_name, + orig_content=self.cib_with_constraint, + ), + TmpFileCall( + self.cib_diff_remove_constraint_updated_tmp_file_name, +- orig_content=self.orig_cib, ++ orig_content=self.cib_without_constraint, + ), + TmpFileCall( + self.simulated_cib_add_constraint_tmp_file_name, +@@ -1067,6 +1178,11 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + stdout=self.cib_diff_add_constraint, + name="runner.cib.diff.add_constraint", + ) ++ self.config.runner.pcmk.resource_clear( ++ resource=self.resource_id, ++ node=node, ++ env=dict(CIB_file=self.cib_constraint_removed_by_unmove_file_name), ++ ) + self.config.runner.cib.diff( + self.cib_diff_remove_constraint_orig_tmp_file_name, + self.cib_diff_remove_constraint_updated_tmp_file_name, +@@ -1081,6 +1197,15 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + ) + if stage <= 1: + return ++ self.config.runner.pcmk.load_state( ++ resources=_state_resource_fixture( ++ self.resource_id, "Started", node if node else "node2" ++ ), ++ name="runner.pcmk.load_state.mid_simulation", ++ env=dict( ++ CIB_file=self.cib_apply_diff_remove_constraint_from_simulated_cib_tmp_file_name ++ ), ++ ) + self.config.runner.cib.push_diff( + cib_diff=self.cib_diff_remove_constraint, + name="pcmk.push_cib_diff.simulation.remove_constraint", +@@ -1110,6 +1235,17 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + self.cib_with_constraint, + name="load_cib_after_move", + ) ++ if stage <= 3: ++ return ++ self.config.runner.pcmk.load_state( ++ resources=_state_resource_fixture( ++ self.resource_id, "Started", node if node else "node2" ++ ), ++ name="runner.pcmk.load_state.after_push", ++ env=dict( ++ CIB_file=self.cib_apply_diff_remove_constraint_after_push_tmp_file_name ++ ), ++ ) + self.config.runner.cib.push_diff( + cib_diff=self.cib_diff_remove_constraint, + name="pcmk.push_cib_diff.simulation.remove_constraint_after_move", +@@ -1126,7 +1262,7 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + ), + name="pcmk.simulate.rsc.unmove.after_push", + ) +- if stage <= 3: ++ if stage <= 4: + return + self.config.runner.cib.push_diff( + cib_diff=self.cib_diff_remove_constraint, +@@ -1153,6 +1289,11 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + file_path=self.cib_diff_add_constraint_updated_tmp_file_name, + content=self.cib_with_constraint, + ), ++ fixture.debug( ++ reports.codes.TMP_FILE_WRITE, ++ file_path=self.cib_constraint_removed_by_unmove_file_name, ++ content=self.cib_with_constraint, ++ ), + fixture.debug( + reports.codes.TMP_FILE_WRITE, + file_path=self.cib_diff_remove_constraint_orig_tmp_file_name, +@@ -1161,7 +1302,7 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + fixture.debug( + reports.codes.TMP_FILE_WRITE, + file_path=self.cib_diff_remove_constraint_updated_tmp_file_name, +- content=self.orig_cib, ++ content=self.cib_without_constraint, + ), + fixture.debug( + reports.codes.TMP_FILE_WRITE, +@@ -1199,7 +1340,7 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + reports.codes.WAIT_FOR_IDLE_STARTED, + timeout=0, + ), +- ][: {None: None, 3: -2, 2: 7, 1: 5}[stage]] ++ ][: {None: None, 4: -2, 3: 10, 2: 8, 1: 6}[stage]] + + def test_move_affects_other_resources_strict(self): + self.tmp_file_mock_obj.set_calls( +@@ -1304,7 +1445,8 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + ), + ) + ) +- self.set_up_testing_env(stage=3) ++ setup_stage = 4 ++ self.set_up_testing_env(stage=setup_stage) + self.env_assist.assert_raise_library_error( + lambda: move_autoclean(self.env_assist.get_env(), self.resource_id), + [ +@@ -1316,7 +1458,7 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + ], + expected_in_processor=False, + ) +- self.env_assist.assert_reports(self.get_reports(stage=3)) ++ self.env_assist.assert_reports(self.get_reports(stage=setup_stage)) + + def test_unmove_after_push_affects_other_resources_strict(self): + self.tmp_file_mock_obj.set_calls( +@@ -1330,7 +1472,8 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + ), + ) + ) +- self.set_up_testing_env(stage=3) ++ setup_stage = 4 ++ self.set_up_testing_env(stage=setup_stage) + self.env_assist.assert_raise_library_error( + lambda: move_autoclean( + self.env_assist.get_env(), +@@ -1346,7 +1489,7 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + ], + expected_in_processor=False, + ) +- self.env_assist.assert_reports(self.get_reports(stage=3)) ++ self.env_assist.assert_reports(self.get_reports(stage=setup_stage)) + + def test_resource_not_runnig_after_move(self): + self.tmp_file_mock_obj.set_calls( +@@ -1381,8 +1524,113 @@ class MoveAutocleanFailures(MoveAutocleanCommonSetup): + ] + ) + ++ def test_simulation_resource_not_moved(self): ++ node = "node2" ++ different_node = f"different-{node}" ++ setup_stage = 1 ++ self.tmp_file_mock_obj.set_calls( ++ self.get_tmp_files_mocks( ++ _simulation_transition_fixture( ++ _simulation_synapses_fixture(self.resource_id) ++ ), ++ ) ++ + [ ++ TmpFileCall( ++ self.cib_apply_diff_remove_constraint_from_simulated_cib_tmp_file_name, ++ orig_content=self.cib_simulate_constraint, ++ ), ++ ] ++ ) ++ self.set_up_testing_env(node=node, stage=setup_stage) ++ self.config.runner.pcmk.load_state( ++ resources=_state_resource_fixture( ++ self.resource_id, "Started", different_node ++ ), ++ name="runner.pcmk.load_state.final", ++ env=dict( ++ CIB_file=self.cib_apply_diff_remove_constraint_from_simulated_cib_tmp_file_name ++ ), ++ ) ++ self.env_assist.assert_raise_library_error( ++ lambda: move_autoclean( ++ self.env_assist.get_env(), ++ self.resource_id, ++ node=node, ++ ), ++ [ ++ fixture.error( ++ reports.codes.RESOURCE_MOVE_NOT_AFFECTING_RESOURCE, ++ resource_id=self.resource_id, ++ ) ++ ], ++ expected_in_processor=False, ++ ) ++ self.env_assist.assert_reports( ++ self.get_reports(stage=setup_stage) ++ + [ ++ fixture.debug( ++ reports.codes.TMP_FILE_WRITE, ++ file_path=self.cib_apply_diff_remove_constraint_from_simulated_cib_tmp_file_name, ++ content=self.cib_simulate_constraint, ++ ), ++ ] ++ ) ++ ++ def test_after_push_resource_not_moved(self): ++ node = "node2" ++ different_node = f"different-{node}" ++ setup_stage = 3 ++ self.tmp_file_mock_obj.set_calls( ++ self.get_tmp_files_mocks( ++ _simulation_transition_fixture( ++ _simulation_synapses_fixture(self.resource_id) ++ ), ++ _simulation_transition_fixture(), ++ ) ++ + [ ++ TmpFileCall( ++ self.cib_apply_diff_remove_constraint_after_push_tmp_file_name, ++ orig_content=self.cib_with_constraint, ++ ), ++ ] ++ ) ++ self.set_up_testing_env(node=node, stage=setup_stage) ++ self.config.runner.pcmk.load_state( ++ resources=_state_resource_fixture( ++ self.resource_id, "Started", different_node ++ ), ++ name="runner.pcmk.load_state.final", ++ env=dict( ++ CIB_file=self.cib_apply_diff_remove_constraint_after_push_tmp_file_name, ++ ), ++ ) ++ self.env_assist.assert_raise_library_error( ++ lambda: move_autoclean( ++ self.env_assist.get_env(), ++ self.resource_id, ++ node=node, ++ ), ++ [ ++ fixture.error( ++ reports.codes.RESOURCE_MOVE_NOT_AFFECTING_RESOURCE, ++ resource_id=self.resource_id, ++ ) ++ ], ++ expected_in_processor=False, ++ ) ++ self.env_assist.assert_reports( ++ self.get_reports(stage=setup_stage) ++ + [ ++ fixture.debug( ++ reports.codes.TMP_FILE_WRITE, ++ file_path=self.cib_apply_diff_remove_constraint_after_push_tmp_file_name, ++ content=self.cib_with_constraint, ++ ), ++ ] ++ ) ++ + def test_resource_running_on_a_different_node(self): +- node = "node1" ++ node = "node2" + different_node = f"different-{node}" + self.tmp_file_mock_obj.set_calls( + self.get_tmp_files_mocks( +diff --git a/pcs_test/tier0/lib/commands/resource/test_resource_move_ban.py b/pcs_test/tier0/lib/commands/resource/test_resource_move_ban.py +index 5d57fa06..28dd1cd1 100644 +--- a/pcs_test/tier0/lib/commands/resource/test_resource_move_ban.py ++++ b/pcs_test/tier0/lib/commands/resource/test_resource_move_ban.py +@@ -10,6 +10,29 @@ from pcs.common.reports import ReportItemSeverity as severities + from pcs.common.reports import codes as report_codes + from pcs.lib.commands import resource + ++ ++def _node_fixture(name, node_id): ++ return f'' ++ ++ ++def _node_list_fixture(nodes): ++ return "\n".join( ++ _node_fixture(node_name, node_id) ++ for node_id, node_name in enumerate(nodes) ++ ) ++ ++ ++def _nodes_section_fixture(content): ++ return f""" ++ ++ {content} ++ ++ """ ++ ++ ++nodes_section = _nodes_section_fixture( ++ _node_list_fixture(["node", "node1", "node2"]) ++) + resources_primitive = """ + + +@@ -128,8 +151,24 @@ class MoveBanBaseMixin(MoveBanClearBaseMixin): + expected_in_processor=False, + ) + ++ def test_node_not_found(self): ++ self.config.runner.cib.load(resources=resources_primitive) ++ node = "node" ++ self.env_assist.assert_raise_library_error( ++ lambda: self.lib_action(self.env_assist.get_env(), "A", node) ++ ) ++ self.env_assist.assert_reports( ++ [ ++ fixture.error( ++ report_codes.NODE_NOT_FOUND, node=node, searched_types=[] ++ ) ++ ] ++ ) ++ + def test_all_options(self): +- self.config.runner.cib.load(resources=resources_promotable) ++ self.config.runner.cib.load( ++ resources=resources_promotable, nodes=nodes_section ++ ) + self.config_pcmk_action( + resource="A-clone", + master=True, +@@ -274,7 +313,9 @@ class MoveBanWaitMixin: + def setUp(self): + self.timeout = 10 + self.env_assist, self.config = get_env_tools(self) +- self.config.runner.cib.load(resources=resources_primitive) ++ self.config.runner.cib.load( ++ resources=resources_primitive, nodes=nodes_section ++ ) + + @mock.patch.object( + settings, +diff --git a/pcs_test/tools/command_env/config_runner_pcmk.py b/pcs_test/tools/command_env/config_runner_pcmk.py +index e276e03b..213941b8 100644 +--- a/pcs_test/tools/command_env/config_runner_pcmk.py ++++ b/pcs_test/tools/command_env/config_runner_pcmk.py +@@ -706,6 +706,7 @@ class PcmkShortcuts: + stdout="", + stderr="", + returncode=0, ++ env=None, + ): + """ + Create a call for crm_resource --clear +@@ -722,6 +723,7 @@ class PcmkShortcuts: + string stdout -- crm_resource's stdout + string stderr -- crm_resource's stderr + int returncode -- crm_resource's returncode ++ dict env -- CommandRunner environment variables + """ + # arguments are used via locals() + # pylint: disable=unused-argument +diff --git a/pcs_test/tools/command_env/mock_runner.py b/pcs_test/tools/command_env/mock_runner.py +index f7871fc2..8520ce02 100644 +--- a/pcs_test/tools/command_env/mock_runner.py ++++ b/pcs_test/tools/command_env/mock_runner.py +@@ -143,6 +143,6 @@ class Runner: + env.update(env_extend) + if env != call.env: + raise self.__call_queue.error_with_context( +- f"ENV doesn't match. Expected: {call.env}; Real: {env}" ++ f"Command #{i}: ENV doesn't match. Expected: {call.env}; Real: {env}" + ) + return call.stdout, call.stderr, call.returncode +diff --git a/pcs_test/tools/fixture_cib.py b/pcs_test/tools/fixture_cib.py +index 602491c8..bf02bacc 100644 +--- a/pcs_test/tools/fixture_cib.py ++++ b/pcs_test/tools/fixture_cib.py +@@ -310,6 +310,7 @@ MODIFIER_GENERATORS = { + "replace": replace_all, + "append": append_all, + "resources": lambda xml: replace_all({"./configuration/resources": xml}), ++ "nodes": lambda xml: replace_all({"./configuration/nodes": xml}), + "constraints": lambda xml: replace_all( + {"./configuration/constraints": xml} + ), +-- +2.31.1 + diff --git a/SOURCES/bz1998454-01-fix-creating-resources-with-depth-operation-attribut.patch b/SOURCES/bz1998454-01-fix-creating-resources-with-depth-operation-attribut.patch deleted file mode 100644 index 4616131..0000000 --- a/SOURCES/bz1998454-01-fix-creating-resources-with-depth-operation-attribut.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 189c73e31f5033413fc4483e40d0bfc78d77f962 Mon Sep 17 00:00:00 2001 -From: Tomas Jelinek -Date: Fri, 27 Aug 2021 12:05:18 +0200 -Subject: [PATCH 1/2] fix creating resources with depth operation attribute - ---- - CHANGELOG.md | 9 +++++++++ - pcs/lib/cib/resource/operations.py | 2 +- - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/CHANGELOG.md b/CHANGELOG.md -index f768cc36..c15546ba 100644 ---- a/CHANGELOG.md -+++ b/CHANGELOG.md -@@ -1,5 +1,14 @@ - # Change Log - -+## [Unreleased] -+ -+### Fixed -+- Fixed an error when creating a resource which defines 'depth' attribute for -+ its operations ([rhbz#1998454]) -+ -+[rhbz#1998454]: https://bugzilla.redhat.com/show_bug.cgi?id=1998454 -+ -+ - ## [0.10.10] - 2021-08-19 - - ### Added -diff --git a/pcs/lib/cib/resource/operations.py b/pcs/lib/cib/resource/operations.py -index 390db71a..44b2e7dd 100644 ---- a/pcs/lib/cib/resource/operations.py -+++ b/pcs/lib/cib/resource/operations.py -@@ -197,7 +197,7 @@ def _action_dto_to_dict( - ) -> Dict[str, str]: - result = dict( - filter( -- lambda item: item[0] != "deph" and item[1] not in (None, ""), -+ lambda item: item[0] != "depth" and item[1] not in (None, ""), - to_dict(dto).items(), - ) - ) --- -2.31.1 - diff --git a/SOURCES/bz2022463-01-fix-creating-empty-cib.patch b/SOURCES/bz2022463-01-fix-creating-empty-cib.patch new file mode 100644 index 0000000..1437dd1 --- /dev/null +++ b/SOURCES/bz2022463-01-fix-creating-empty-cib.patch @@ -0,0 +1,94 @@ +From f0342f110bdb4a7421532b85ca0f49070c7e5c1e Mon Sep 17 00:00:00 2001 +From: Tomas Jelinek +Date: Thu, 13 Jan 2022 17:32:38 +0100 +Subject: [PATCH 4/5] fix creating empty cib + +--- + pcs/utils.py | 21 +++++++++++---------- + pcs_test/tier1/test_misc.py | 25 ++++++++++++++++++++++++- + 2 files changed, 35 insertions(+), 11 deletions(-) + +diff --git a/pcs/utils.py b/pcs/utils.py +index ad2d4452..423ffc43 100644 +--- a/pcs/utils.py ++++ b/pcs/utils.py +@@ -2067,16 +2067,17 @@ def write_empty_cib(cibfile): + """ + Commandline options: no options + """ +- empty_xml = """ +- +- +- +- +- +- +- +- +-""" ++ empty_xml = """ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ """ + with open(cibfile, "w") as f: + f.write(empty_xml) + +diff --git a/pcs_test/tier1/test_misc.py b/pcs_test/tier1/test_misc.py +index 29ca6a71..6e6f72fb 100644 +--- a/pcs_test/tier1/test_misc.py ++++ b/pcs_test/tier1/test_misc.py +@@ -1,8 +1,10 @@ ++import os + from unittest import TestCase + + from pcs_test.tools.assertions import AssertPcsMixin + from pcs_test.tools.misc import ( + get_test_resource as rc, ++ get_tmp_dir, + get_tmp_file, + outdent, + write_file_to_tmpfile, +@@ -19,7 +21,7 @@ class ParseArgvDashDash(TestCase, AssertPcsMixin): + cmd = "constraint colocation add R1 with R2".split() + + def setUp(self): +- self.temp_cib = get_tmp_file("tier1_misc") ++ self.temp_cib = get_tmp_file("tier1_misc_dashdash") + write_file_to_tmpfile(rc("cib-empty.xml"), self.temp_cib) + self.pcs_runner = PcsRunner(self.temp_cib.name) + self.allowed_roles = format_list(const.PCMK_ROLES) +@@ -89,3 +91,24 @@ class ParseArgvDashDash(TestCase, AssertPcsMixin): + """ + ), + ) ++ ++ ++class EmptyCibIsPcmk2Compatible(TestCase, AssertPcsMixin): ++ # This test verifies that a default empty CIB created by pcs when -f points ++ # to an empty file conforms to minimal schema version supported by ++ # pacemaker 2.0. If pcs prints a message that CIB schema has been upgraded, ++ # then the test fails and shows there is a bug. Bundle with promoted-max ++ # requires CIB compliant with schema 3.1, which was introduced in pacemaker ++ # 2.0.0. ++ def setUp(self): ++ self.cib_dir = get_tmp_dir("tier1_misc_empty_cib") ++ self.pcs_runner = PcsRunner(os.path.join(self.cib_dir.name, "cib.xml")) ++ ++ def tearDown(self): ++ self.cib_dir.cleanup() ++ ++ def test_success(self): ++ self.assert_pcs_success( ++ "resource bundle create b container docker image=my.img promoted-max=1".split(), ++ "", ++ ) +-- +2.31.1 + diff --git a/SOURCES/bz2028902-01-fix-enabling-corosync-qdevice.patch b/SOURCES/bz2028902-01-fix-enabling-corosync-qdevice.patch new file mode 100644 index 0000000..e45d0b9 --- /dev/null +++ b/SOURCES/bz2028902-01-fix-enabling-corosync-qdevice.patch @@ -0,0 +1,25 @@ +From 6b4b0c0026e5077044e4e908d093cb613ae2e94e Mon Sep 17 00:00:00 2001 +From: Tomas Jelinek +Date: Mon, 6 Dec 2021 16:06:31 +0100 +Subject: [PATCH 1/3] fix enabling corosync-qdevice + +--- + pcsd/remote.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pcsd/remote.rb b/pcsd/remote.rb +index c49db116..3574d665 100644 +--- a/pcsd/remote.rb ++++ b/pcsd/remote.rb +@@ -2515,7 +2515,7 @@ def qdevice_client_enable(param, request, auth_user) + unless allowed_for_local_cluster(auth_user, Permissions::WRITE) + return 403, 'Permission denied' + end +- if not ServiceChecker.new('corosync', enabled: true).is_enabled?('corosync') ++ if not ServiceChecker.new(['corosync'], enabled: true).is_enabled?('corosync') + return pcsd_success('corosync is not enabled, skipping') + elsif enable_service('corosync-qdevice') + return pcsd_success('corosync-qdevice enabled') +-- +2.31.1 + diff --git a/SOURCES/bz2032997-01-skip-checking-of-scsi-devices-to-be-removed.patch b/SOURCES/bz2032997-01-skip-checking-of-scsi-devices-to-be-removed.patch new file mode 100644 index 0000000..e11b09e --- /dev/null +++ b/SOURCES/bz2032997-01-skip-checking-of-scsi-devices-to-be-removed.patch @@ -0,0 +1,86 @@ +From 082bded126151e4f4b4667a1d8337db741828da6 Mon Sep 17 00:00:00 2001 +From: Miroslav Lisik +Date: Thu, 16 Dec 2021 14:12:58 +0100 +Subject: [PATCH 1/5] skip checking of scsi devices to be removed before + unfencing to be added devices + +--- + pcs/lib/commands/scsi.py | 3 ++- + pcs_test/tier0/lib/commands/test_scsi.py | 21 +++++++++++++++++---- + 2 files changed, 19 insertions(+), 5 deletions(-) + +diff --git a/pcs/lib/commands/scsi.py b/pcs/lib/commands/scsi.py +index ff20a563..ab732805 100644 +--- a/pcs/lib/commands/scsi.py ++++ b/pcs/lib/commands/scsi.py +@@ -31,7 +31,8 @@ def unfence_node( + return + fence_scsi_bin = os.path.join(settings.fence_agent_binaries, "fence_scsi") + fenced_devices = [] +- for device in original_devices: ++ # do not check devices being removed ++ for device in sorted(set(original_devices) & set(updated_devices)): + stdout, stderr, return_code = env.cmd_runner().run( + [ + fence_scsi_bin, +diff --git a/pcs_test/tier0/lib/commands/test_scsi.py b/pcs_test/tier0/lib/commands/test_scsi.py +index 8ef9836a..bc2357a9 100644 +--- a/pcs_test/tier0/lib/commands/test_scsi.py ++++ b/pcs_test/tier0/lib/commands/test_scsi.py +@@ -13,10 +13,13 @@ class TestUnfenceNode(TestCase): + self.old_devices = ["device1", "device3"] + self.new_devices = ["device3", "device0", "device2"] + self.added_devices = set(self.new_devices) - set(self.old_devices) ++ self.check_devices = sorted( ++ set(self.old_devices) & set(self.new_devices) ++ ) + self.node = "node1" + + def test_success_devices_to_unfence(self): +- for old_dev in self.old_devices: ++ for old_dev in self.check_devices: + self.config.runner.scsi.get_status( + self.node, old_dev, name=f"runner.scsi.is_fenced.{old_dev}" + ) +@@ -38,9 +41,19 @@ class TestUnfenceNode(TestCase): + ) + self.env_assist.assert_reports([]) + ++ def test_success_replace_unavailable_device(self): ++ self.config.runner.scsi.unfence_node(self.node, {"device2"}) ++ scsi.unfence_node( ++ self.env_assist.get_env(), ++ self.node, ++ {"device1"}, ++ {"device2"}, ++ ) ++ self.env_assist.assert_reports([]) ++ + def test_unfencing_failure(self): + err_msg = "stderr" +- for old_dev in self.old_devices: ++ for old_dev in self.check_devices: + self.config.runner.scsi.get_status( + self.node, old_dev, name=f"runner.scsi.is_fenced.{old_dev}" + ) +@@ -98,7 +111,7 @@ class TestUnfenceNode(TestCase): + + def test_unfencing_skipped_devices_are_fenced(self): + stdout_off = "Status: OFF" +- for old_dev in self.old_devices: ++ for old_dev in self.check_devices: + self.config.runner.scsi.get_status( + self.node, + old_dev, +@@ -116,7 +129,7 @@ class TestUnfenceNode(TestCase): + [ + fixture.info( + report_codes.STONITH_UNFENCING_SKIPPED_DEVICES_FENCED, +- devices=sorted(self.old_devices), ++ devices=sorted(self.check_devices), + ) + ] + ) +-- +2.31.1 + diff --git a/SOURCES/bz2036633-01-Make-ocf-linbit-drbd-agent-pass-OCF-validation.patch b/SOURCES/bz2036633-01-Make-ocf-linbit-drbd-agent-pass-OCF-validation.patch new file mode 100644 index 0000000..455dcda --- /dev/null +++ b/SOURCES/bz2036633-01-Make-ocf-linbit-drbd-agent-pass-OCF-validation.patch @@ -0,0 +1,41 @@ +From 46b079a93d1817f9c1d6a7403c70b30f59d19c20 Mon Sep 17 00:00:00 2001 +From: Tomas Jelinek +Date: Tue, 4 Jan 2022 12:56:56 +0100 +Subject: [PATCH 2/5] Make ocf:linbit:drbd agent pass OCF validation + +--- + data/ocf-1.0.rng | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/data/ocf-1.0.rng b/data/ocf-1.0.rng +index 36ba4611..1e14a83b 100644 +--- a/data/ocf-1.0.rng ++++ b/data/ocf-1.0.rng +@@ -169,16 +169,14 @@ RNGs. Thank you. + + + +- +- +- boolean +- string +- integer +- second +- int +- time +- +- ++ ++ + +