diff --git a/CHANGELOG.md b/CHANGELOG.md index e25bdc7d6..7239ee33a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,14 @@ ### Added - Commands `pcs cluster node rename-corosync` and `pcs cluster node rename-cib` for cluster node renaming ([RHEL-149172]) +- `pcs constraint config` (and its variants for each constraint type) now list + resources in sets in the order defined in the CIB, instead of sorting them + alphabetically ([rhbz#2461143]) ([RHEL-176478]) + [RHEL-149172]: https://redhat.atlassian.net/browse/RHEL-149172 +[RHEL-176478]: https://redhat.atlassian.net/browse/RHEL-176478 +[rhbz#2461143]: https://bugzilla.redhat.com/show_bug.cgi?id=2461143 ## [0.11.11] - 2026-01-06 diff --git a/pcs/cli/constraint/output/set.py b/pcs/cli/constraint/output/set.py index 5395ebf7a..5335fdf47 100644 --- a/pcs/cli/constraint/output/set.py +++ b/pcs/cli/constraint/output/set.py @@ -1,7 +1,4 @@ -from typing import ( - Optional, - Sequence, -) +from typing import Optional, Sequence from pcs.cli.common.output import ( INDENT_STEP, @@ -12,7 +9,7 @@ from pcs.cli.reports.output import warn from pcs.common.pacemaker.constraint import CibResourceSetDto from pcs.common.str_tools import ( - format_list, + format_list_dont_sort, format_optional, indent, pairs_to_text, @@ -56,7 +53,7 @@ def resource_set_to_text( ] set_options = [ "Resources: {resources}".format( - resources=format_list(resource_set_dto.resources_ids) + resources=format_list_dont_sort(resource_set_dto.resources_ids) ) ] + pairs_to_text(_resource_set_options_to_pairs(resource_set_dto)) output.extend(indent(set_options, indent_step=INDENT_STEP)) diff --git a/pcs_test/Makefile.am b/pcs_test/Makefile.am index 53f451be9..fefe99da2 100644 --- a/pcs_test/Makefile.am +++ b/pcs_test/Makefile.am @@ -86,7 +86,9 @@ EXTRA_DIST = \ tier0/cli/constraint/__init__.py \ tier0/cli/constraint/location/__init__.py \ tier0/cli/constraint/location/test_command.py \ + tier0/cli/constraint/output/__init__.py \ tier0/cli/constraint/output/test_all.py \ + tier0/cli/constraint/output/test_set.py \ tier0/cli/constraint/rule/__init__.py \ tier0/cli/constraint/rule/test_command.py \ tier0/cli/constraint/test_command.py \ diff --git a/pcs_test/resources/cib-all.xml b/pcs_test/resources/cib-all.xml index 70d070faa..30d1c07c6 100644 --- a/pcs_test/resources/cib-all.xml +++ b/pcs_test/resources/cib-all.xml @@ -173,12 +173,12 @@ - - - + + + - + diff --git a/pcs_test/resources/constraint-commands b/pcs_test/resources/constraint-commands index 759e71463..6bb8a96d2 100644 --- a/pcs_test/resources/constraint-commands +++ b/pcs_test/resources/constraint-commands @@ -22,9 +22,9 @@ pcs -- constraint order stop R7 then stop G2 \ pcs -- constraint order start G2 then start B2 \ id=order-G2-B2-Optional kind=Optional; pcs -- constraint order \ - set B2 R6-clone require-all=0 action=stop \ + set R6-clone B2 require-all=0 action=stop \ set G1-clone sequential=0 action=promote \ - setoptions id=order_set_B2R6-cloneSe kind=Optional; + setoptions id=order_set_R6-cloneB2Se kind=Optional; pcs -- constraint ticket add custom-ticket1 Promoted G1-clone \ id=ticket-custom-ticket1-G1-clone-Promoted loss-policy=demote; pcs -- constraint ticket \ diff --git a/pcs_test/tier0/cli/constraint/output/__init__.py b/pcs_test/tier0/cli/constraint/output/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pcs_test/tier0/cli/constraint/output/test_set.py b/pcs_test/tier0/cli/constraint/output/test_set.py new file mode 100644 index 000000000..55031b066 --- /dev/null +++ b/pcs_test/tier0/cli/constraint/output/test_set.py @@ -0,0 +1,45 @@ +from unittest import TestCase + +from pcs.cli.constraint.output.order import set_constraint_to_text +from pcs.common.pacemaker.constraint import ( + CibConstraintOrderAttributesDto, + CibConstraintOrderSetDto, +) +from pcs.common.pacemaker.constraint.set import CibResourceSetDto + + +class TestSetConstraintToTextResourceOrder(TestCase): + def test_resource_order_is_preserved(self): + result = set_constraint_to_text( + CibConstraintOrderSetDto( + resource_sets=[ + CibResourceSetDto( + set_id="set1", + sequential=None, + require_all=None, + ordering=None, + action=None, + role=None, + score=None, + kind=None, + resources_ids=["c_rsc", "a_rsc", "b_rsc"], + ), + ], + attributes=CibConstraintOrderAttributesDto( + constraint_id="order1", + symmetrical=None, + require_all=None, + score=None, + kind=None, + ), + ), + with_id=False, + ) + self.assertEqual( + result, + [ + "Set Constraint:", + " Resource Set:", + " Resources: 'c_rsc', 'a_rsc', 'b_rsc'", + ], + ) diff --git a/pcs_test/tier0/cli/constraint/test_command.py b/pcs_test/tier0/cli/constraint/test_command.py index 6cb33f0c9..453c5ea1d 100644 --- a/pcs_test/tier0/cli/constraint/test_command.py +++ b/pcs_test/tier0/cli/constraint/test_command.py @@ -69,7 +69,7 @@ def test_constraint_or_rule_ids(self): "loc_constr_with_expired_rule-rule", "loc_constr_with_not_expired_rule-rule-1", "colocation-G1-clone-R6-clone--100", - "order_set_B2R6-cloneSe", + "order_set_R6-cloneB2Se", "ticket_set_R7B2G2", ] self._call_cmd(constraint_or_rule_ids) diff --git a/pcs_test/tier0/common/pacemaker/constraint/all.py b/pcs_test/tier0/common/pacemaker/constraint/all.py index e22b422fe..b7ddad4ff 100644 --- a/pcs_test/tier0/common/pacemaker/constraint/all.py +++ b/pcs_test/tier0/common/pacemaker/constraint/all.py @@ -29,7 +29,7 @@ def test_constraints_defined(self): "location-R7-non-existing-node--10000", "order-G2-B2-Optional", "order-R7-G2-mandatory", - "order_set_B2R6-cloneSe", + "order_set_R6-cloneB2Se", "ticket-custom-ticket1-G1-clone-Promoted", "ticket_set_R7B2G2", }, diff --git a/pcs_test/tier1/constraint/test_config.py b/pcs_test/tier1/constraint/test_config.py index 271b5ff1d..8a1352a22 100644 --- a/pcs_test/tier1/constraint/test_config.py +++ b/pcs_test/tier1/constraint/test_config.py @@ -282,7 +282,7 @@ def test_success(self): Set Constraint: score=-1 Resource Set: - Resources: 'G2', 'R7' + Resources: 'R7', 'G2' role=Started Resource Set: Resources: 'B2', 'R6-clone' @@ -296,7 +296,7 @@ def test_success(self): Set Constraint: kind=Optional Resource Set: - Resources: 'B2', 'R6-clone' + Resources: 'R6-clone', 'B2' require-all=0 action=stop Resource Set: Resources: 'G1-clone' @@ -308,7 +308,7 @@ def test_success(self): Set Constraint: ticket=ticket2 Resource Set: - Resources: 'B2', 'G2', 'R7' + Resources: 'R7', 'B2', 'G2' role=Stopped """ ) @@ -348,7 +348,7 @@ def test_all_option(self): Set Constraint: score=-1 Resource Set: - Resources: 'G2', 'R7' + Resources: 'R7', 'G2' role=Started Resource Set: Resources: 'B2', 'R6-clone' @@ -362,7 +362,7 @@ def test_all_option(self): Set Constraint: kind=Optional Resource Set: - Resources: 'B2', 'R6-clone' + Resources: 'R6-clone', 'B2' require-all=0 action=stop Resource Set: Resources: 'G1-clone' @@ -374,7 +374,7 @@ def test_all_option(self): Set Constraint: ticket=ticket2 Resource Set: - Resources: 'B2', 'G2', 'R7' + Resources: 'R7', 'B2', 'G2' role=Stopped """ ) @@ -410,7 +410,7 @@ def test_full_option(self): Set Constraint: colocation_set_R7G2B2 score=-1 Resource Set: colocation_set_R7G2B2_set - Resources: 'G2', 'R7' + Resources: 'R7', 'G2' role=Started Resource Set: colocation_set_R7G2B2_set-1 Resources: 'B2', 'R6-clone' @@ -421,12 +421,12 @@ def test_full_option(self): start resource 'G2' then start resource 'B2' (id: order-G2-B2-Optional) kind=Optional Order Set Constraints: - Set Constraint: order_set_B2R6-cloneSe + Set Constraint: order_set_R6-cloneB2Se kind=Optional - Resource Set: order_set_B2R6-cloneSe_set - Resources: 'B2', 'R6-clone' + Resource Set: order_set_R6-cloneB2Se_set + Resources: 'R6-clone', 'B2' require-all=0 action=stop - Resource Set: order_set_B2R6-cloneSe_set-1 + Resource Set: order_set_R6-cloneB2Se_set-1 Resources: 'G1-clone' sequential=0 action=promote Ticket Constraints: @@ -436,7 +436,7 @@ def test_full_option(self): Set Constraint: ticket_set_R7B2G2 ticket=ticket2 Resource Set: ticket_set_R7B2G2_set - Resources: 'B2', 'G2', 'R7' + Resources: 'R7', 'B2', 'G2' role=Stopped """ ) @@ -476,7 +476,7 @@ def test_all_full_options(self): Set Constraint: colocation_set_R7G2B2 score=-1 Resource Set: colocation_set_R7G2B2_set - Resources: 'G2', 'R7' + Resources: 'R7', 'G2' role=Started Resource Set: colocation_set_R7G2B2_set-1 Resources: 'B2', 'R6-clone' @@ -487,12 +487,12 @@ def test_all_full_options(self): start resource 'G2' then start resource 'B2' (id: order-G2-B2-Optional) kind=Optional Order Set Constraints: - Set Constraint: order_set_B2R6-cloneSe + Set Constraint: order_set_R6-cloneB2Se kind=Optional - Resource Set: order_set_B2R6-cloneSe_set - Resources: 'B2', 'R6-clone' + Resource Set: order_set_R6-cloneB2Se_set + Resources: 'R6-clone', 'B2' require-all=0 action=stop - Resource Set: order_set_B2R6-cloneSe_set-1 + Resource Set: order_set_R6-cloneB2Se_set-1 Resources: 'G1-clone' sequential=0 action=promote Ticket Constraints: @@ -502,7 +502,7 @@ def test_all_full_options(self): Set Constraint: ticket_set_R7B2G2 ticket=ticket2 Resource Set: ticket_set_R7B2G2_set - Resources: 'B2', 'G2', 'R7' + Resources: 'R7', 'B2', 'G2' role=Stopped """ ) diff --git a/pcs_test/tier1/legacy/test_constraints.py b/pcs_test/tier1/legacy/test_constraints.py index 5c4129acb..dd9459bbd 100644 --- a/pcs_test/tier1/legacy/test_constraints.py +++ b/pcs_test/tier1/legacy/test_constraints.py @@ -2380,13 +2380,13 @@ def test_master_slave_constraint(self): # noqa: PLR0915 Set Constraint: colocation_set_s1d1 score=INFINITY Resource Set: colocation_set_s1d1_set - Resources: 'dummy1', 'stateful1' + Resources: 'stateful1', 'dummy1' Order Constraints: start resource 'stateful1' then start resource 'dummy1' (id: order-stateful1-dummy1-mandatory) Order Set Constraints: Set Constraint: order_set_s1d1 Resource Set: order_set_s1d1_set - Resources: 'dummy1', 'stateful1' + Resources: 'stateful1', 'dummy1' """ ), ) @@ -2625,13 +2625,13 @@ def test_clone_constraint(self): # noqa: PLR0915 Set Constraint: colocation_set_d1dy score=INFINITY Resource Set: colocation_set_d1dy_set - Resources: 'dummy', 'dummy1' + Resources: 'dummy1', 'dummy' Order Constraints: start resource 'dummy' then start resource 'dummy1' (id: order-dummy-dummy1-mandatory) Order Set Constraints: Set Constraint: order_set_d1dy Resource Set: order_set_d1dy_set - Resources: 'dummy', 'dummy1' + Resources: 'dummy1', 'dummy' """ ), ) @@ -3422,7 +3422,7 @@ def test_duplicate_set_constraints(self): # noqa: PLR0915 Set Constraint: colocation_set_D6D1 score=INFINITY Resource Set: colocation_set_D6D1_set - Resources: 'D1', 'D6' + Resources: 'D6', 'D1' Order Set Constraints: Set Constraint: order_set_D1D2 Resource Set: order_set_D1D2_set @@ -3442,7 +3442,7 @@ def test_duplicate_set_constraints(self): # noqa: PLR0915 Resources: 'D5', 'D6' Set Constraint: order_set_D6D1 Resource Set: order_set_D6D1_set - Resources: 'D1', 'D6' + Resources: 'D6', 'D1' """ ), ) @@ -3789,7 +3789,7 @@ def test_constraints_custom_id(self): # noqa: PLR0915 Set Constraint: id4 score=100 Resource Set: id4_set - Resources: 'D1', 'D2' + Resources: 'D2', 'D1' Order Constraints: start resource 'D1' then start resource 'D2' (id: id7) start resource 'D2' then start resource 'D1' (id: id8) @@ -3801,7 +3801,7 @@ def test_constraints_custom_id(self): # noqa: PLR0915 Set Constraint: id6 kind=Mandatory Resource Set: id6_set - Resources: 'D1', 'D2' + Resources: 'D2', 'D1' """ ), ) diff --git a/pcs_test/tools/constraints_dto.py b/pcs_test/tools/constraints_dto.py index 44b8fdc12..f4ed596e1 100644 --- a/pcs_test/tools/constraints_dto.py +++ b/pcs_test/tools/constraints_dto.py @@ -354,7 +354,7 @@ def get_all_constraints( CibConstraintOrderSetDto( resource_sets=[ CibResourceSetDto( - set_id="order_set_B2R6-cloneSe_set", + set_id="order_set_R6-cloneB2Se_set", sequential=None, require_all=False, ordering=None, @@ -362,10 +362,10 @@ def get_all_constraints( role=None, score=None, kind=None, - resources_ids=["B2", "R6-clone"], + resources_ids=["R6-clone", "B2"], ), CibResourceSetDto( - set_id="order_set_B2R6-cloneSe_set-1", + set_id="order_set_R6-cloneB2Se_set-1", sequential=False, require_all=None, ordering=None, @@ -377,7 +377,7 @@ def get_all_constraints( ), ], attributes=CibConstraintOrderAttributesDto( - constraint_id="order_set_B2R6-cloneSe", + constraint_id="order_set_R6-cloneB2Se", symmetrical=None, require_all=None, score=None,