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,