diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..111c603 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +SOURCES/backports-3.17.2.gem +SOURCES/dacite-1.6.0.tar.gz +SOURCES/daemons-1.3.1.gem +SOURCES/ethon-0.12.0.gem +SOURCES/eventmachine-1.2.7.gem +SOURCES/ffi-1.13.1.gem +SOURCES/mustermann-1.1.1.gem +SOURCES/open4-1.3.4-1.gem +SOURCES/pcs-0.11.1.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/rack-2.2.3.gem +SOURCES/rack-protection-2.0.8.1.gem +SOURCES/rack-test-1.1.0.gem +SOURCES/rexml-3.2.5.gem +SOURCES/ruby2_keywords-0.0.2.gem +SOURCES/sinatra-2.0.8.1.gem +SOURCES/thin-1.7.2.gem +SOURCES/tilt-2.0.10.gem +SOURCES/tornado-6.1.0.tar.gz +SOURCES/webrick-1.7.0.gem diff --git a/.pcs.metadata b/.pcs.metadata new file mode 100644 index 0000000..fc491e3 --- /dev/null +++ b/.pcs.metadata @@ -0,0 +1,22 @@ +28b63a742124da6c9575a1c5e7d7331ef93600b2 SOURCES/backports-3.17.2.gem +31546c37fbdc6270d5097687619e9c0db6f1c05c SOURCES/dacite-1.6.0.tar.gz +e28c1e78d1a6e34e80f4933b494f1e0501939dd3 SOURCES/daemons-1.3.1.gem +921ef1be44583a7644ee7f20fe5f26f21d018a04 SOURCES/ethon-0.12.0.gem +7a5b2896e210fac9759c786ee4510f265f75b481 SOURCES/eventmachine-1.2.7.gem +cfa25e7a3760c3ec16723cb8263d9b7a52d0eadf SOURCES/ffi-1.13.1.gem +50a4e37904485810cb05e27d75c9783e5a8f3402 SOURCES/mustermann-1.1.1.gem +41a7fe9f8e3e02da5ae76c821b89c5b376a97746 SOURCES/open4-1.3.4-1.gem +47d8d30bf502ff2a6a81c6cebc262fc272b48011 SOURCES/pcs-0.11.1.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 +345b7169d4d2d62176a225510399963bad62b68f SOURCES/rack-2.2.3.gem +1f046e23baca8beece3b38c60382f44aa2b2cb41 SOURCES/rack-protection-2.0.8.1.gem +b80bc5ca38a885e747271675ba91dd3d02136bf1 SOURCES/rack-test-1.1.0.gem +e7f48fa5fb2d92e6cb21d6b1638fe41a5a7c4287 SOURCES/rexml-3.2.5.gem +0be571aacb5d6a212a30af3f322a7000d8af1ef9 SOURCES/ruby2_keywords-0.0.2.gem +04cca7a5d9d641fe076e4e24dc5b6ff31922f4c3 SOURCES/sinatra-2.0.8.1.gem +41395e86322ffd31f3a7aef1f697bda3e1e2d6b9 SOURCES/thin-1.7.2.gem +d265c822a6b228392d899e9eb5114613d65e6967 SOURCES/tilt-2.0.10.gem +c23c617c7a0205e465bebad5b8cdf289ae8402a2 SOURCES/tornado-6.1.0.tar.gz +10ba51035928541b7713415f1f2e3a41114972fc SOURCES/webrick-1.7.0.gem diff --git a/SOURCES/Make-ocf-linbit-drbd-agent-pass-OCF-validation.patch b/SOURCES/Make-ocf-linbit-drbd-agent-pass-OCF-validation.patch new file mode 100644 index 0000000..15a7ab4 --- /dev/null +++ b/SOURCES/Make-ocf-linbit-drbd-agent-pass-OCF-validation.patch @@ -0,0 +1,41 @@ +From e58f7897d561cff2f9c257933acdb36d57cc130c Mon Sep 17 00:00:00 2001 +From: Tomas Jelinek <tojeline@redhat.com> +Date: Tue, 4 Jan 2022 12:56:56 +0100 +Subject: [PATCH 2/4] 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. + <optional> + <element name="content"> + <choice> +- <attribute name="type"> +- <choice> +- <value>boolean</value> +- <value>string</value> +- <value>integer</value> +- <value>second</value><!-- used by fence agents --> +- <value>int</value><!-- used by fence agents intead of integer --> +- <value>time</value><!-- used by pacemaker metadata --> +- </choice> +- </attribute> ++ <!-- ++ OCF 1.0 allows values: boolean, integer, string. Agents, however, ++ quite often use other values: int (fence agents), numeric ++ (ocf:linbit:drbd), second (fence agents), time (pacemaker ++ metadata). Since pcs doesn't actually care about the type, we ++ allow any type to keep compatibility with existing agents. ++ --> ++ <attribute name="type" /> + <group> + <!-- + used by fence agents and processed by pcs even though it is not +-- +2.31.1 + diff --git a/SOURCES/bz1811072-01-revert-of-disallowing-to-clone-a-group-with-a-stonit.patch b/SOURCES/bz1811072-01-revert-of-disallowing-to-clone-a-group-with-a-stonit.patch new file mode 100644 index 0000000..6a5ba20 --- /dev/null +++ b/SOURCES/bz1811072-01-revert-of-disallowing-to-clone-a-group-with-a-stonit.patch @@ -0,0 +1,84 @@ +From e1573865543a3d59930b315a40ecd9b7a807e1c1 Mon Sep 17 00:00:00 2001 +From: Ondrej Mular <omular@redhat.com> +Date: Mon, 13 Dec 2021 12:48:26 +0100 +Subject: [PATCH 3/3] revert of disallowing to clone a group with a stonith + inside + +Originally, this was not fixed properly (it was possible to add a stonith +into a cloned group), therefore to stay consistent, this change is being +reverted. It will be fixed in the future by not allowing stonith to be +placed into a group. +--- + pcs/resource.py | 16 ++-------------- + .../tier1/cib_resource/test_clone_unclone.py | 8 ++------ + 2 files changed, 4 insertions(+), 20 deletions(-) + +diff --git a/pcs/resource.py b/pcs/resource.py +index 928477b2..c7cf4c7e 100644 +--- a/pcs/resource.py ++++ b/pcs/resource.py +@@ -1697,7 +1697,7 @@ def resource_clone_create( + ): + element.parentNode.parentNode.removeChild(element.parentNode) + +- def _reject_stonith_clone_report(force_flags, stonith_ids, group_id=None): ++ if element.getAttribute("class") == "stonith": + process_library_reports( + [ + reports.ReportItem( +@@ -1706,24 +1706,12 @@ def resource_clone_create( + is_forced=reports.codes.FORCE in force_flags, + ), + message=reports.messages.CloningStonithResourcesHasNoEffect( +- stonith_ids, group_id=group_id ++ [name] + ), + ) + ] + ) + +- if element.getAttribute("class") == "stonith": +- _reject_stonith_clone_report(force_flags, [name]) +- +- if element.tagName == "group": +- stonith_ids = [ +- resource.getAttribute("id") +- for resource in element.getElementsByTagName("primitive") +- if resource.getAttribute("class") == "stonith" +- ] +- if stonith_ids: +- _reject_stonith_clone_report(force_flags, stonith_ids, name) +- + parts = parse_clone_args(argv, promotable=promotable) + if not update_existing: + clone_id = parts["clone_id"] +diff --git a/pcs_test/tier1/cib_resource/test_clone_unclone.py b/pcs_test/tier1/cib_resource/test_clone_unclone.py +index 7b0e89f9..4cc4cb3e 100644 +--- a/pcs_test/tier1/cib_resource/test_clone_unclone.py ++++ b/pcs_test/tier1/cib_resource/test_clone_unclone.py +@@ -354,12 +354,9 @@ class Clone( + + def test_clone_group_with_stonith(self): + self.set_cib_file(FIXTURE_GROUP_WITH_STONITH) +- self.assert_pcs_fail( ++ self.assert_effect( + "resource clone Group".split(), +- fixture_clone_stonith_msg(group=True), +- ) +- self.assert_resources_xml_in_cib( +- fixture_resources_xml(FIXTURE_GROUP_WITH_STONITH) ++ fixture_resources_xml(FIXTURE_CLONED_GROUP_WITH_STONITH), + ) + + def test_clone_group_with_stonith_forced(self): +@@ -367,7 +364,6 @@ class Clone( + self.assert_effect( + "resource clone Group --force".split(), + fixture_resources_xml(FIXTURE_CLONED_GROUP_WITH_STONITH), +- output=fixture_clone_stonith_msg(forced=True, group=True), + ) + + def test_promotable_clone(self): +-- +2.31.1 + diff --git a/SOURCES/bz1990787-01-Multiple-fixes-in-pcs-resource-move-command.patch b/SOURCES/bz1990787-01-Multiple-fixes-in-pcs-resource-move-command.patch new file mode 100644 index 0000000..b304d91 --- /dev/null +++ b/SOURCES/bz1990787-01-Multiple-fixes-in-pcs-resource-move-command.patch @@ -0,0 +1,1056 @@ +From 4effb249590c6da5eeb13d9106f36e210e6fe5c2 Mon Sep 17 00:00:00 2001 +From: Ondrej Mular <omular@redhat.com> +Date: Mon, 10 Jan 2022 16:04:54 +0100 +Subject: [PATCH 3/4] Multiple fixes in `pcs resource move` 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 +- + pcs/resource.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 + + 12 files changed, 463 insertions(+), 34 deletions(-) + +diff --git a/pcs/common/reports/codes.py b/pcs/common/reports/codes.py +index 8ed83d84..8887fd6d 100644 +--- a/pcs/common/reports/codes.py ++++ b/pcs/common/reports/codes.py +@@ -421,6 +421,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 16171fd0..37c79ba1 100644 +--- a/pcs/common/reports/messages.py ++++ b/pcs/common/reports/messages.py +@@ -6140,6 +6140,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/resource.py b/pcs/resource.py +index c7cf4c7e..f4f2c093 100644 +--- a/pcs/resource.py ++++ b/pcs/resource.py +@@ -24,6 +24,7 @@ from pcs.settings import ( + pacemaker_wait_timeout_status as PACEMAKER_WAIT_TIMEOUT_STATUS, + ) + from pcs.cli.common.errors import ( ++ SEE_MAN_CHANGES, + raise_command_replaced, + CmdLineInputError, + ) +@@ -868,6 +869,12 @@ def resource_move(lib: Any, argv: List[str], modifiers: InputModifiers): + node = None + if argv: + node = argv.pop(0) ++ if node.startswith("lifetime="): ++ deprecation_warning( ++ "Option 'lifetime' has been removed. {}".format( ++ SEE_MAN_CHANGES.format("0.11") ++ ) ++ ) + if argv: + raise CmdLineInputError() + +diff --git a/pcs_test/tier0/common/reports/test_messages.py b/pcs_test/tier0/common/reports/test_messages.py +index a6f92395..a56ef382 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'<node id="{node_id}" uname="{name}"/>' ++ ++ ++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""" ++ <nodes> ++ {content} ++ </nodes> ++ """ ++ ++ + def _rsc_primitive_fixture(res_id): + return f'<primitive id="{res_id}"/>' + +@@ -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 = '<updated_cib with_constraint="True"/>' ++ self.cib_without_constraint = ( ++ '<cib with_constraint="False" updated="True"/>' ++ ) + self.cib_simulate_constraint = ( + '<cib simulate="True" with_constraint="True"/>' + ) +@@ -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 with_constraint="True"/>' ++ cib_without_constraint = '<cib with_constraint="False" updated="True"/>' + 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): + <rsc_location id="prefer-{resource_id}" rsc="{resource_id}" role="Started" node="{node}" score="INFINITY"/> + </constraints> + """, ++ 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 = '<cib with_constraint="True"/>' ++ self.cib_without_constraint = ( ++ '<cib with_constraint="False" updated="True"/>' ++ ) + 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'<node id="{node_id}" uname="{name}"/>' ++ ++ ++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""" ++ <nodes> ++ {content} ++ </nodes> ++ """ ++ ++ ++nodes_section = _nodes_section_fixture( ++ _node_list_fixture(["node", "node1", "node2"]) ++) + resources_primitive = """ + <resources> + <primitive id="A" /> +@@ -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 6df3dff3..7a88cf96 100644 +--- a/pcs_test/tools/command_env/config_runner_pcmk.py ++++ b/pcs_test/tools/command_env/config_runner_pcmk.py +@@ -695,6 +695,7 @@ class PcmkShortcuts: + stdout="", + stderr="", + returncode=0, ++ env=None, + ): + """ + Create a call for crm_resource --clear +@@ -711,6 +712,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/bz2019836-01-fix-rsc-update-cmd-when-unable-to-get-agent-metadata.patch b/SOURCES/bz2019836-01-fix-rsc-update-cmd-when-unable-to-get-agent-metadata.patch new file mode 100644 index 0000000..9611c1a --- /dev/null +++ b/SOURCES/bz2019836-01-fix-rsc-update-cmd-when-unable-to-get-agent-metadata.patch @@ -0,0 +1,73 @@ +From 69bfb22dbd68023069f6dae11e418f6ad455474f Mon Sep 17 00:00:00 2001 +From: Ondrej Mular <omular@redhat.com> +Date: Tue, 7 Dec 2021 11:14:37 +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 b2a5e355..928477b2 100644 +--- a/pcs/resource.py ++++ b/pcs/resource.py +@@ -1075,13 +1075,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 417ca131..0f8415b4 100644 +--- a/pcs_test/tier1/legacy/test_resource.py ++++ b/pcs_test/tier1/legacy/test_resource.py +@@ -4882,6 +4882,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 = """ + <resources> +-- +2.31.1 + diff --git a/SOURCES/bz2032473-01-fix-enabling-corosync-qdevice.patch b/SOURCES/bz2032473-01-fix-enabling-corosync-qdevice.patch new file mode 100644 index 0000000..71a2290 --- /dev/null +++ b/SOURCES/bz2032473-01-fix-enabling-corosync-qdevice.patch @@ -0,0 +1,25 @@ +From 798d054db1a20b7cd2f2aed2b35b9e51835dec55 Mon Sep 17 00:00:00 2001 +From: Tomas Jelinek <tojeline@redhat.com> +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 b569e249..e1923d6f 100644 +--- a/pcsd/remote.rb ++++ b/pcsd/remote.rb +@@ -2002,7 +2002,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/bz2033248-01-skip-checking-of-scsi-devices-to-be-removed.patch b/SOURCES/bz2033248-01-skip-checking-of-scsi-devices-to-be-removed.patch new file mode 100644 index 0000000..277e1a8 --- /dev/null +++ b/SOURCES/bz2033248-01-skip-checking-of-scsi-devices-to-be-removed.patch @@ -0,0 +1,86 @@ +From 1f91f67a18885937794e775bbbcde973ffe59468 Mon Sep 17 00:00:00 2001 +From: Miroslav Lisik <mlisik@redhat.com> +Date: Thu, 16 Dec 2021 14:12:58 +0100 +Subject: [PATCH 1/4] 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/bz2040420-01-fix-creating-empty-cib.patch b/SOURCES/bz2040420-01-fix-creating-empty-cib.patch new file mode 100644 index 0000000..0039b3d --- /dev/null +++ b/SOURCES/bz2040420-01-fix-creating-empty-cib.patch @@ -0,0 +1,94 @@ +From 94d411afc37de231c8a3101c30e1e6ba66ecd223 Mon Sep 17 00:00:00 2001 +From: Tomas Jelinek <tojeline@redhat.com> +Date: Thu, 13 Jan 2022 17:32:38 +0100 +Subject: [PATCH 4/4] 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 2f5949a7..b5b8af05 100644 +--- a/pcs/utils.py ++++ b/pcs/utils.py +@@ -2135,16 +2135,17 @@ def write_empty_cib(cibfile): + """ + Commandline options: no options + """ +- empty_xml = """<?xml version="1.0" encoding="UTF-8"?> +-<cib admin_epoch="0" epoch="1" num_updates="1" validate-with="pacemaker-1.2"> +- <configuration> +- <crm_config/> +- <nodes/> +- <resources/> +- <constraints/> +- </configuration> +- <status/> +-</cib>""" ++ empty_xml = """ ++ <cib admin_epoch="0" epoch="1" num_updates="1" validate-with="pacemaker-3.1"> ++ <configuration> ++ <crm_config/> ++ <nodes/> ++ <resources/> ++ <constraints/> ++ </configuration> ++ <status/> ++ </cib> ++ """ + 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 13312a69..abd02c61 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/bz2044409-01-fix-backend-parameter-all-in-cluster-destroy.patch b/SOURCES/bz2044409-01-fix-backend-parameter-all-in-cluster-destroy.patch new file mode 100644 index 0000000..1131d7f --- /dev/null +++ b/SOURCES/bz2044409-01-fix-backend-parameter-all-in-cluster-destroy.patch @@ -0,0 +1,23 @@ +From fa75f40361bc39cbd645b8014713e4c0ad0cda18 Mon Sep 17 00:00:00 2001 +From: Ivan Devat <idevat@redhat.com> +Date: Mon, 24 Jan 2022 14:08:54 +0100 +Subject: [PATCH 2/2] fix backend parameter "all" in cluster destroy + +--- + src/app/backend/calls/destroyCluster.ts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/app/backend/calls/destroyCluster.ts b/src/app/backend/calls/destroyCluster.ts +index b6e83a41..cf41ea42 100644 +--- a/src/app/backend/calls/destroyCluster.ts ++++ b/src/app/backend/calls/destroyCluster.ts +@@ -4,5 +4,5 @@ const { url } = endpoints.destroyCluster; + + export const destroyCluster = (clusterName: string): CallResult => + http.post(url({ clusterName }), { +- params: [["--all", "1"]], ++ params: [["all", "1"]], + }); +-- +2.31.1 + diff --git a/SOURCES/bz20486401-01-Fix-snmp-client.patch b/SOURCES/bz20486401-01-Fix-snmp-client.patch new file mode 100644 index 0000000..63a05d5 --- /dev/null +++ b/SOURCES/bz20486401-01-Fix-snmp-client.patch @@ -0,0 +1,25 @@ +From 7902bb8fe7f97fbbc93e7001a6c4e8a445dcb44e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Valentin=20Vidi=C4=87?= <vvidic@valentin-vidic.from.hr> +Date: Wed, 15 Dec 2021 20:32:26 +0100 +Subject: [PATCH 1/2] Fix snmp client + +Required constant is missing causing the command to fail on startup and breaking the pcs_snmp_agent service. +--- + pcsd/pcsd-cli-main.rb | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/pcsd/pcsd-cli-main.rb b/pcsd/pcsd-cli-main.rb +index 29b9006d..be72d543 100644 +--- a/pcsd/pcsd-cli-main.rb ++++ b/pcsd/pcsd-cli-main.rb +@@ -10,6 +10,7 @@ require 'remote.rb' + + + PCS = get_pcs_path() ++PCS_INTERNAL = get_pcs_internal_path() + $logger_device = StringIO.new + $logger = Logger.new($logger_device) + early_log($logger) +-- +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 new file mode 100644 index 0000000..fa1ead6 --- /dev/null +++ b/SOURCES/do-not-support-cluster-setup-with-udp-u-transport.patch @@ -0,0 +1,38 @@ +From 49d9c698697b0dd49f53b60340705b4fd656e248 Mon Sep 17 00:00:00 2001 +From: Ivan Devat <idevat@redhat.com> +Date: Tue, 20 Nov 2018 15:03:56 +0100 +Subject: [PATCH] do not support cluster setup with udp(u) transport in RHEL9 + +--- + pcs/pcs.8.in | 2 ++ + pcs/usage.py | 1 + + 2 files changed, 3 insertions(+) + +diff --git a/pcs/pcs.8.in b/pcs/pcs.8.in +index 0bbee071..ba14251d 100644 +--- a/pcs/pcs.8.in ++++ b/pcs/pcs.8.in +@@ -457,6 +457,8 @@ By default, encryption is enabled with cipher=aes256 and hash=sha256. To disable + + Transports udp and udpu: + .br ++WARNING: These transports are not supported in RHEL 9. ++.br + These transports are limited to one address per node. They do not support traffic encryption nor compression. + .br + Transport options are: ip_version, netmtu +diff --git a/pcs/usage.py b/pcs/usage.py +index bc885918..4e286f46 100644 +--- a/pcs/usage.py ++++ b/pcs/usage.py +@@ -916,6 +916,7 @@ Commands: + hash=sha256. To disable encryption, set cipher=none and hash=none. + + Transports udp and udpu: ++ WARNING: These transports are not supported in RHEL 9. + These transports are limited to one address per node. They do not + support traffic encryption nor compression. + Transport options are: +-- +2.31.1 + diff --git a/SOURCES/fix-translating-resource-roles-in-colocation-constra.patch b/SOURCES/fix-translating-resource-roles-in-colocation-constra.patch new file mode 100644 index 0000000..a6cc80a --- /dev/null +++ b/SOURCES/fix-translating-resource-roles-in-colocation-constra.patch @@ -0,0 +1,25 @@ +From f759872276ed8ff04bbf05010c18bbe4d1abdb11 Mon Sep 17 00:00:00 2001 +From: Tomas Jelinek <tojeline@redhat.com> +Date: Tue, 1 Feb 2022 16:10:35 +0100 +Subject: [PATCH 2/2] fix translating resource roles in colocation constraints + +--- + pcs/lib/xml_tools.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pcs/lib/xml_tools.py b/pcs/lib/xml_tools.py +index 07752f92..6a652fd1 100644 +--- a/pcs/lib/xml_tools.py ++++ b/pcs/lib/xml_tools.py +@@ -66,7 +66,7 @@ def export_attributes( + result = {str(key): str(value) for key, value in element.attrib.items()} + if not with_id: + result.pop("id", None) +- for role_name in ("role", "rsc-role"): ++ for role_name in ("role", "rsc-role", "with-rsc-role"): + if role_name in result: + result[role_name] = pacemaker.role.get_value_primary( + const.PcmkRoleType(result[role_name].capitalize()) +-- +2.34.1 + diff --git a/SOURCES/simplify-ternar-expression.patch b/SOURCES/simplify-ternar-expression.patch new file mode 100644 index 0000000..0835fbd --- /dev/null +++ b/SOURCES/simplify-ternar-expression.patch @@ -0,0 +1,26 @@ +From f44cdc871a39da3960bd04565b4d1d5ffa19bd23 Mon Sep 17 00:00:00 2001 +From: Ivan Devat <idevat@redhat.com> +Date: Thu, 20 Jan 2022 13:32:49 +0100 +Subject: [PATCH 1/2] simplify ternar expression + +The motivation for this is that covscan complains about it. +--- + src/app/view/share/useUrlTabs.ts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/app/view/share/useUrlTabs.ts b/src/app/view/share/useUrlTabs.ts +index 7278dad8..a1136bf3 100644 +--- a/src/app/view/share/useUrlTabs.ts ++++ b/src/app/view/share/useUrlTabs.ts +@@ -13,7 +13,7 @@ export const useUrlTabs = <TABS extends ReadonlyArray<string>>( + + return { + currentTab, +- matchedContext: tab !== null ? tab.matched : `/${defaultTab}`, ++ matchedContext: tab?.matched ?? `/${defaultTab}`, + tabList, + }; + }; +-- +2.31.1 + diff --git a/SPECS/pcs.spec b/SPECS/pcs.spec new file mode 100644 index 0000000..d4b1245 --- /dev/null +++ b/SPECS/pcs.spec @@ -0,0 +1,1013 @@ +Name: pcs +Version: 0.11.1 +Release: 10%{?dist} +# https://docs.fedoraproject.org/en-US/packaging-guidelines/LicensingGuidelines/ +# https://fedoraproject.org/wiki/Licensing:Main?rd=Licensing#Good_Licenses +# GPLv2: pcs +# ASL 2.0: tornado +# MIT: backports, dacite, daemons, ethon, mustermann, rack, rack-protection, +# rack-test, sinatra, tilt +# GPLv2 or Ruby: eventmachne +# (GPLv2 or Ruby) and BSD: thin +# BSD or Ruby: open4, rexml, ruby2_keywords, webrick +# BSD and MIT: ffi +License: GPLv2 and ASL 2.0 and MIT and BSD and (GPLv2 or Ruby) and (BSD or Ruby) +URL: https://github.com/ClusterLabs/pcs +Group: System Environment/Base +Summary: Pacemaker Configuration System +#building only for architectures with pacemaker and corosync available +ExclusiveArch: i686 x86_64 s390x ppc64le aarch64 + +%global version_or_commit %{version} +# %%global version_or_commit %%{version}.210-9862 + +%global pcs_source_name %{name}-%{version_or_commit} + +# ui_commit can be determined by hash, tag or branch +%global ui_commit 0.1.12 +%global ui_modules_version 0.1.12 +%global ui_src_name pcs-web-ui-%{ui_commit} + +%global pcs_snmp_pkg_name pcs-snmp + +%global pyagentx_version 0.4.pcs.2 +%global tornado_version 6.1.0 +%global dacite_version 1.6.0 +%global version_rubygem_backports 3.17.2 +%global version_rubygem_daemons 1.3.1 +%global version_rubygem_ethon 0.12.0 +%global version_rubygem_eventmachine 1.2.7 +%global version_rubygem_ffi 1.13.1 +%global version_rubygem_mustermann 1.1.1 +%global version_rubygem_open4 1.3.4 +%global version_rubygem_rack 2.2.3 +%global version_rubygem_rack_protection 2.0.8.1 +%global version_rubygem_rack_test 1.1.0 +%global version_rubygem_rexml 3.2.5 +%global version_rubygem_ruby2_keywords 0.0.2 +%global version_rubygem_sinatra 2.0.8.1 +%global version_rubygem_thin 1.7.2 +%global version_rubygem_tilt 2.0.10 +%global version_rubygem_webrick 1.7.0 + +%global required_pacemaker_version 2.1.0 + +%global pcs_bundled_dir pcs_bundled +%global pcsd_public_dir pcsd/public +%global rubygem_bundle_dir pcsd/vendor/bundle +%global rubygem_cache_dir %{rubygem_bundle_dir}/cache + +# mangling shebang in /usr/lib/pcsd/vendor/bundle/ruby/gems/rack-2.0.5/test/cgi/test from /usr/bin/env ruby to #!/usr/bin/ruby +#*** ERROR: ./usr/lib/pcsd/vendor/bundle/ruby/gems/rack-2.0.5/test/cgi/test.ru has shebang which doesn't start with '/' (../../bin/rackup) +#mangling shebang in /usr/lib/pcsd/vendor/bundle/ruby/gems/rack-2.0.5/test/cgi/rackup_stub.rb from /usr/bin/env ruby to #!/usr/bin/ruby +#*** WARNING: ./usr/lib/pcsd/vendor/bundle/ruby/gems/rack-2.0.5/test/cgi/sample_rackup.ru is executable but has empty or no shebang, removing executable bit +#*** WARNING: ./usr/lib/pcsd/vendor/bundle/ruby/gems/rack-2.0.5/test/cgi/lighttpd.conf is executable but has empty or no shebang, removing executable bit +#*** ERROR: ambiguous python shebang in /usr/lib/pcsd/vendor/bundle/ruby/gems/ffi-1.9.25/ext/ffi_c/libffi/generate-darwin-source-and-headers.py: #!/usr/bin/env python. Change it to python3 (or python2) explicitly. +%undefine __brp_mangle_shebangs + +# https://fedoraproject.org/wiki/Changes/Avoid_usr_bin_python_in_RPM_Build#Python_bytecompilation +# Enforce python3 because bytecompilation of tornado produced warnings: +# DEPRECATION WARNING: python2 invoked with /usr/bin/python. +# Use /usr/bin/python3 or /usr/bin/python2 +# /usr/bin/python will be removed or switched to Python 3 in the future. +%global __python %{__python3} + +Source0: %{url}/archive/%{version_or_commit}/%{pcs_source_name}.tar.gz + +Source41: https://github.com/ondrejmular/pyagentx/archive/v%{pyagentx_version}/pyagentx-%{pyagentx_version}.tar.gz +Source42: https://github.com/tornadoweb/tornado/archive/v%{tornado_version}/tornado-%{tornado_version}.tar.gz +Source44: https://github.com/konradhalas/dacite/archive/v%{dacite_version}/dacite-%{dacite_version}.tar.gz + +Source81: https://rubygems.org/downloads/backports-%{version_rubygem_backports}.gem +Source82: https://rubygems.org/downloads/ethon-%{version_rubygem_ethon}.gem +Source83: https://rubygems.org/downloads/ffi-%{version_rubygem_ffi}.gem +Source85: https://rubygems.org/downloads/rexml-%{version_rubygem_rexml}.gem +Source86: https://rubygems.org/downloads/mustermann-%{version_rubygem_mustermann}.gem +# We needed to re-upload open4 rubygem because of issues with sources in gating. +# Unfortunately, there was no newer version available, therefore we had to +# change its 'version' ourselves. +Source87: https://rubygems.org/downloads/open4-%{version_rubygem_open4}.gem#/open4-%{version_rubygem_open4}-1.gem +Source88: https://rubygems.org/downloads/rack-%{version_rubygem_rack}.gem +Source89: https://rubygems.org/downloads/rack-protection-%{version_rubygem_rack_protection}.gem +Source90: https://rubygems.org/downloads/rack-test-%{version_rubygem_rack_test}.gem +Source91: https://rubygems.org/downloads/sinatra-%{version_rubygem_sinatra}.gem +Source92: https://rubygems.org/downloads/tilt-%{version_rubygem_tilt}.gem +Source93: https://rubygems.org/downloads/eventmachine-%{version_rubygem_eventmachine}.gem +Source94: https://rubygems.org/downloads/daemons-%{version_rubygem_daemons}.gem +Source95: https://rubygems.org/downloads/thin-%{version_rubygem_thin}.gem +Source96: https://rubygems.org/downloads/ruby2_keywords-%{version_rubygem_ruby2_keywords}.gem +Source97: https://rubygems.org/downloads/webrick-%{version_rubygem_webrick}.gem + +Source100: https://github.com/ClusterLabs/pcs-web-ui/archive/%{ui_commit}/%{ui_src_name}.tar.gz +Source101: https://github.com/ClusterLabs/pcs-web-ui/releases/download/%{ui_commit}/pcs-web-ui-node-modules-%{ui_modules_version}.tar.xz + +# Patches from upstream. +# They should come before downstream patches to avoid unnecessary conflicts. +# Z-streams are exception here: they can come from upstream but should be +# applied at the end to keep z-stream changes as straightforward as possible. +# Patch1: bzNUMBER-01-name.patch +Patch2: bz2032473-01-fix-enabling-corosync-qdevice.patch +Patch3: bz2019836-01-fix-rsc-update-cmd-when-unable-to-get-agent-metadata.patch +Patch4: bz1811072-01-revert-of-disallowing-to-clone-a-group-with-a-stonit.patch +Patch5: bz2033248-01-skip-checking-of-scsi-devices-to-be-removed.patch +Patch6: Make-ocf-linbit-drbd-agent-pass-OCF-validation.patch +Patch7: bz1990787-01-Multiple-fixes-in-pcs-resource-move-command.patch +Patch8: bz2040420-01-fix-creating-empty-cib.patch +Patch9: bz20486401-01-Fix-snmp-client.patch +Patch10: fix-translating-resource-roles-in-colocation-constra.patch + +# Downstream patches do not come from upstream. They adapt pcs for specific +# RHEL needs. + +# pcs patches: <= 200 +Patch1: do-not-support-cluster-setup-with-udp-u-transport.patch + +# ui patches: >200 +# Patch201: bzNUMBER-01-name.patch +Patch201: simplify-ternar-expression.patch +Patch202: bz2044409-01-fix-backend-parameter-all-in-cluster-destroy.patch + +# git for patches +BuildRequires: git-core +#printf from coreutils is used in makefile +BuildRequires: coreutils +# python for pcs +BuildRequires: python3 >= 3.9 +BuildRequires: python3-cryptography +BuildRequires: python3-dateutil >= 2.7.0 +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pycurl +BuildRequires: python3-pip +BuildRequires: python3-pyparsing +BuildRequires: python3-cryptography +BuildRequires: python3-lxml +# for building bundled python packages +BuildRequires: python3-wheel +# for bundled python dateutil +BuildRequires: python3-setuptools_scm +# gcc for compiling custom rubygems +BuildRequires: gcc +BuildRequires: gcc-c++ +# ruby and gems for pcsd +BuildRequires: ruby >= 2.5 +BuildRequires: ruby-devel +BuildRequires: rubygems +BuildRequires: rubygem-bundler +# ruby libraries for tests +BuildRequires: rubygem-json +BuildRequires: rubygem-test-unit +# for touching patch files (sanitization function) +BuildRequires: diffstat +# for post, preun and postun macros +BuildRequires: systemd +BuildRequires: make +# Red Hat logo for creating symlink of favicon +BuildRequires: redhat-logos +# for building web ui +BuildRequires: npm +# cluster stack packages for pkg-config +BuildRequires: booth +BuildRequires: corosync-qdevice-devel +BuildRequires: corosynclib-devel >= 3.0 +BuildRequires: fence-agents-common +BuildRequires: pacemaker-libs-devel >= %{required_pacemaker_version} +BuildRequires: resource-agents +BuildRequires: sbd + +# python and libraries for pcs, setuptools for pcs entrypoint +Requires: python3 >= 3.9 +Requires: python3-cryptography +Requires: python3-dateutil >= 2.7.0 +Requires: python3-lxml +Requires: python3-setuptools +Requires: python3-pycurl +Requires: python3-pyparsing +Requires: python3-cryptography +# ruby and gems for pcsd +Requires: ruby >= 2.5 +Requires: rubygems +Requires: rubygem-json +# for killall +Requires: psmisc +# cluster stack and related packages +Requires: pcmk-cluster-manager >= %{required_pacemaker_version} +Suggests: pacemaker >= %{required_pacemaker_version} +Requires: (corosync >= 3.0 if pacemaker) +# pcs enables corosync encryption by default so we require libknet1-plugins-all +Requires: (libknet1-plugins-all if corosync) +Requires: pacemaker-cli >= %{required_pacemaker_version} +# for post, preun and postun macros +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd +# pam is used for authentication inside daemon (python ctypes) +# more details: https://bugzilla.redhat.com/show_bug.cgi?id=1717113 +Requires: pam +# favicon Red Hat logo +Requires: redhat-logos +# needs logrotate for /etc/logrotate.d/pcsd +Requires: logrotate + +Provides: bundled(tornado) = %{tornado_version} +Provides: bundled(dacite) = %{dacite_version} +Provides: bundled(backports) = %{version_rubygem_backports} +Provides: bundled(daemons) = %{version_rubygem_daemons} +Provides: bundled(ethon) = %{version_rubygem_ethon} +Provides: bundled(eventmachine) = %{version_rubygem_eventmachine} +Provides: bundled(ffi) = %{version_rubygem_ffi} +Provides: bundled(mustermann) = %{version_rubygem_mustermann} +Provides: bundled(open4) = %{version_rubygem_open4} +Provides: bundled(rack) = %{version_rubygem_rack} +Provides: bundled(rack_protection) = %{version_rubygem_rack_protection} +Provides: bundled(rack_test) = %{version_rubygem_rack_test} +Provides: bundled(rexml) = %{version_rubygem_rexml} +Provides: bundled(ruby2_keywords) = %{version_rubygem_ruby2_keywords} +Provides: bundled(sinatra) = %{version_rubygem_sinatra} +Provides: bundled(thin) = %{version_rubygem_thin} +Provides: bundled(tilt) = %{version_rubygem_tilt} +Provides: bundled(webrick) = %{version_rubygem_webrick} + +%description +pcs is a corosync and pacemaker configuration tool. It permits users to +easily view, modify and create pacemaker based clusters. + +# pcs-snmp package definition +%package -n %{pcs_snmp_pkg_name} +Group: System Environment/Base +Summary: Pacemaker cluster SNMP agent +# https://fedoraproject.org/wiki/Licensing:Main?rd=Licensing#Good_Licenses +# GPLv2: pcs +# BSD-2-Clause: pyagentx +License: GPLv2 and BSD-2-Clause +URL: https://github.com/ClusterLabs/pcs + +# tar for unpacking pyagetx source tar ball +BuildRequires: tar + +Requires: pcs = %{version}-%{release} +Requires: pacemaker +Requires: net-snmp + +Provides: bundled(pyagentx) = %{pyagentx_version} + +%description -n %{pcs_snmp_pkg_name} +SNMP agent that provides information about pacemaker cluster to the master agent (snmpd) + +%prep +# -- following is inspired by python-simplejon.el5 -- +# Update timestamps on the files touched by a patch, to avoid non-equal +# .pyc/.pyo files across the multilib peers within a build + +update_times(){ + # update_times <reference_file> <file_to_touch> ... + # set the access and modification times of each file_to_touch to the times + # of reference_file + + # put all args to file_list + file_list=("$@") + # first argument is reference_file: so take it and remove from file_list + reference_file=${file_list[0]} + unset file_list[0] + + for fname in ${file_list[@]}; do + # some files could be deleted by a patch therefore we test file for + # existance before touch to avoid exit with error: No such file or + # directory + # diffstat cannot create list of files without deleted files + test -e $fname && touch -r $reference_file $fname + done +} + +update_times_patch(){ + # update_times_patch <patch_file_name> + # set the access and modification times of each file in patch to the times + # of patch_file_name + + patch_file_name=$1 + + # diffstat + # -l lists only the filenames. No histogram is generated. + # -p override the logic that strips common pathnames, + # simulating the patch "-p" option. (Strip the smallest prefix containing + # num leading slashes from each file name found in the patch file) + update_times ${patch_file_name} `diffstat -p1 -l ${patch_file_name}` +} + +# documentation for setup/autosetup/autopatch: +# * http://ftp.rpm.org/max-rpm/s1-rpm-inside-macros.html +# * https://rpm-software-management.github.io/rpm/manual/autosetup.html +# patch web-ui sources +%autosetup -D -T -b 100 -a 101 -S git -n %{ui_src_name} -N +%autopatch -p1 -m 201 +# update_times_patch %%{PATCH201} +update_times_patch %{PATCH201} +update_times_patch %{PATCH202} + +# patch pcs sources +%autosetup -S git -n %{pcs_source_name} -N +%autopatch -p1 -M 200 +update_times_patch %{PATCH1} +update_times_patch %{PATCH2} +update_times_patch %{PATCH3} +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 %{PATCH10} + +# prepare dirs/files necessary for building all bundles +# ----------------------------------------------------- +# 1) rubygems sources + +mkdir -p %{rubygem_cache_dir} +cp -f %SOURCE81 %{rubygem_cache_dir} +cp -f %SOURCE82 %{rubygem_cache_dir} +cp -f %SOURCE83 %{rubygem_cache_dir} +cp -f %SOURCE85 %{rubygem_cache_dir} +cp -f %SOURCE86 %{rubygem_cache_dir} +# For reason why we are renaming open4 rubygem, see comment of source +# definition above. +cp -f %SOURCE87 %{rubygem_cache_dir}/open4-%{version_rubygem_open4}.gem +cp -f %SOURCE88 %{rubygem_cache_dir} +cp -f %SOURCE89 %{rubygem_cache_dir} +cp -f %SOURCE90 %{rubygem_cache_dir} +cp -f %SOURCE91 %{rubygem_cache_dir} +cp -f %SOURCE92 %{rubygem_cache_dir} +cp -f %SOURCE93 %{rubygem_cache_dir} +cp -f %SOURCE94 %{rubygem_cache_dir} +cp -f %SOURCE95 %{rubygem_cache_dir} +cp -f %SOURCE96 %{rubygem_cache_dir} +cp -f %SOURCE97 %{rubygem_cache_dir} + + +# 2) prepare python bundles +mkdir -p %{pcs_bundled_dir}/src +cp -f %SOURCE41 rpm/ +cp -f %SOURCE42 rpm/ +cp -f %SOURCE44 rpm/ + +%build +%define debug_package %{nil} + +./autogen.sh +%{configure} --enable-local-build --enable-use-local-cache-only --enable-individual-bundling PYTHON=%{__python3} ruby_CFLAGS="%{optflags}" ruby_LIBS="%{build_ldflags}" +make all + +# build pcs-web-ui +make -C %{_builddir}/%{ui_src_name} build BUILD_USE_EXISTING_NODE_MODULES=true + +%install +rm -rf $RPM_BUILD_ROOT +pwd + +%make_install + +# install pcs-web-ui +cp -r %{_builddir}/%{ui_src_name}/build ${RPM_BUILD_ROOT}%{_libdir}/%{pcsd_public_dir}/ui + +# symlink favicon into pcsd directories +mkdir -p ${RPM_BUILD_ROOT}%{_libdir}/%{pcsd_public_dir}/images/ +ln -fs /etc/favicon.png ${RPM_BUILD_ROOT}%{_libdir}/%{pcsd_public_dir}/images/favicon.png + +# prepare license files +# some rubygems do not have a license file (ruby2_keywords, thin) +mv %{rubygem_bundle_dir}/gems/backports-%{version_rubygem_backports}/LICENSE.txt backports_LICENSE.txt +mv %{rubygem_bundle_dir}/gems/daemons-%{version_rubygem_daemons}/LICENSE daemons_LICENSE +mv %{rubygem_bundle_dir}/gems/ethon-%{version_rubygem_ethon}/LICENSE ethon_LICENSE +mv %{rubygem_bundle_dir}/gems/eventmachine-%{version_rubygem_eventmachine}/LICENSE eventmachine_LICENSE +mv %{rubygem_bundle_dir}/gems/eventmachine-%{version_rubygem_eventmachine}/GNU eventmachine_GNU +mv %{rubygem_bundle_dir}/gems/ffi-%{version_rubygem_ffi}/COPYING ffi_COPYING +mv %{rubygem_bundle_dir}/gems/ffi-%{version_rubygem_ffi}/LICENSE ffi_LICENSE +mv %{rubygem_bundle_dir}/gems/ffi-%{version_rubygem_ffi}/LICENSE.SPECS ffi_LICENSE.SPECS +mv %{rubygem_bundle_dir}/gems/mustermann-%{version_rubygem_mustermann}/LICENSE mustermann_LICENSE +mv %{rubygem_bundle_dir}/gems/open4-%{version_rubygem_open4}/LICENSE open4_LICENSE +mv %{rubygem_bundle_dir}/gems/rack-%{version_rubygem_rack}/MIT-LICENSE rack_MIT-LICENSE +mv %{rubygem_bundle_dir}/gems/rexml-%{version_rubygem_rexml}/LICENSE.txt rexml_LICENSE.txt +mv %{rubygem_bundle_dir}/gems/rack-protection-%{version_rubygem_rack_protection}/License rack-protection_License +mv %{rubygem_bundle_dir}/gems/rack-test-%{version_rubygem_rack_test}/MIT-LICENSE.txt rack-test_MIT-LICENSE.txt +mv %{rubygem_bundle_dir}/gems/sinatra-%{version_rubygem_sinatra}/LICENSE sinatra_LICENSE +mv %{rubygem_bundle_dir}/gems/tilt-%{version_rubygem_tilt}/COPYING tilt_COPYING +mv %{rubygem_bundle_dir}/gems/webrick-%{version_rubygem_webrick}/LICENSE.txt webrick_LICENSE.txt + +cp %{pcs_bundled_dir}/src/pyagentx-*/LICENSE.txt pyagentx_LICENSE.txt +cp %{pcs_bundled_dir}/src/pyagentx-*/CONTRIBUTORS.txt pyagentx_CONTRIBUTORS.txt +cp %{pcs_bundled_dir}/src/pyagentx-*/README.md pyagentx_README.md + +cp %{pcs_bundled_dir}/src/tornado-*/LICENSE tornado_LICENSE +cp %{pcs_bundled_dir}/src/tornado-*/README.rst tornado_README.rst + +cp %{pcs_bundled_dir}/src/dacite-*/LICENSE dacite_LICENSE +cp %{pcs_bundled_dir}/src/dacite-*/README.md dacite_README.md + +# We are not building debug package for pcs but we need to add MiniDebuginfo +# to the bundled shared libraries from rubygem extensions in order to satisfy +# rpmdiff's binary stripping checker. +# Therefore we call find-debuginfo.sh script manually in order to strip +# binaries and add MiniDebugInfo with .gnu_debugdata section +/usr/lib/rpm/find-debuginfo.sh -j2 -m -i -S debugsourcefiles.list +# find-debuginfo.sh generated some files into /usr/lib/debug and +# /usr/src/debug/ that we don't want in the package +rm -rf $RPM_BUILD_ROOT%{_libdir}/debug +rm -rf $RPM_BUILD_ROOT/usr/lib/debug +rm -rf $RPM_BUILD_ROOT%{_prefix}/src/debug + +# We can remove files required for gem compilation +rm -rf $RPM_BUILD_ROOT%{_libdir}/%{rubygem_bundle_dir}/gems/eventmachine-%{version_rubygem_eventmachine}/ext +rm -rf $RPM_BUILD_ROOT%{_libdir}/%{rubygem_bundle_dir}/gems/ffi-%{version_rubygem_ffi}/ext +rm -rf $RPM_BUILD_ROOT%{_libdir}/%{rubygem_bundle_dir}/gems/thin-%{version_rubygem_thin}/ext + +%check +# In the building environment LC_CTYPE is set to C which causes tests to fail +# due to python prints a warning about it to stderr. The following environment +# variable disables the warning. +# On the live system either UTF8 locale is set or the warning is emmited +# which breaks pcs. That is the correct behavior since with wrong locales it +# would be probably broken anyway. +# The main concern here is to make the tests pass. +# See https://fedoraproject.org/wiki/Changes/python3_c.utf-8_locale for details. +export PYTHONCOERCECLOCALE=0 + +run_all_tests(){ + #run pcs tests + + # disabled tests: + # + # pcs_test.tier0.lib.commands.test_resource_agent.DescribeAgentUtf8.test_describe + # For an unknown reason this test is failing in mock environment and + # passing outside the mock environment. + # TODO: Investigate the issue + + %{__python3} pcs_test/suite --tier0 -v --vanilla --all-but \ + pcs_test.tier0.lib.commands.test_resource_agent.DescribeAgentUtf8.test_describe \ + pcs_test.tier0.daemon.app.test_app_remote.SyncConfigMutualExclusive.test_get_not_locked \ + pcs_test.tier0.daemon.app.test_app_remote.SyncConfigMutualExclusive.test_post_not_locked \ + + test_result_python=$? + + #run pcsd tests and remove them + GEM_HOME=$RPM_BUILD_ROOT%{_libdir}/%{rubygem_bundle_dir} ruby \ + -I$RPM_BUILD_ROOT%{_libdir}/pcsd \ + -Ipcsd/test \ + pcsd/test/test_all_suite.rb + test_result_ruby=$? + + if [ $test_result_python -ne 0 ]; then + return $test_result_python + fi + return $test_result_ruby +} + +run_all_tests + +%posttrans +# Make sure the new version of the daemon is runnning. +# Also, make sure to start pcsd-ruby if it hasn't been started or even +# installed before. This is done by restarting pcsd.service. +%{_bindir}/systemctl daemon-reload +%{_bindir}/systemctl try-restart pcsd.service + + +%post +%systemd_post pcsd.service +%systemd_post pcsd-ruby.service + +%post -n %{pcs_snmp_pkg_name} +%systemd_post pcs_snmp_agent.service + +%preun +%systemd_preun pcsd.service +%systemd_preun pcsd-ruby.service + +%preun -n %{pcs_snmp_pkg_name} +%systemd_preun pcs_snmp_agent.service + +%postun +%systemd_postun_with_restart pcsd.service +%systemd_postun_with_restart pcsd-ruby.service + +%postun -n %{pcs_snmp_pkg_name} +%systemd_postun_with_restart pcs_snmp_agent.service + +%files +%doc CHANGELOG.md +%doc README.md +%doc tornado_README.rst +%doc dacite_README.md +%license tornado_LICENSE +%license dacite_LICENSE +%license COPYING +# rugygem licenses +%license backports_LICENSE.txt +%license daemons_LICENSE +%license ethon_LICENSE +%license eventmachine_LICENSE +%license eventmachine_GNU +%license ffi_COPYING +%license ffi_LICENSE +%license ffi_LICENSE.SPECS +%license mustermann_LICENSE +%license open4_LICENSE +%license rack_MIT-LICENSE +%license rack-protection_License +%license rack-test_MIT-LICENSE.txt +%license rexml_LICENSE.txt +%license sinatra_LICENSE +%license tilt_COPYING +%license webrick_LICENSE.txt +%{python3_sitelib}/* +%{_sbindir}/pcs +%{_sbindir}/pcsd +%{_libdir}/pcs/* +%{_libdir}/pcsd/* +%{_unitdir}/pcsd.service +%{_unitdir}/pcsd-ruby.service +%{_datadir}/bash-completion/completions/pcs +%{_sharedstatedir}/pcsd +%config(noreplace) %{_sysconfdir}/pam.d/pcsd +%dir %{_var}/log/pcsd +%config(noreplace) %{_sysconfdir}/logrotate.d/pcsd +%config(noreplace) %{_sysconfdir}/sysconfig/pcsd +%ghost %config(noreplace) %attr(0600,root,root) %{_sharedstatedir}/pcsd/cfgsync_ctl +%ghost %config(noreplace) %attr(0600,root,root) %{_sharedstatedir}/pcsd/known-hosts +%ghost %config(noreplace) %attr(0600,root,root) %{_sharedstatedir}/pcsd/pcsd.cookiesecret +%ghost %config(noreplace) %attr(0600,root,root) %{_sharedstatedir}/pcsd/pcsd.crt +%ghost %config(noreplace) %attr(0600,root,root) %{_sharedstatedir}/pcsd/pcsd.key +%ghost %config(noreplace) %attr(0644,root,root) %{_sharedstatedir}/pcsd/pcs_settings.conf +%ghost %config(noreplace) %attr(0644,root,root) %{_sharedstatedir}/pcsd/pcs_users.conf +%{_mandir}/man8/pcs.* +%{_mandir}/man8/pcsd.* +%exclude %{_libdir}/pcs/pcs_snmp_agent +%exclude %{_libdir}/pcs/%{pcs_bundled_dir}/packages/pyagentx* + + +%files -n %{pcs_snmp_pkg_name} +%{_libdir}/pcs/pcs_snmp_agent +%{_libdir}/pcs/%{pcs_bundled_dir}/packages/pyagentx* +%{_unitdir}/pcs_snmp_agent.service +%{_datadir}/snmp/mibs/PCMK-PCS*-MIB.txt +%{_mandir}/man8/pcs_snmp_agent.* +%config(noreplace) %{_sysconfdir}/sysconfig/pcs_snmp_agent +%doc CHANGELOG.md +%doc pyagentx_CONTRIBUTORS.txt +%doc pyagentx_README.md +%license COPYING +%license pyagentx_LICENSE.txt + +%changelog +* Tue Feb 01 2022 Miroslav Lisik <mlisik@redhat.com> - 0.11.1-10 +- Fixed snmp client +- Fixed translating resource roles in colocation constraint +- Resolves: rhbz#2048640 + +* Tue Jan 25 2022 Miroslav Lisik <mlisik@redhat.com> - 0.11.1-9 +- Fixed cluster destroy in web ui +- Fixed covscan issue in web ui +- Resolves: rhbz#2044409 + +* Fri Jan 14 2022 Miroslav Lisik <mlisik@redhat.com> - 0.11.1-8 +- Fixed 'pcs resource move' command +- Fixed removing of unavailable fence-scsi storage device +- Fixed ocf validation of ocf linbit drdb agent +- Fixed creating empty cib +- Updated pcs-web-ui +- Resolves: rhbz#1990787 rhbz#2033248 rhbz#2039883 rhbz#2040420 + +* Wed Dec 15 2021 Miroslav Lisik <mlisik@redhat.com> - 0.11.1-7 +- Fixed enabling corosync-qdevice +- Fixed resource update command when unable to get agent metadata +- Fixed revert of disallowing to clone a group with a stonith +- Resolves: rhbz#1811072 rhbz#2019836 rhbz#2032473 + +* Thu Dec 02 2021 Miroslav Lisik <mlisik@redhat.com> - 0.11.1-6 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Updated pcs web ui +- Resolves: rhbz#1990787 rhbz#1997019 rhbz#2012129 rhbz#2024542 rhbz#2027678 rhbz#2027679 + +* Thu Nov 18 2021 Miroslav Lisik <mlisik@redhat.com> - 0.11.1-5 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Resolves: rhbz#1990787 rhbz#2018969 rhbz#2019836 rhbz#2023752 rhbz#2012129 + +* Tue Nov 02 2021 Miroslav Lisik <mlisik@redhat.com> - 0.11.1-4 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Updated pcs web ui +- Enabled wui patching +- Resolves: rhbz#1811072 rhbz#1945305 rhbz#1997019 rhbz#2012129 + +* Thu Aug 26 2021 Miroslav Lisik <mlisik@redhat.com> - 0.11.1-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Resolves: rhbz#1283805 rhbz#1910644 rhbz#1910645 rhbz#1956703 rhbz#1956706 rhbz#1985981 rhbz#1991957 rhbz#1996062 rhbz#1996067 + +* Tue Aug 24 2021 Miroslav Lisik <mlisik@redhat.com> - 0.11.0.alpha.1-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Updated pcs web ui +- Resolves: rhbz#1283805 rhbz#1910644 rhbz#1910645 rhbz#1985981 rhbz#1991957 rhbz#1996067 + +* Thu Aug 19 2021 DJ Delorie <dj@redhat.com> - 0.10.9-2 +- Rebuilt for libffi 3.4.2 SONAME transition. + Related: rhbz#1891914 + +* Tue Aug 10 2021 Miroslav Lisik <mlisik@redhat.com> - 0.10.9-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Resolves: rhbz#1991957 + +* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 0.10.8-11 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Tue Jul 20 2021 Miroslav Lisik <mlisik@redhat.com> - 0.10.8-10 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Fixed web-ui build +- Fixed tests for pacemaker 2.1 +- Resolves: rhbz#1975440 rhbz#1922302 + +* Tue Jun 22 2021 Mohan Boddu <mboddu@redhat.com> - 0.10.8-9 +- Rebuilt for RHEL 9 BETA for openssl 3.0 + Related: rhbz#1971065 + +* Wed Jun 16 2021 Miroslav Lisik <mlisik@redhat.com> - 0.10.8-8 +- Rebuild with fixed gaiting tests +- Stopped bundling rubygem-json (use distribution package instead) +- Fixed patches +- Resolves: rhbz#1881064 + +* Tue Jun 15 2021 Miroslav Lisik <mlisik@redhat.com> - 0.10.8-7 +- Fixed License tag +- Rebuild with fixed dependency for gating tier0 tests +- Resolves: rhbz#1881064 + +* Thu Jun 10 2021 Miroslav Lisik <mlisik@redhat.com> - 0.10.8-6 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Removed clufter related commands +- Resolves: rhbz#1881064 + +* Wed Apr 28 2021 Miroslav Lisik <mlisik@redhat.com> - 0.10.8-5 +- Updated pcs web ui node modules +- Fixed build issue on low memory build hosts +- Resolves: rhbz#1951272 + +* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 0.10.8-4 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Thu Mar 04 2021 Miroslav Lisik <mlisik@redhat.com> - 0.10.8-3 +- Replace pyOpenSSL with python-cryptography +- Resolves: rhbz#1927404 + +* Fri Feb 19 2021 Miroslav Lisik <mlisik@redhat.com> - 0.10.8-2 +- Bundle rubygem depedencies and python3-tornado +- Resolves: rhbz#1929710 + +* Thu Feb 04 2021 Miroslav Lisik <mlisik@redhat.com> - 0.10.8-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Updated pcs-web-ui +- Updated bundled python dependency: dacite +- Changed BuildRequires from git to git-core +- Added conditional (Build)Requires: rubygem(rexml) +- Added conditional Requires: rubygem(webrick) + +* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 0.10.7-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Thu Jan 7 2021 Vít Ondruch <vondruch@redhat.com> - 0.10.7-3 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Ruby_3.0 + +* Thu Nov 26 2020 Ondrej Mular <omular@redhat.com> - 0.10.7-2 +- Python 3.10 related fix + +* Wed Sep 30 2020 Miroslav Lisik <mlisik@redhat.com> - 0.10.7-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Added dependency on python packages pyparsing and dateutil +- Fixed virtual bundle provides for ember, handelbars, jquery and jquery-ui +- Removed dependency on python3-clufter + +* Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.10.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue Jul 21 2020 Miroslav Lisik <mlisik@redhat.com> - 0.10.6-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Updated pcs-web-ui +- Stopped bundling tornado (use distribution package instead) +- Stopped bundling rubygem-tilt (use distribution package instead) +- Removed rubygem bundling +- Removed unneeded BuildRequires: execstack, gcc, gcc-c++ +- Excluded some tests for tornado daemon + +* Tue Jul 21 2020 Tom Stellard <tstellar@redhat.com> - 0.10.5-8 +- Use make macros +- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro + +* Wed Jul 15 2020 Ondrej Mular <omular@redhat.com> - 0.10.5-7 +- Use fixed upstream version of dacite with Python 3.9 support +- Split upstream tests in gating into tiers + +* Fri Jul 03 2020 Ondrej Mular <omular@redhat.com> - 0.10.5-6 +- Use patched version of dacite compatible with Python 3.9 +- Resolves: rhbz#1838327 + +* Tue May 26 2020 Miro Hrončok <mhroncok@redhat.com> - 0.10.5-5 +- Rebuilt for Python 3.9 + +* Thu May 07 2020 Ondrej Mular <omular@redhat.com> - 0.10.5-4 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Run only tier0 tests in check section + +* Fri Apr 03 2020 Ondrej Mular <omular@redhat.com> - 0.10.5-3 +- Enable gating + +* Fri Mar 27 2020 Ondrej Mular <omular@redhat.com> - 0.10.5-2 +- Remove usage of deprecated module xml.etree.cElementTree +- Resolves: rhbz#1817695 + +* Wed Mar 18 2020 Miroslav Lisik <mlisik@redhat.com> - 0.10.5-1 +- Rebased to latest upstream sources (see CHANGELOG.md) + +* Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.10.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Thu Nov 28 2019 Miroslav Lisik <mlisik@redhat.com> - 0.10.4-1 +- Rebased to latest upstream sources (see CHANGELOG.md) + +* Thu Oct 03 2019 Miro Hrončok <mhroncok@redhat.com> - 0.10.3-2 +- Rebuilt for Python 3.8.0rc1 (#1748018) + +* Fri Aug 23 2019 Ondrej Mular <omular@redhat.com> - 0.10.3-1 +- Rebased to latest upstream sources (see CHANGELOG.md) + +* Mon Aug 19 2019 Miro Hrončok <mhroncok@redhat.com> - 0.10.2-3 +- Rebuilt for Python 3.8 + +* Fri Jul 26 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.10.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Fri Jun 14 2019 Ondrej Mular <omular@redhat.com> - 0.10.2-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Added pam as required package +- An alternative webUI rebased to latest upstream sources +- Improved configuration files permissions in rpm + +* Tue Mar 19 2019 Tomas Jelinek <tojeline@redhat.com> - 0.10.1-4 +- Removed unused dependency rubygem-multi_json +- Removed files needed only for building rubygems from the package + +* Mon Feb 04 2019 Ivan Devát <idevat@redhat.com> - 0.10.1-3 +- Corrected gem install flags + +* Fri Feb 01 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.10.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Wed Jan 09 2019 Ivan Devát <idevat@redhat.com> - 0.10.1-1 +- Rebased to latest upstream sources (see CHANGELOG.md) + +* Tue Oct 09 2018 Ondrej Mular <omular@redhat.com> - 0.10.0.alpha.6-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Resolves: rhbz#1618911 + +* Fri Aug 31 2018 Ivan Devát <idevat@redhat.com> - 0.10.0.alpha.2-3 +- Started bundling rubygem-tilt (rubygem-tilt is orphaned in fedora due to rubygem-prawn dependency) +- Enabled passing tests + +* Sat Aug 25 2018 Ivan Devát <idevat@redhat.com> - 0.10.0.alpha.2-2 +- Fixed error with missing rubygem location during pcsd start +- Resolves: rhbz#1618911 + +* Thu Aug 02 2018 Ivan Devát <idevat@redhat.com> - 0.10.0.alpha.2-1 +- Rebased to latest upstream sources (see CHANGELOG.md) + +* Wed Jul 25 2018 Ivan Devát <idevat@redhat.com> - 0.9.164-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.164-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Tue Jun 19 2018 Miro Hrončok <mhroncok@redhat.com> - 0.9.164-2 +- Rebuilt for Python 3.7 + +* Mon Apr 09 2018 Ondrej Mular <omular@redhat.com> - 0.9.164-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Fixed: CVE-2018-1086, CVE-2018-1079 + +* Mon Feb 26 2018 Ivan Devát <idevat@redhat.com> - 0.9.163-2 +- Fixed crash when adding a node to a cluster + +* Tue Feb 20 2018 Ivan Devát <idevat@redhat.com> - 0.9.163-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- Adapted for Rack 2 and Sinatra 2 + +* Fri Feb 09 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 0.9.160-5 +- Escape macros in %%changelog + +* Thu Feb 08 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.160-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Sat Jan 20 2018 Björn Esser <besser82@fedoraproject.org> - 0.9.160-3 +- Rebuilt for switch to libxcrypt + +* Fri Jan 05 2018 Mamoru TASAKA <mtasaka@fedoraproject.org> - 0.9.160-2 +- F-28: rebuild for ruby25 +- Workaround for gem install option + +* Wed Oct 18 2017 Ondrej Mular <omular@redhat.com> - 0.9.160-1 +- Rebased to latest upstream sources (see CHANGELOG.md) +- All pcs tests are temporarily disabled because of issues in pacemaker. + +* Thu Sep 14 2017 Ondrej Mular <omular@redhat.com> - 0.9.159-4 +- Bundle rubygem-rack-protection which is being updated to 2.0.0 in Fedora. +- Removed setuptools patch. +- Disabled debuginfo subpackage. + +* Thu Aug 03 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.159-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.159-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Wed Jul 12 2017 Ondrej Mular <omular@redhat.com> - 0.9.159-1 +- Rebased to latest upstream sources (see CHANGELOG.md) + +* Tue May 23 2017 Tomas Jelinek <tojeline@redhat.com> - 0.9.156-3 +- Fixed python locales issue preventing build-time tests to pass +- Bundle rubygem-tilt which is being retired from Fedora + +* Thu Mar 23 2017 Tomas Jelinek <tojeline@redhat.com> - 0.9.156-2 +- Fixed Cross-site scripting (XSS) vulnerability in web UI CVE-2017-2661 +- Re-added support for clufter as it is now available for Python 3 + +* Wed Feb 22 2017 Tomas Jelinek <tojeline@redhat.com> - 0.9.156-1 +- Rebased to latest upstream sources (see CHANGELOG.md) + +* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.155-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Jan 12 2017 Vít Ondruch <vondruch@redhat.com> - 0.9.155-2 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Ruby_2.4 + +* Wed Jan 04 2017 Adam Williamson <awilliam@redhat.com> - 0.9.155-1 +- Latest release 0.9.155 +- Fix tests with Python 3.6 and lxml 3.7 +- Package the license as license, not doc +- Use -f param for rm when wiping test directories as they are nested now + +* Mon Dec 19 2016 Miro Hrončok <mhroncok@redhat.com> +- Rebuild for Python 3.6 + +* Tue Oct 18 2016 Tomas Jelinek <tojeline@redhat.com> - 0.9.154-2 +- Fixed upgrading from pcs-0.9.150 + +* Thu Sep 22 2016 Tomas Jelinek <tojeline@redhat.com> - 0.9.154-1 +- Re-synced to upstream sources +- Spec file cleanup and fixes + +* Tue Jul 19 2016 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.9.150-2 +- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages + +* Mon Apr 11 2016 Tomas Jelinek <tojeline@redhat.com> - 0.9.150-1 +- Re-synced to upstream sources +- Make pcs depend on python3 +- Spec file cleanup + +* Tue Feb 23 2016 Tomas Jelinek <tojeline@redhat.com> - 0.9.149-2 +- Fixed rubygems issues which prevented pcsd from starting +- Added missing python-lxml dependency + +* Thu Feb 18 2016 Tomas Jelinek <tojeline@redhat.com> - 0.9.149-1 +- Re-synced to upstream sources +- Security fix for CVE-2016-0720, CVE-2016-0721 +- Fixed rubygems issues which prevented pcsd from starting +- Rubygems built with RELRO +- Spec file cleanup +- Fixed multilib .pyc/.pyo issue + +* Thu Feb 04 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.144-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Tue Jan 12 2016 Vít Ondruch <vondruch@redhat.com> - 0.9.144-2 +- Rebuilt for https://fedoraproject.org/wiki/Changes/Ruby_2.3 + +* Fri Sep 18 2015 Tomas Jelinek <tojeline@redhat.com> - 0.9.144-1 +- Re-synced to upstream sources + +* Tue Jun 23 2015 Tomas Jelinek <tojeline@redhat.com> - 0.9.141-2 +- Added requirement for psmisc for killall + +* Tue Jun 23 2015 Tomas Jelinek <tojeline@redhat.com> - 0.9.141-1 +- Re-synced to upstream sources + +* Thu Jun 18 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.9.140-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Fri Jun 05 2015 Tomas Jelinek <tojeline@redhat.com> - 0.9.140-1 +- Re-synced to upstream sources + +* Fri May 22 2015 Tomas Jelinek <tojeline@redhat.com> - 0.9.139-4 +- Fix for CVE-2015-1848, CVE-2015-3983 (sessions not signed) + +* Thu Mar 26 2015 Tomas Jelinek <tojeline@redhat.com> - 0.9.139-3 +- Add BuildRequires: systemd (rhbz#1206253) + +* Fri Feb 27 2015 Tomas Jelinek <tojeline@redhat.com> - 0.9.139-2 +- Reflect clufter inclusion (rhbz#1180723) + +* Thu Feb 19 2015 Tomas Jelinek <tojeline@redhat.com> - 0.9.139-1 +- Re-synced to upstream sources + +* Sat Jan 17 2015 Mamoru TASAKA <mtasaka@fedoraproject.org> - 0.9.115-5 +- Rebuild for https://fedoraproject.org/wiki/Changes/Ruby_2.2 + +* Sun Aug 17 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.9.115-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Fri Jun 06 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.9.115-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Tue May 06 2014 Tomas Jelinek <tojeline@redhat.com> - 0.9.115-2 +- Rebuild to fix ruby dependencies + +* Mon Apr 21 2014 Chris Feist <cfeist@redhat.com> - 0.9.115-1 +- Re-synced to upstream sources + +* Fri Dec 13 2013 Chris Feist <cfeist@redhat.com> - 0.9.102-1 +- Re-synced to upstream sources + +* Wed Jun 19 2013 Chris Feist <cfeist@redhat.com> - 0.9.48-1 +- Rebuild with upstream sources + +* Thu Jun 13 2013 Chris Feist <cfeist@redhat.com> - 0.9.44-5 +- Added fixes for building rpam with ruby-2.0.0 + +* Mon Jun 03 2013 Chris Feist <cfeist@redhat.com> - 0.9.44-4 +- Rebuild with upstream sources + +* Tue May 07 2013 Chris Feist <cfeist@redhat.com> - 0.9.41-2 +- Resynced to upstream sources + +* Fri Apr 19 2013 Chris Feist <cfeist@redhat.com> - 0.9.39-1 +- Fixed gem building +- Re-synced to upstream sources + +* Mon Mar 25 2013 Chris Feist <cfeist@rehdat.com> - 0.9.36-4 +- Don't try to build gems at all + +* Mon Mar 25 2013 Chris Feist <cfeist@rehdat.com> - 0.9.36-3 +- Removed all gems from build, will need to find pam package in the future + +* Mon Mar 25 2013 Chris Feist <cfeist@redhat.com> - 0.9.36-2 +- Removed duplicate libraries already present in fedora + +* Mon Mar 18 2013 Chris Feist <cfeist@redhat.com> - 0.9.36-1 +- Resynced to latest upstream + +* Mon Mar 11 2013 Chris Feist <cfeist@redhat.com> - 0.9.33-1 +- Resynched to latest upstream +- pcsd has been moved to /usr/lib to fix /usr/local packaging issues + +* Thu Feb 21 2013 Chris Feist <cfeist@redhat.com> - 0.9.32-1 +- Resynced to latest version of pcs/pcsd + +* Mon Nov 05 2012 Chris Feist <cfeist@redhat.com> - 0.9.27-3 +- Build on all archs + +* Thu Oct 25 2012 Chris Feist <cfeist@redhat.com> - 0.9.27-2 +- Resync to latest version of pcs +- Added pcsd daemon + +* Mon Oct 08 2012 Chris Feist <cfeist@redhat.cmo> - 0.9.26-1 +- Resync to latest version of pcs + +* Thu Sep 20 2012 Chris Feist <cfeist@redhat.cmo> - 0.9.24-1 +- Resync to latest version of pcs + +* Thu Sep 20 2012 Chris Feist <cfeist@redhat.cmo> - 0.9.23-1 +- Resync to latest version of pcs + +* Wed Sep 12 2012 Chris Feist <cfeist@redhat.cmo> - 0.9.22-1 +- Resync to latest version of pcs + +* Thu Sep 06 2012 Chris Feist <cfeist@redhat.cmo> - 0.9.19-1 +- Resync to latest version of pcs + +* Tue Aug 07 2012 Chris Feist <cfeist@redhat.com> - 0.9.12-1 +- Resync to latest version of pcs + +* Fri Jul 20 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.9.3.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu May 24 2012 Chris Feist <cfeist@redhat.com> - 0.9.4-1 +- Resync to latest version of pcs +- Move cluster creation options to cluster sub command. + +* Mon May 07 2012 Chris Feist <cfeist@redhat.com> - 0.9.3.1-1 +- Resync to latest version of pcs which includes fixes to work with F17. + +* Mon Mar 19 2012 Chris Feist <cfeist@redhat.com> - 0.9.2.4-1 +- Resynced to latest version of pcs + +* Mon Jan 23 2012 Chris Feist <cfeist@redhat.com> - 0.9.1-1 +- Updated BuildRequires and %%doc section for fedora + +* Fri Jan 20 2012 Chris Feist <cfeist@redhat.com> - 0.9.0-2 +- Updated spec file for fedora specific changes + +* Mon Jan 16 2012 Chris Feist <cfeist@redhat.com> - 0.9.0-1 +- Initial Build