From 181ad849bad1e9967da7e40ffeba59069912d1d2 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 18:47:15 -0800 Subject: [PATCH 01/41] Test: cts-cli: Use word boundaries for CIB version attributes In the sed call, match a space character instead of a word boundary, because word boundary support is version-dependent (for example, wasn't part of POSIX sed for a long time). Re-order the shadow version replacements as admin_epoch -> epoch -> num_updates, since that's the order of precedence. Signed-off-by: Reid Wahl --- cts/cts-cli.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cts/cts-cli.in b/cts/cts-cli.in index 6f2422b3587..eadb6a69ba1 100644 --- a/cts/cts-cli.in +++ b/cts/cts-cli.in @@ -193,9 +193,9 @@ def reset_shadow_cib_version(): """Set various version numbers in a shadow CIB file back to 0.""" with fileinput.input(files=[shadow_path()], inplace=True) as f: for line in f: - line = re.sub('epoch="[0-9]*"', 'epoch="1"', line) - line = re.sub('num_updates="[0-9]*"', 'num_updates="0"', line) - line = re.sub('admin_epoch="[0-9]*"', 'admin_epoch="0"', line) + line = re.sub(r'\badmin_epoch="[0-9]*"', 'admin_epoch="0"', line) + line = re.sub(r'\bepoch="[0-9]*"', 'epoch="1"', line) + line = re.sub(r'\bnum_updates="[0-9]*"', 'num_updates="0"', line) print(line, end='') @@ -1417,7 +1417,7 @@ class CrmAttributeRegressionTest(RegressionTest): "crm_attribute --query -n cpu -N node1 -z"), # This update will fail because it has version numbers Test("Replace operation should fail", - """cibadmin -Q | sed -e 's/epoch="[^"]*"/epoch="1"/' | cibadmin -R -p""", + """cibadmin -Q | sed -e 's/ epoch="[^"]*"/ epoch="1"/' | cibadmin -R -p""", expected_rc=ExitStatus.OLD), ] @@ -2346,7 +2346,7 @@ class CrmSimulateRegressionTest(RegressionTest): no_version_cib = good_cib.replace('validate-with="pacemaker-1.2" ', "") - no_version_bad_cib = bad_version_cib.replace('epoch="3"', 'epoch="30"').replace("start", "break") + no_version_bad_cib = re.sub(r'\bepoch="3"', 'epoch="30"', bad_version_cib).replace("start", "break") basic_tests = [ Test("Show allocation scores with crm_simulate", From c40b5b45a7fd3f1c83e57957861276a01f5c7ab1 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 19:00:47 -0800 Subject: [PATCH 02/41] Feature: libcib, tools: Empty CIB contains admin_epoch before epoch The order of precedence of version numbers when determining which of two CIBs is newer, is admin_epoch -> epoch -> num_updates. This change affects cibadmin, crm_shadow, and createEmptyCib(). However, since this only affects newly created empty CIBs, the attribute order shouldn't matter to users unless they're diffing the empty CIB against some other CIB. Signed-off-by: Reid Wahl --- cts/cli/regression.access_render.exp | 10 +-- cts/cli/regression.acls.exp | 74 +++++++++--------- cts/cli/regression.cibadmin.exp | 24 +++--- cts/cli/regression.crm_attribute.exp | 70 ++++++++--------- cts/cli/regression.crm_resource.exp | 110 +++++++++++++-------------- cts/cli/regression.crm_shadow.exp | 11 +-- cts/cli/regression.crm_standby.exp | 4 +- cts/cli/regression.crm_ticket.exp | 20 ++--- cts/cli/regression.upgrade.exp | 8 +- cts/cli/regression.validity.exp | 6 +- lib/cib/cib_utils.c | 2 +- 11 files changed, 170 insertions(+), 169 deletions(-) diff --git a/cts/cli/regression.access_render.exp b/cts/cli/regression.access_render.exp index f0ec2675178..ed2f704bcfd 100644 --- a/cts/cli/regression.access_render.exp +++ b/cts/cli/regression.access_render.exp @@ -1,6 +1,6 @@ =#=#=#= Begin test: Configure some ACLs =#=#=#= =#=#=#= Current cib after: Configure some ACLs =#=#=#= - + @@ -23,7 +23,7 @@ * Passed: cibadmin - Configure some ACLs =#=#=#= Begin test: Enable ACLs =#=#=#= =#=#=#= Current cib after: Enable ACLs =#=#=#= - + @@ -50,7 +50,7 @@ * Passed: crm_attribute - Enable ACLs =#=#=#= Begin test: An instance of ACLs render (into color) =#=#=#= - +    @@ -77,7 +77,7 @@ * Passed: cibadmin - An instance of ACLs render (into color) =#=#=#= Begin test: An instance of ACLs render (into namespacing) =#=#=#= - + @@ -105,7 +105,7 @@ =#=#=#= Begin test: An instance of ACLs render (into text) =#=#=#= vvv---[ READABLE ]---vvv - + diff --git a/cts/cli/regression.acls.exp b/cts/cli/regression.acls.exp index a6aeb155e23..353edeb53c3 100644 --- a/cts/cli/regression.acls.exp +++ b/cts/cli/regression.acls.exp @@ -1,6 +1,6 @@ =#=#=#= Begin test: Configure some ACLs =#=#=#= =#=#=#= Current cib after: Configure some ACLs =#=#=#= - + @@ -56,7 +56,7 @@ * Passed: cibadmin - Configure some ACLs =#=#=#= Begin test: Enable ACLs =#=#=#= =#=#=#= Current cib after: Enable ACLs =#=#=#= - + @@ -116,7 +116,7 @@ * Passed: crm_attribute - Enable ACLs =#=#=#= Begin test: Set cluster option =#=#=#= =#=#=#= Current cib after: Set cluster option =#=#=#= - + @@ -177,7 +177,7 @@ * Passed: crm_attribute - Set cluster option =#=#=#= Begin test: New ACL role =#=#=#= =#=#=#= Current cib after: New ACL role =#=#=#= - + @@ -241,7 +241,7 @@ * Passed: cibadmin - New ACL role =#=#=#= Begin test: New ACL target =#=#=#= =#=#=#= Current cib after: New ACL target =#=#=#= - + @@ -308,7 +308,7 @@ * Passed: cibadmin - New ACL target =#=#=#= Begin test: Another ACL role =#=#=#= =#=#=#= Current cib after: Another ACL role =#=#=#= - + @@ -378,7 +378,7 @@ * Passed: cibadmin - Another ACL role =#=#=#= Begin test: Another ACL target =#=#=#= =#=#=#= Current cib after: Another ACL target =#=#=#= - + @@ -451,7 +451,7 @@ * Passed: cibadmin - Another ACL target =#=#=#= Begin test: Updated ACL =#=#=#= =#=#=#= Current cib after: Updated ACL =#=#=#= - + @@ -560,7 +560,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= End test: l33t-haxor: Create a resource - Insufficient privileges (4) =#=#=#= * Passed: cibadmin - l33t-haxor: Create a resource =#=#=#= Begin test: niceguy: Query configuration =#=#=#= - + @@ -641,7 +641,7 @@ crm_attribute: Error performing operation: Permission denied =#=#=#= Begin test: niceguy: Set fencing-enabled =#=#=#= pcmk__apply_creation_acl trace: ACLs allow creation of with id="cib-bootstrap-options-fencing-enabled" =#=#=#= Current cib after: niceguy: Set fencing-enabled =#=#=#= - + @@ -721,7 +721,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= End test: niceguy: Create a resource - Insufficient privileges (4) =#=#=#= * Passed: cibadmin - niceguy: Create a resource =#=#=#= Begin test: root: Query configuration =#=#=#= - + @@ -796,7 +796,7 @@ cibadmin: CIB API call failed: Permission denied * Passed: cibadmin - root: Query configuration =#=#=#= Begin test: root: Set fencing-enabled =#=#=#= =#=#=#= Current cib after: root: Set fencing-enabled =#=#=#= - + @@ -871,7 +871,7 @@ cibadmin: CIB API call failed: Permission denied * Passed: crm_attribute - root: Set fencing-enabled =#=#=#= Begin test: root: Create a resource =#=#=#= =#=#=#= Current cib after: root: Create a resource =#=#=#= - + @@ -948,7 +948,7 @@ cibadmin: CIB API call failed: Permission denied * Passed: cibadmin - root: Create a resource =#=#=#= Begin test: root: Create another resource (with description) =#=#=#= =#=#=#= Current cib after: root: Create another resource (with description) =#=#=#= - + @@ -1045,7 +1045,7 @@ pcmk__apply_creation_acl trace: Creation of scaffolding with pcmk__apply_creation_acl trace: ACLs allow creation of with id="dummy-meta_attributes-target-role" Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role value=Stopped =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#= - + @@ -1129,7 +1129,7 @@ Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attribut unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Stopped =#=#=#= Current cib after: niceguy: Query a resource meta attribute =#=#=#= - + @@ -1213,7 +1213,7 @@ Stopped unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Deleted 'dummy' option: id=dummy-meta_attributes-target-role name=target-role =#=#=#= Current cib after: niceguy: Remove a resource meta attribute =#=#=#= - + @@ -1296,7 +1296,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h pcmk__apply_creation_acl trace: ACLs allow creation of with id="dummy-meta_attributes-target-role" Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role value=Started =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#= - + @@ -1404,7 +1404,7 @@ Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attribut =#=#=#= End test: betteridea: Query configuration - explicit deny - OK (0) =#=#=#= * Passed: cibadmin - betteridea: Query configuration - explicit deny - + @@ -1432,7 +1432,7 @@ pcmk__check_acl trace: Default ACL denies user 'niceguy' read/write access to / cibadmin: CIB API call failed: Permission denied =#=#=#= End test: niceguy: Replace - remove acls - Insufficient privileges (4) =#=#=#= * Passed: cibadmin - niceguy: Replace - remove acls - + @@ -1518,7 +1518,7 @@ pcmk__apply_creation_acl trace: ACLs disallow creation of with id=" cibadmin: CIB API call failed: Permission denied =#=#=#= End test: niceguy: Replace - create resource - Insufficient privileges (4) =#=#=#= * Passed: cibadmin - niceguy: Replace - create resource - + @@ -1602,7 +1602,7 @@ pcmk__check_acl trace: Default ACL denies user 'niceguy' read/write access to / cibadmin: CIB API call failed: Permission denied =#=#=#= End test: niceguy: Replace - modify attribute (deny) - Insufficient privileges (4) =#=#=#= * Passed: cibadmin - niceguy: Replace - modify attribute (deny) - + @@ -1686,7 +1686,7 @@ pcmk__check_acl trace: Default ACL denies user 'niceguy' read/write access to / cibadmin: CIB API call failed: Permission denied =#=#=#= End test: niceguy: Replace - delete attribute (deny) - Insufficient privileges (4) =#=#=#= * Passed: cibadmin - niceguy: Replace - delete attribute (deny) - + @@ -1770,7 +1770,7 @@ pcmk__check_acl trace: Default ACL denies user 'niceguy' read/write access to / cibadmin: CIB API call failed: Permission denied =#=#=#= End test: niceguy: Replace - create attribute (deny) - Insufficient privileges (4) =#=#=#= * Passed: cibadmin - niceguy: Replace - create attribute (deny) - + @@ -1851,7 +1851,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: bob: Replace - create attribute (direct allow) =#=#=#= =#=#=#= End test: bob: Replace - create attribute (direct allow) - OK (0) =#=#=#= * Passed: cibadmin - bob: Replace - create attribute (direct allow) - + @@ -1932,7 +1932,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: bob: Replace - modify attribute (direct allow) =#=#=#= =#=#=#= End test: bob: Replace - modify attribute (direct allow) - OK (0) =#=#=#= * Passed: cibadmin - bob: Replace - modify attribute (direct allow) - + @@ -2009,7 +2009,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: bob: Replace - delete attribute (direct allow) =#=#=#= =#=#=#= End test: bob: Replace - delete attribute (direct allow) - OK (0) =#=#=#= * Passed: cibadmin - bob: Replace - delete attribute (direct allow) - + @@ -2086,7 +2086,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: joe: Replace - create attribute (inherited allow) =#=#=#= =#=#=#= End test: joe: Replace - create attribute (inherited allow) - OK (0) =#=#=#= * Passed: cibadmin - joe: Replace - create attribute (inherited allow) - + @@ -2163,7 +2163,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: joe: Replace - modify attribute (inherited allow) =#=#=#= =#=#=#= End test: joe: Replace - modify attribute (inherited allow) - OK (0) =#=#=#= * Passed: cibadmin - joe: Replace - modify attribute (inherited allow) - + @@ -2240,7 +2240,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: joe: Replace - delete attribute (inherited allow) =#=#=#= =#=#=#= End test: joe: Replace - delete attribute (inherited allow) - OK (0) =#=#=#= * Passed: cibadmin - joe: Replace - delete attribute (inherited allow) - + @@ -2317,7 +2317,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: mike: Replace - create attribute (allow overrides deny) =#=#=#= =#=#=#= End test: mike: Replace - create attribute (allow overrides deny) - OK (0) =#=#=#= * Passed: cibadmin - mike: Replace - create attribute (allow overrides deny) - + @@ -2394,7 +2394,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: mike: Replace - modify attribute (allow overrides deny) =#=#=#= =#=#=#= End test: mike: Replace - modify attribute (allow overrides deny) - OK (0) =#=#=#= * Passed: cibadmin - mike: Replace - modify attribute (allow overrides deny) - + @@ -2471,7 +2471,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: mike: Replace - delete attribute (allow overrides deny) =#=#=#= =#=#=#= End test: mike: Replace - delete attribute (allow overrides deny) - OK (0) =#=#=#= * Passed: cibadmin - mike: Replace - delete attribute (allow overrides deny) - + @@ -2548,7 +2548,7 @@ cibadmin: CIB API call failed: Permission denied =#=#=#= Begin test: mike: Create another resource =#=#=#= pcmk__apply_creation_acl trace: ACLs allow creation of with id="dummy2" =#=#=#= Current cib after: mike: Create another resource =#=#=#= - + @@ -2625,7 +2625,7 @@ pcmk__apply_creation_acl trace: ACLs allow creation of with id="dum =#=#=#= End test: mike: Create another resource - OK (0) =#=#=#= * Passed: cibadmin - mike: Create another resource - + @@ -2705,7 +2705,7 @@ pcmk__check_acl trace: Parent ACL denies user 'chris' read/write access to /cib cibadmin: CIB API call failed: Permission denied =#=#=#= End test: chris: Replace - create attribute (deny overrides allow) - Insufficient privileges (4) =#=#=#= * Passed: cibadmin - chris: Replace - create attribute (deny overrides allow) - + @@ -2785,7 +2785,7 @@ pcmk__check_acl trace: Parent ACL denies user 'chris' read/write access to /cib cibadmin: CIB API call failed: Permission denied =#=#=#= End test: chris: Replace - modify attribute (deny overrides allow) - Insufficient privileges (4) =#=#=#= * Passed: cibadmin - chris: Replace - modify attribute (deny overrides allow) - + diff --git a/cts/cli/regression.cibadmin.exp b/cts/cli/regression.cibadmin.exp index 94d919f082e..0b009a88815 100644 --- a/cts/cli/regression.cibadmin.exp +++ b/cts/cli/regression.cibadmin.exp @@ -1,5 +1,5 @@ =#=#=#= Begin test: Validate CIB =#=#=#= - + @@ -17,7 +17,7 @@ =#=#=#= Current cib after: Validate CIB =#=#=#= - + @@ -38,7 +38,7 @@ * Passed: cibadmin - Validate CIB =#=#=#= Begin test: Validate CIB (XML) =#=#=#= - + @@ -59,7 +59,7 @@ =#=#=#= Current cib after: Validate CIB (XML) =#=#=#= - + @@ -79,12 +79,12 @@ =#=#=#= End test: Validate CIB (XML) - OK (0) =#=#=#= * Passed: cibadmin - Validate CIB (XML) =#=#=#= Begin test: Digest calculation =#=#=#= -9130d6f39c2b83bd032a00e76621508c +1f3492630cde57d6b7ee45de4d390469 =#=#=#= End test: Digest calculation - OK (0) =#=#=#= * Passed: cibadmin - Digest calculation =#=#=#= Begin test: Digest calculation (XML) =#=#=#= - + =#=#=#= End test: Digest calculation (XML) - OK (0) =#=#=#= @@ -92,7 +92,7 @@ =#=#=#= Begin test: Require --force for CIB erasure =#=#=#= cibadmin: The supplied command is considered dangerous. To prevent accidental destruction of the cluster, the --force flag is required in order to proceed. =#=#=#= Current cib after: Require --force for CIB erasure =#=#=#= - + @@ -120,7 +120,7 @@ cibadmin: The supplied command is considered dangerous. To prevent accidental de =#=#=#= Current cib after: Require --force for CIB erasure (XML) =#=#=#= - + @@ -149,7 +149,7 @@ cibadmin: The supplied command is considered dangerous. To prevent accidental de =#=#=#= End test: Allow CIB erasure with --force (XML) - OK (0) =#=#=#= * Passed: cibadmin - Allow CIB erasure with --force (XML) =#=#=#= Begin test: Query CIB =#=#=#= - + @@ -159,7 +159,7 @@ cibadmin: The supplied command is considered dangerous. To prevent accidental de =#=#=#= Current cib after: Query CIB =#=#=#= - + @@ -172,7 +172,7 @@ cibadmin: The supplied command is considered dangerous. To prevent accidental de * Passed: cibadmin - Query CIB =#=#=#= Begin test: Query CIB (XML) =#=#=#= - + @@ -185,7 +185,7 @@ cibadmin: The supplied command is considered dangerous. To prevent accidental de =#=#=#= Current cib after: Query CIB (XML) =#=#=#= - + diff --git a/cts/cli/regression.crm_attribute.exp b/cts/cli/regression.crm_attribute.exp index 882f5da2113..a9e69cec54c 100644 --- a/cts/cli/regression.crm_attribute.exp +++ b/cts/cli/regression.crm_attribute.exp @@ -1067,7 +1067,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: crm_attribute - Query the value of an attribute that does not exist =#=#=#= Begin test: Configure something before erasing =#=#=#= =#=#=#= Current cib after: Configure something before erasing =#=#=#= - + @@ -1084,7 +1084,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: crm_attribute - Configure something before erasing =#=#=#= Begin test: Test '++' XML attribute update syntax =#=#=#= =#=#=#= Current cib after: Test '++' XML attribute update syntax =#=#=#= - + @@ -1101,7 +1101,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: cibadmin - Test '++' XML attribute update syntax =#=#=#= Begin test: Test '+=' XML attribute update syntax =#=#=#= =#=#=#= Current cib after: Test '+=' XML attribute update syntax =#=#=#= - + @@ -1118,7 +1118,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: cibadmin - Test '+=' XML attribute update syntax =#=#=#= Begin test: Test '++' nvpair value update syntax =#=#=#= =#=#=#= Current cib after: Test '++' nvpair value update syntax =#=#=#= - + @@ -1138,7 +1138,7 @@ crm_attribute: Error performing operation: No such device or address =#=#=#= Current cib after: Test '++' nvpair value update syntax (XML) =#=#=#= - + @@ -1155,7 +1155,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: crm_attribute - Test '++' nvpair value update syntax (XML) =#=#=#= Begin test: Test '+=' nvpair value update syntax =#=#=#= =#=#=#= Current cib after: Test '+=' nvpair value update syntax =#=#=#= - + @@ -1175,7 +1175,7 @@ crm_attribute: Error performing operation: No such device or address =#=#=#= Current cib after: Test '+=' nvpair value update syntax (XML) =#=#=#= - + @@ -1192,7 +1192,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: crm_attribute - Test '+=' nvpair value update syntax (XML) =#=#=#= Begin test: Test '++' XML attribute update syntax (--score not set) =#=#=#= =#=#=#= Current cib after: Test '++' XML attribute update syntax (--score not set) =#=#=#= - + @@ -1209,7 +1209,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: cibadmin - Test '++' XML attribute update syntax (--score not set) =#=#=#= Begin test: Test '+=' XML attribute update syntax (--score not set) =#=#=#= =#=#=#= Current cib after: Test '+=' XML attribute update syntax (--score not set) =#=#=#= - + @@ -1226,7 +1226,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: cibadmin - Test '+=' XML attribute update syntax (--score not set) =#=#=#= Begin test: Test '++' nvpair value update syntax (--score not set) =#=#=#= =#=#=#= Current cib after: Test '++' nvpair value update syntax (--score not set) =#=#=#= - + @@ -1246,7 +1246,7 @@ crm_attribute: Error performing operation: No such device or address =#=#=#= Current cib after: Test '++' nvpair value update syntax (--score not set) (XML) =#=#=#= - + @@ -1263,7 +1263,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: crm_attribute - Test '++' nvpair value update syntax (--score not set) (XML) =#=#=#= Begin test: Test '+=' nvpair value update syntax (--score not set) =#=#=#= =#=#=#= Current cib after: Test '+=' nvpair value update syntax (--score not set) =#=#=#= - + @@ -1283,7 +1283,7 @@ crm_attribute: Error performing operation: No such device or address =#=#=#= Current cib after: Test '+=' nvpair value update syntax (--score not set) (XML) =#=#=#= - + @@ -1300,7 +1300,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: crm_attribute - Test '+=' nvpair value update syntax (--score not set) (XML) =#=#=#= Begin test: Set cluster option =#=#=#= =#=#=#= Current cib after: Set cluster option =#=#=#= - + @@ -1321,7 +1321,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: cibadmin - Query new cluster option =#=#=#= Begin test: Set no-quorum policy =#=#=#= =#=#=#= Current cib after: Set no-quorum policy =#=#=#= - + @@ -1339,7 +1339,7 @@ crm_attribute: Error performing operation: No such device or address * Passed: crm_attribute - Set no-quorum policy =#=#=#= Begin test: Delete nvpair =#=#=#= =#=#=#= Current cib after: Delete nvpair =#=#=#= - + @@ -1364,7 +1364,7 @@ cibadmin: CIB API call failed: File exists =#=#=#= Current cib after: Create operation should fail =#=#=#= - + @@ -1381,7 +1381,7 @@ cibadmin: CIB API call failed: File exists * Passed: cibadmin - Create operation should fail =#=#=#= Begin test: Modify cluster options section =#=#=#= =#=#=#= Current cib after: Modify cluster options section =#=#=#= - + @@ -1400,7 +1400,7 @@ cibadmin: CIB API call failed: File exists =#=#=#= Begin test: Query updated cluster option =#=#=#= =#=#=#= Current cib after: Query updated cluster option =#=#=#= - + @@ -1418,7 +1418,7 @@ cibadmin: CIB API call failed: File exists * Passed: cibadmin - Query updated cluster option =#=#=#= Begin test: Set duplicate cluster option =#=#=#= =#=#=#= Current cib after: Set duplicate cluster option =#=#=#= - + @@ -1443,7 +1443,7 @@ Multiple attributes match name=cluster-delay Value: 60s (id=cib-bootstrap-options-cluster-delay) Value: 40s (id=duplicate-cluster-delay) =#=#=#= Current cib after: Setting multiply defined cluster option should fail =#=#=#= - + @@ -1464,7 +1464,7 @@ Multiple attributes match name=cluster-delay * Passed: crm_attribute - Setting multiply defined cluster option should fail =#=#=#= Begin test: Set cluster option with -s =#=#=#= =#=#=#= Current cib after: Set cluster option with -s =#=#=#= - + @@ -1486,7 +1486,7 @@ Multiple attributes match name=cluster-delay =#=#=#= Begin test: Delete cluster option with -i =#=#=#= Deleted crm_config option: id=(null) name=cluster-delay =#=#=#= Current cib after: Delete cluster option with -i =#=#=#= - + @@ -1526,7 +1526,7 @@ Revised Cluster Status: * Full List of Resources: * No resources =#=#=#= Current cib after: Create node1 and bring it online =#=#=#= - + @@ -1550,7 +1550,7 @@ Revised Cluster Status: * Passed: crm_simulate - Create node1 and bring it online =#=#=#= Begin test: Create node attribute =#=#=#= =#=#=#= Current cib after: Create node attribute =#=#=#= - + @@ -1579,7 +1579,7 @@ Revised Cluster Status: =#=#=#= Begin test: Query new node attribute =#=#=#= =#=#=#= Current cib after: Query new node attribute =#=#=#= - + @@ -1607,7 +1607,7 @@ Revised Cluster Status: * Passed: cibadmin - Query new node attribute =#=#=#= Begin test: Create second node attribute =#=#=#= =#=#=#= Current cib after: Create second node attribute =#=#=#= - + @@ -1641,7 +1641,7 @@ scope=nodes name=rattr value=XYZ * Passed: crm_attribute - Query node attributes by pattern =#=#=#= Begin test: Update node attributes by pattern =#=#=#= =#=#=#= Current cib after: Update node attributes by pattern =#=#=#= - + @@ -1671,7 +1671,7 @@ scope=nodes name=rattr value=XYZ =#=#=#= Begin test: Delete node attributes by pattern =#=#=#= Deleted nodes attribute: id=nodes-node1-rattr name=rattr =#=#=#= Current cib after: Delete node attributes by pattern =#=#=#= - + @@ -1699,7 +1699,7 @@ Deleted nodes attribute: id=nodes-node1-rattr name=rattr * Passed: crm_attribute - Delete node attributes by pattern =#=#=#= Begin test: Set a transient (fail-count) node attribute =#=#=#= =#=#=#= Current cib after: Set a transient (fail-count) node attribute =#=#=#= - + @@ -1734,7 +1734,7 @@ Deleted nodes attribute: id=nodes-node1-rattr name=rattr =#=#=#= Begin test: Query a fail count =#=#=#= scope=status name=fail-count-foo value=3 =#=#=#= Current cib after: Query a fail count =#=#=#= - + @@ -1782,7 +1782,7 @@ Current cluster status: * Passed: crm_simulate - Show node attributes with crm_simulate =#=#=#= Begin test: Set a second transient node attribute =#=#=#= =#=#=#= Current cib after: Set a second transient node attribute =#=#=#= - + @@ -1822,7 +1822,7 @@ scope=status name=fail-count-bar value=5 * Passed: crm_attribute - Query transient node attributes by pattern =#=#=#= Begin test: Update transient node attributes by pattern =#=#=#= =#=#=#= Current cib after: Update transient node attributes by pattern =#=#=#= - + @@ -1859,7 +1859,7 @@ scope=status name=fail-count-bar value=5 Deleted status attribute: id=status-node1-fail-count-foo name=fail-count-foo Deleted status attribute: id=status-node1-fail-count-bar name=fail-count-bar =#=#=#= Current cib after: Delete transient node attributes by pattern =#=#=#= - + @@ -1895,7 +1895,7 @@ crm_attribute: Error: must specify attribute name or pattern to delete * Passed: crm_attribute - crm_attribute given invalid delete usage =#=#=#= Begin test: Set a utilization node attribute =#=#=#= =#=#=#= Current cib after: Set a utilization node attribute =#=#=#= - + diff --git a/cts/cli/regression.crm_resource.exp b/cts/cli/regression.crm_resource.exp index 394d5b933a8..1b8f728f653 100644 --- a/cts/cli/regression.crm_resource.exp +++ b/cts/cli/regression.crm_resource.exp @@ -824,7 +824,7 @@ Special parameters that are available for all fencing resources, regardless of t * Passed: crm_resource - List all available fencing parameters (XML) =#=#=#= Begin test: Create a resource =#=#=#= =#=#=#= Current cib after: Create a resource =#=#=#= - + @@ -857,7 +857,7 @@ crm_resource: --class, --agent, and --provider can only be used with --validate unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Set 'dummy' option: id=dummy-meta_attributes-is-managed set=dummy-meta_attributes name=is-managed value=false =#=#=#= Current cib after: Create a resource meta attribute =#=#=#= - + @@ -886,7 +886,7 @@ Set 'dummy' option: id=dummy-meta_attributes-is-managed set=dummy-meta_attribute unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. false =#=#=#= Current cib after: Query a resource meta attribute =#=#=#= - + @@ -915,7 +915,7 @@ false unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Deleted 'dummy' option: id=dummy-meta_attributes-is-managed name=is-managed =#=#=#= Current cib after: Remove a resource meta attribute =#=#=#= - + @@ -984,7 +984,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Attribute 'nonexistent' not found for 'dummy' =#=#=#= Current cib after: Get a non-existent attribute from a resource element =#=#=#= - + @@ -1017,7 +1017,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h =#=#=#= Current cib after: Get a non-existent attribute from a resource element (XML) =#=#=#= - + @@ -1044,7 +1044,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. ocf =#=#=#= Current cib after: Get an existent attribute from a resource element =#=#=#= - + @@ -1073,7 +1073,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h =#=#=#= Current cib after: Set a non-existent attribute for a resource element (XML) =#=#=#= - + @@ -1102,7 +1102,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h =#=#=#= Current cib after: Set an existent attribute for a resource element (XML) =#=#=#= - + @@ -1131,7 +1131,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h =#=#=#= Current cib after: Delete an existent attribute for a resource element (XML) =#=#=#= - + @@ -1160,7 +1160,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h =#=#=#= Current cib after: Delete a non-existent attribute for a resource element (XML) =#=#=#= - + @@ -1187,7 +1187,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Set attribute: name=description value=test_description =#=#=#= Current cib after: Set a non-existent attribute for a resource element =#=#=#= - + @@ -1214,7 +1214,7 @@ Set attribute: name=description value=test_description unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Set attribute: name=description value=test_description =#=#=#= Current cib after: Set an existent attribute for a resource element =#=#=#= - + @@ -1241,7 +1241,7 @@ Set attribute: name=description value=test_description unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Deleted attribute: description =#=#=#= Current cib after: Delete an existent attribute for a resource element =#=#=#= - + @@ -1268,7 +1268,7 @@ Deleted attribute: description unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Deleted attribute: description =#=#=#= Current cib after: Delete a non-existent attribute for a resource element =#=#=#= - + @@ -1295,7 +1295,7 @@ Deleted attribute: description unpack_resources error: Resource start-up disabled since no fencing resources have been defined. Either configure some or disable fencing with the fencing-enabled option. NOTE: Clusters with shared data need fencing to ensure data integrity. Set 'dummy' option: id=dummy-instance_attributes-delay set=dummy-instance_attributes name=delay value=10s =#=#=#= Current cib after: Create a resource attribute =#=#=#= - + @@ -1326,7 +1326,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h Full List of Resources: * dummy (ocf:pacemaker:Dummy): Stopped =#=#=#= Current cib after: List the configured resources =#=#=#= - + @@ -1361,7 +1361,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h =#=#=#= Current cib after: List the configured resources (XML) =#=#=#= - + @@ -1432,7 +1432,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h crm_resource: Resource 'dummy' not moved: active in 0 locations. To prevent 'dummy' from running on a specific location, specify a node. =#=#=#= Current cib after: Require a destination when migrating a resource that is stopped =#=#=#= - + @@ -1463,7 +1463,7 @@ unpack_resources error: Resource start-up disabled since no fencing resources h crm_resource: Node 'i.do.not.exist' not found Error performing operation: No such object =#=#=#= Current cib after: Don't support migration to non-existent locations =#=#=#= - + @@ -1491,7 +1491,7 @@ Error performing operation: No such object * Passed: crm_resource - Don't support migration to non-existent locations =#=#=#= Begin test: Create a fencing resource =#=#=#= =#=#=#= Current cib after: Create a fencing resource =#=#=#= - + @@ -1545,7 +1545,7 @@ Revised Cluster Status: * dummy (ocf:pacemaker:Dummy): Started node1 * Fence (stonith:fence_true): Started node1 =#=#=#= Current cib after: Bring resources online =#=#=#= - + @@ -1586,7 +1586,7 @@ Revised Cluster Status: =#=#=#= Begin test: Try to move a resource to its existing location =#=#=#= crm_resource: Error performing operation: Requested item already exists =#=#=#= Current cib after: Try to move a resource to its existing location =#=#=#= - + @@ -1634,7 +1634,7 @@ WARNING: Creating rsc_location constraint 'cli-ban-dummy-on-node1' with a score This will prevent dummy from running on node1 until the constraint is removed using the clear option or by editing the CIB with an appropriate tool. This will be the case even if node1 is the last node in the cluster =#=#=#= Current cib after: Move a resource from its existing location =#=#=#= - + @@ -1677,7 +1677,7 @@ WARNING: Creating rsc_location constraint 'cli-ban-dummy-on-node1' with a score =#=#=#= Begin test: Clear out constraints generated by --move =#=#=#= Removing constraint: cli-ban-dummy-on-node1 =#=#=#= Current cib after: Clear out constraints generated by --move =#=#=#= - + @@ -1752,7 +1752,7 @@ Revised Cluster Status: * dummy (ocf:pacemaker:Dummy): Started node1 * Fence (stonith:fence_true): Started node2 =#=#=#= Current cib after: Create two more nodes and bring them online =#=#=#= - + @@ -1821,7 +1821,7 @@ WARNING: Creating rsc_location constraint 'cli-ban-dummy-on-node1' with a score This will prevent dummy from running on node1 until the constraint is removed using the clear option or by editing the CIB with an appropriate tool. This will be the case even if node1 is the last node in the cluster =#=#=#= Current cib after: Ban dummy from node1 =#=#=#= - + @@ -1901,7 +1901,7 @@ Locations: =#=#=#= Current cib after: Ban dummy from node2 (XML) =#=#=#= - + @@ -1992,7 +1992,7 @@ Revised Cluster Status: * dummy (ocf:pacemaker:Dummy): Started node3 * Fence (stonith:fence_true): Started node2 =#=#=#= Current cib after: Relocate resources due to ban =#=#=#= - + @@ -2064,7 +2064,7 @@ Revised Cluster Status: =#=#=#= Current cib after: Move dummy to node1 (XML) =#=#=#= - + @@ -2134,7 +2134,7 @@ Revised Cluster Status: =#=#=#= Begin test: Clear implicit constraints for dummy on node2 =#=#=#= Removing constraint: cli-ban-dummy-on-node2 =#=#=#= Current cib after: Clear implicit constraints for dummy on node2 =#=#=#= - + @@ -2210,7 +2210,7 @@ Removing constraint: cli-ban-dummy-on-node2 Performing update of 'is-managed' on 'test-clone', the parent of 'test-primitive' Set 'test-clone' option: id=test-clone-meta_attributes-is-managed set=test-clone-meta_attributes name=is-managed value=false =#=#=#= Current cib after: Create a resource meta attribute =#=#=#= - + @@ -2248,7 +2248,7 @@ Set 'test-clone' option: id=test-clone-meta_attributes-is-managed set=test-clone =#=#=#= Begin test: Create a resource meta attribute in the primitive =#=#=#= Set 'test-primitive' option: id=test-primitive-meta_attributes-is-managed set=test-primitive-meta_attributes name=is-managed value=false =#=#=#= Current cib after: Create a resource meta attribute in the primitive =#=#=#= - + @@ -2295,7 +2295,7 @@ Multiple attributes match name=is-managed A value for 'is-managed' already exists in child 'test-primitive', performing update on that instead of 'test-clone' Set 'test-primitive' option: id=test-primitive-meta_attributes-is-managed name=is-managed value=true =#=#=#= Current cib after: Update resource meta attribute with duplicates =#=#=#= - + @@ -2337,7 +2337,7 @@ Set 'test-primitive' option: id=test-primitive-meta_attributes-is-managed name=i =#=#=#= Begin test: Update resource meta attribute with duplicates (force clone) =#=#=#= Set 'test-clone' option: id=test-clone-meta_attributes-is-managed name=is-managed value=true =#=#=#= Current cib after: Update resource meta attribute with duplicates (force clone) =#=#=#= - + @@ -2383,7 +2383,7 @@ Multiple attributes match name=is-managed Set 'test-primitive' option: id=test-primitive-meta_attributes-is-managed name=is-managed value=false =#=#=#= Current cib after: Update child resource meta attribute with duplicates =#=#=#= - + @@ -2430,7 +2430,7 @@ Multiple attributes match name=is-managed A value for 'is-managed' already exists in child 'test-primitive', performing delete on that instead of 'test-clone' Deleted 'test-primitive' option: id=test-primitive-meta_attributes-is-managed name=is-managed =#=#=#= Current cib after: Delete resource meta attribute with duplicates =#=#=#= - + @@ -2471,7 +2471,7 @@ Deleted 'test-primitive' option: id=test-primitive-meta_attributes-is-managed na Performing delete of 'is-managed' on 'test-clone', the parent of 'test-primitive' Deleted 'test-clone' option: id=test-clone-meta_attributes-is-managed name=is-managed =#=#=#= Current cib after: Delete resource meta attribute in parent =#=#=#= - + @@ -2509,7 +2509,7 @@ Deleted 'test-clone' option: id=test-clone-meta_attributes-is-managed name=is-ma =#=#=#= Begin test: Create a resource meta attribute in the primitive =#=#=#= Set 'test-primitive' option: id=test-primitive-meta_attributes-is-managed set=test-primitive-meta_attributes name=is-managed value=false =#=#=#= Current cib after: Create a resource meta attribute in the primitive =#=#=#= - + @@ -2550,7 +2550,7 @@ Set 'test-primitive' option: id=test-primitive-meta_attributes-is-managed set=te A value for 'is-managed' already exists in child 'test-primitive', performing update on that instead of 'test-clone' Set 'test-primitive' option: id=test-primitive-meta_attributes-is-managed name=is-managed value=true =#=#=#= Current cib after: Update existing resource meta attribute =#=#=#= - + @@ -2590,7 +2590,7 @@ Set 'test-primitive' option: id=test-primitive-meta_attributes-is-managed name=i =#=#=#= Begin test: Create a resource meta attribute in the parent =#=#=#= Set 'test-clone' option: id=test-clone-meta_attributes-is-managed set=test-clone-meta_attributes name=is-managed value=true =#=#=#= Current cib after: Create a resource meta attribute in the parent =#=#=#= - + @@ -2632,7 +2632,7 @@ Set 'test-clone' option: id=test-clone-meta_attributes-is-managed set=test-clone =#=#=#= Begin test: Delete resource parent meta attribute (force) =#=#=#= Deleted 'test-clone' option: id=test-clone-meta_attributes-is-managed name=is-managed =#=#=#= Current cib after: Delete resource parent meta attribute (force) =#=#=#= - + @@ -2676,7 +2676,7 @@ Multiple attributes match name=is-managed Deleted 'test-primitive' option: id=test-primitive-meta_attributes-is-managed name=is-managed =#=#=#= Current cib after: Delete resource child meta attribute =#=#=#= - + @@ -2715,7 +2715,7 @@ Deleted 'test-primitive' option: id=test-primitive-meta_attributes-is-managed na * Passed: crm_resource - Delete resource child meta attribute =#=#=#= Begin test: Create the dummy-group resource group =#=#=#= =#=#=#= Current cib after: Create the dummy-group resource group =#=#=#= - + @@ -2759,7 +2759,7 @@ Deleted 'test-primitive' option: id=test-primitive-meta_attributes-is-managed na =#=#=#= Begin test: Create a resource meta attribute in dummy1 =#=#=#= Set 'dummy1' option: id=dummy1-meta_attributes-is-managed set=dummy1-meta_attributes name=is-managed value=true =#=#=#= Current cib after: Create a resource meta attribute in dummy1 =#=#=#= - + @@ -2808,7 +2808,7 @@ Set 'dummy1' option: id=dummy1-meta_attributes-is-managed set=dummy1-meta_attrib Set 'dummy1' option: id=dummy1-meta_attributes-is-managed name=is-managed value=false Set 'dummy-group' option: id=dummy-group-meta_attributes-is-managed set=dummy-group-meta_attributes name=is-managed value=false =#=#=#= Current cib after: Create a resource meta attribute in dummy-group =#=#=#= - + @@ -2858,7 +2858,7 @@ Set 'dummy-group' option: id=dummy-group-meta_attributes-is-managed set=dummy-gr * Passed: crm_resource - Create a resource meta attribute in dummy-group =#=#=#= Begin test: Delete the dummy-group resource group =#=#=#= =#=#=#= Current cib after: Delete the dummy-group resource group =#=#=#= - + @@ -2898,7 +2898,7 @@ Set 'dummy-group' option: id=dummy-group-meta_attributes-is-managed set=dummy-gr =#=#=#= Begin test: Specify a lifetime when moving a resource =#=#=#= Migration will take effect until: =#=#=#= Current cib after: Specify a lifetime when moving a resource =#=#=#= - + @@ -2942,7 +2942,7 @@ Migration will take effect until: * Passed: crm_resource - Specify a lifetime when moving a resource =#=#=#= Begin test: Try to move a resource previously moved with a lifetime =#=#=#= =#=#=#= Current cib after: Try to move a resource previously moved with a lifetime =#=#=#= - + @@ -2985,7 +2985,7 @@ WARNING: Creating rsc_location constraint 'cli-ban-dummy-on-node1' with a score This will prevent dummy from running on node1 until the constraint is removed using the clear option or by editing the CIB with an appropriate tool. This will be the case even if node1 is the last node in the cluster =#=#=#= Current cib after: Ban dummy from node1 for a short time =#=#=#= - + @@ -3031,7 +3031,7 @@ WARNING: Creating rsc_location constraint 'cli-ban-dummy-on-node1' with a score =#=#=#= Begin test: Remove expired constraints =#=#=#= Removing constraint: cli-ban-dummy-on-node1 =#=#=#= Current cib after: Remove expired constraints =#=#=#= - + @@ -3071,7 +3071,7 @@ Removing constraint: cli-ban-dummy-on-node1 =#=#=#= Begin test: Clear all implicit constraints for dummy =#=#=#= Removing constraint: cli-prefer-dummy =#=#=#= Current cib after: Clear all implicit constraints for dummy =#=#=#= - + @@ -3108,7 +3108,7 @@ Removing constraint: cli-prefer-dummy * Passed: crm_resource - Clear all implicit constraints for dummy =#=#=#= Begin test: Set a node health strategy =#=#=#= =#=#=#= Current cib after: Set a node health strategy =#=#=#= - + @@ -3146,7 +3146,7 @@ Removing constraint: cli-prefer-dummy * Passed: crm_attribute - Set a node health strategy =#=#=#= Begin test: Set a node health attribute =#=#=#= =#=#=#= Current cib after: Set a node health attribute =#=#=#= - + @@ -3197,7 +3197,7 @@ Removing constraint: cli-prefer-dummy * Passed: crm_resource - Show why a resource is not running on an unhealthy node (XML) =#=#=#= Begin test: Delete a resource =#=#=#= =#=#=#= Current cib after: Delete a resource =#=#=#= - + diff --git a/cts/cli/regression.crm_shadow.exp b/cts/cli/regression.crm_shadow.exp index f8a733743db..bccf28bdb13 100644 --- a/cts/cli/regression.crm_shadow.exp +++ b/cts/cli/regression.crm_shadow.exp @@ -1322,7 +1322,7 @@ A new shadow instance was created. To begin using it, enter the following into y =#=#=#= End test: Create empty shadow instance (file already exists) (force) (XML) - OK (0) =#=#=#= * Passed: crm_shadow - Create empty shadow instance (file already exists) (force) (XML) =#=#=#= Begin test: Get active shadow instance's contents (empty CIB) =#=#=#= - + @@ -1336,7 +1336,7 @@ A new shadow instance was created. To begin using it, enter the following into y =#=#=#= Begin test: Get active shadow instance's contents (empty CIB) (XML) =#=#=#= - + @@ -1374,7 +1374,7 @@ Diff: +++ 0.1.0 (null) -- /cib/status/node_state[@id='1'] -- /cib/status/node_state[@id='httpd-bundle-0'] -- /cib/status/node_state[@id='httpd-bundle-1'] -+ /cib: @validate-with=pacemaker-X, @num_updates=0, @admin_epoch=0 ++ /cib: @validate-with=pacemaker-X, @admin_epoch=0, @epoch=1, @num_updates=0 -- /cib: @cib-last-written, @update-origin, @update-client, @update-user, @have-quorum, @dc-uuid =#=#=#= End test: Get active shadow instance's diff (empty CIB) - Error occurred (1) =#=#=#= * Passed: crm_shadow - Get active shadow instance's diff (empty CIB) @@ -1410,8 +1410,9 @@ Diff: +++ 0.1.0 (null) - + + @@ -1420,7 +1421,7 @@ Diff: +++ 0.1.0 (null) - + diff --git a/cts/cli/regression.crm_standby.exp b/cts/cli/regression.crm_standby.exp index ef406bb72be..5dce954c75d 100644 --- a/cts/cli/regression.crm_standby.exp +++ b/cts/cli/regression.crm_standby.exp @@ -4,7 +4,7 @@ scope=status name=standby value=off * Passed: crm_standby - Default standby value =#=#=#= Begin test: Set standby status =#=#=#= =#=#=#= Current cib after: Set standby status =#=#=#= - + @@ -28,7 +28,7 @@ scope=nodes name=standby value=true =#=#=#= Begin test: Delete standby value =#=#=#= Deleted nodes attribute: id=nodes-node1-standby name=standby =#=#=#= Current cib after: Delete standby value =#=#=#= - + diff --git a/cts/cli/regression.crm_ticket.exp b/cts/cli/regression.crm_ticket.exp index afb8be30794..1a30cb97190 100644 --- a/cts/cli/regression.crm_ticket.exp +++ b/cts/cli/regression.crm_ticket.exp @@ -4,7 +4,7 @@ false * Passed: crm_ticket - Default ticket granted state =#=#=#= Begin test: Set ticket granted state =#=#=#= =#=#=#= Current cib after: Set ticket granted state =#=#=#= - + @@ -70,7 +70,7 @@ false * Passed: crm_ticket - Query ticket granted state (XML) =#=#=#= Begin test: Delete ticket granted state =#=#=#= =#=#=#= Current cib after: Delete ticket granted state =#=#=#= - + @@ -93,7 +93,7 @@ false * Passed: crm_ticket - Delete ticket granted state =#=#=#= Begin test: Make a ticket standby =#=#=#= =#=#=#= Current cib after: Make a ticket standby =#=#=#= - + @@ -120,7 +120,7 @@ true * Passed: crm_ticket - Query ticket standby state =#=#=#= Begin test: Activate a ticket =#=#=#= =#=#=#= Current cib after: Activate a ticket =#=#=#= - + @@ -157,7 +157,7 @@ ticketA revoked (standby=false) =#=#=#= Begin test: Add a second ticket =#=#=#= false =#=#=#= Current cib after: Add a second ticket =#=#=#= - + @@ -180,7 +180,7 @@ false * Passed: crm_ticket - Add a second ticket =#=#=#= Begin test: Set second ticket granted state =#=#=#= =#=#=#= Current cib after: Set second ticket granted state =#=#=#= - + @@ -219,7 +219,7 @@ ticketB revoked * Passed: crm_ticket - List tickets (XML) =#=#=#= Begin test: Delete second ticket =#=#=#= =#=#=#= Current cib after: Delete second ticket =#=#=#= - + @@ -242,7 +242,7 @@ ticketB revoked * Passed: cibadmin - Delete second ticket =#=#=#= Begin test: Delete ticket standby state =#=#=#= =#=#=#= Current cib after: Delete ticket standby state =#=#=#= - + @@ -265,7 +265,7 @@ ticketB revoked * Passed: crm_ticket - Delete ticket standby state =#=#=#= Begin test: Add a constraint to a ticket =#=#=#= =#=#=#= Current cib after: Add a constraint to a ticket =#=#=#= - + @@ -312,7 +312,7 @@ Constraints XML: * Passed: crm_ticket - Query ticket constraints (XML) =#=#=#= Begin test: Delete ticket constraint =#=#=#= =#=#=#= Current cib after: Delete ticket constraint =#=#=#= - + diff --git a/cts/cli/regression.upgrade.exp b/cts/cli/regression.upgrade.exp index b4e69f6195a..3f3455a8e82 100644 --- a/cts/cli/regression.upgrade.exp +++ b/cts/cli/regression.upgrade.exp @@ -1,6 +1,6 @@ =#=#=#= Begin test: Set fencing-enabled=false =#=#=#= =#=#=#= Current cib after: Set fencing-enabled=false =#=#=#= - + @@ -17,7 +17,7 @@ * Passed: crm_attribute - Set fencing-enabled=false =#=#=#= Begin test: Configure the initial resource =#=#=#= =#=#=#= Current cib after: Configure the initial resource =#=#=#= - + @@ -78,7 +78,7 @@ pcmk__update_schema debug: Schema pacemaker-3.10 validates pcmk__update_schema debug: Schema pacemaker-4.0 validates pcmk__update_schema info: Transformed the configuration schema to pacemaker-4.0 =#=#=#= Current cib after: Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping) =#=#=#= - + @@ -111,7 +111,7 @@ pcmk__update_schema info: Transformed the configuration schema to pacemaker-4.0 =#=#=#= Begin test: Query a resource instance attribute (shall survive) =#=#=#= outputpower =#=#=#= Current cib after: Query a resource instance attribute (shall survive) =#=#=#= - + diff --git a/cts/cli/regression.validity.exp b/cts/cli/regression.validity.exp index 03b61cee5b3..fd566608b3f 100644 --- a/cts/cli/regression.validity.exp +++ b/cts/cli/regression.validity.exp @@ -9,7 +9,7 @@ cibadmin: CIB API call failed: Update does not conform to the configured schema =#=#=#= Begin test: Try to use rsc_order first-action value disallowed by schema =#=#=#= cibadmin: CIB API call failed: Update does not conform to the configured schema =#=#=#= Current cib after: Try to use rsc_order first-action value disallowed by schema =#=#=#= - + @@ -28,7 +28,7 @@ cibadmin: CIB API call failed: Update does not conform to the configured schema =#=#=#= Begin test: Try to use configuration legal only with schema after configured one =#=#=#= cibadmin: CIB API call failed: Update does not conform to the configured schema =#=#=#= Current cib after: Try to use configuration legal only with schema after configured one =#=#=#= - + @@ -49,7 +49,7 @@ cibadmin: CIB API call failed: Update does not conform to the configured schema * Passed: cibadmin - Disable schema validation =#=#=#= Begin test: Set invalid rsc_order first-action value (schema validation disabled) =#=#=#= =#=#=#= Current cib after: Set invalid rsc_order first-action value (schema validation disabled) =#=#=#= - + diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 624bab190bd..ea272ff1f0f 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -100,9 +100,9 @@ createEmptyCib(int cib_epoch) pcmk__xe_set(cib_root, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET); pcmk__xe_set(cib_root, PCMK_XA_VALIDATE_WITH, pcmk__highest_schema_name()); + pcmk__xe_set_int(cib_root, PCMK_XA_ADMIN_EPOCH, 0); pcmk__xe_set_int(cib_root, PCMK_XA_EPOCH, cib_epoch); pcmk__xe_set_int(cib_root, PCMK_XA_NUM_UPDATES, 0); - pcmk__xe_set_int(cib_root, PCMK_XA_ADMIN_EPOCH, 0); config = pcmk__xe_create(cib_root, PCMK_XE_CONFIGURATION); pcmk__xe_create(cib_root, PCMK_XE_STATUS); From a10420bbe35d26896fa964cf012b95fa1c15da70 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 2 Jan 2026 02:34:47 -0800 Subject: [PATCH 03/41] Refactor: libcrmcommon: New pcmk__xml_replace_with_copy() This exposes a previously static function. Nothing else calls it yet. Signed-off-by: Reid Wahl --- include/crm/common/xml_internal.h | 1 + lib/common/xml.c | 45 +++++++++++++++++++++++++++++++ lib/common/xml_element.c | 34 +---------------------- 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h index eed9c6fc837..8fd2148354d 100644 --- a/include/crm/common/xml_internal.h +++ b/include/crm/common/xml_internal.h @@ -326,6 +326,7 @@ pcmk__xml_next(const xmlNode *child) void pcmk__xml_free(xmlNode *xml); void pcmk__xml_free_doc(xmlDoc *doc); xmlNode *pcmk__xml_copy(xmlNode *parent, xmlNode *src); +xmlNode *pcmk__xml_replace_with_copy(xmlNode *old, xmlNode *new); /*! * \internal diff --git a/lib/common/xml.c b/lib/common/xml.c index 5b34ba2fe5a..4f3c7897f26 100644 --- a/lib/common/xml.c +++ b/lib/common/xml.c @@ -856,6 +856,51 @@ pcmk__xml_copy(xmlNode *parent, xmlNode *src) return copy; } +/*! + * \internal + * \brief Replace one XML node with a copy of another XML node + * + * This function handles change tracking and applies ACLs. + * + * \param[in,out] old XML node to replace + * \param[in] new XML node to copy as replacement for \p old + * + * \return Copy of \p new that replaced \p old + * + * \note This frees \p old. + * \note The caller is responsible for freeing the return value using + * \c pcmk__xml_free() (but note that it may be part of a larger XML + * tree). + */ +xmlNode * +pcmk__xml_replace_with_copy(xmlNode *old, xmlNode *new) +{ + xmlNode *new_copy = NULL; + + pcmk__assert((old != NULL) && (new != NULL)); + + /* Pass old to pcmk__xml_copy() so that new_copy gets created within the + * same doc. But old won't remain its parent. + */ + new_copy = pcmk__xml_copy(old, new); + old = xmlReplaceNode(old, new_copy); + + // old == NULL means memory allocation error + pcmk__assert(old != NULL); + + // May be unnecessary but avoids slight changes to some test outputs + pcmk__xml_tree_foreach(new_copy, pcmk__xml_reset_node_flags, NULL); + + if (pcmk__xml_doc_all_flags_set(new_copy->doc, pcmk__xf_tracking)) { + // Replaced sections may have included relevant ACLs + pcmk__apply_acls(new_copy->doc); + } + pcmk__xml_mark_changes(old, new_copy); + pcmk__xml_free_node(old); + + return new_copy; +} + /*! * \internal * \brief Remove XML text nodes from specified XML and all its children diff --git a/lib/common/xml_element.c b/lib/common/xml_element.c index 106ac6f1de1..5e7b5aa97c1 100644 --- a/lib/common/xml_element.c +++ b/lib/common/xml_element.c @@ -732,38 +732,6 @@ pcmk__xe_delete_match(xmlNode *xml, xmlNode *search) return ENXIO; } -/*! - * \internal - * \brief Replace one XML node with a copy of another XML node - * - * This function handles change tracking and applies ACLs. - * - * \param[in,out] old XML node to replace - * \param[in] new XML node to copy as replacement for \p old - * - * \note This frees \p old. - */ -static void -replace_node(xmlNode *old, xmlNode *new) -{ - // Pass old for its doc; it won't remain the parent of new - new = pcmk__xml_copy(old, new); - old = xmlReplaceNode(old, new); - - // old == NULL means memory allocation error - pcmk__assert(old != NULL); - - // May be unnecessary but avoids slight changes to some test outputs - pcmk__xml_tree_foreach(new, pcmk__xml_reset_node_flags, NULL); - - if (pcmk__xml_doc_all_flags_set(new->doc, pcmk__xf_tracking)) { - // Replaced sections may have included relevant ACLs - pcmk__apply_acls(new->doc); - } - pcmk__xml_mark_changes(old, new); - pcmk__xml_free_node(old); -} - /*! * \internal * \brief Replace one XML subtree with a copy of another if the two match @@ -805,7 +773,7 @@ replace_xe_if_matching(xmlNode *xml, void *user_data) pcmk__log_xml_trace(xml, "replace-match"); pcmk__log_xml_trace(replace, "replace-with"); - replace_node(xml, replace); + pcmk__xml_replace_with_copy(xml, replace); // Found a match and replaced it; stop traversing tree return false; From 97164e6e9a119cda0cacb6e15f763ed87040a7c2 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 2 Jan 2026 02:27:57 -0800 Subject: [PATCH 04/41] Refactor: libcib: Replace CIB with a copy of input in same doc This avoids freeing the XML document to which *cib belonged, thus preserving document private data. Signed-off-by: Reid Wahl --- lib/cib/cib_ops.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c index 143d2b5f428..1b2f88af828 100644 --- a/lib/cib/cib_ops.c +++ b/lib/cib/cib_ops.c @@ -868,13 +868,11 @@ replace_cib(xmlNode *request, xmlNode *input, xmlNode **result_cib) return pcmk_rc_old_data; } + *result_cib = pcmk__xml_replace_with_copy(*result_cib, input); + pcmk__info("Replaced %d.%d.%d with %d.%d.%d from %s", admin_epoch, epoch, updates, replace_admin_epoch, replace_epoch, replace_updates, peer); - - pcmk__xml_free(*result_cib); - *result_cib = pcmk__xml_copy(NULL, input); - return pcmk_rc_ok; } From 1802cc93f4bb9fda9afd9d6e8c6758a7f6bc1a53 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 29 Jan 2026 14:06:53 -0800 Subject: [PATCH 05/41] Refactor: libcib: Use result_cib in cib__process_query() This was the only remaining cib__op_fn_t that used existing_cib in a non-trivial way. However, cib__perform_query() ensures that existing_cib is equal to *result_cib. So we can just use *result_cib. An upcoming commit will merge these two cib arguments. Signed-off-by: Reid Wahl --- lib/cib/cib_ops.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c index 1b2f88af828..811feb7267a 100644 --- a/lib/cib/cib_ops.c +++ b/lib/cib/cib_ops.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -615,11 +615,11 @@ cib__process_modify(const char *op, int options, const char *section, static int process_query_xpath(const char *op, int options, const char *xpath, - xmlNode *existing_cib, xmlNode **answer) + xmlNode *cib, xmlNode **answer) { int num_results = 0; int rc = pcmk_rc_ok; - xmlXPathObject *xpath_obj = pcmk__xpath_search(existing_cib->doc, xpath); + xmlXPathObject *xpath_obj = pcmk__xpath_search(cib->doc, xpath); num_results = pcmk__xpath_num_results(xpath_obj); if (num_results == 0) { @@ -706,7 +706,7 @@ process_query_xpath(const char *op, int options, const char *xpath, } static int -process_query_section(int options, const char *section, xmlNode *existing_cib, +process_query_section(int options, const char *section, xmlNode *cib, xmlNode **answer) { xmlNode *obj_root = NULL; @@ -715,7 +715,7 @@ process_query_section(int options, const char *section, xmlNode *existing_cib, section = NULL; } - obj_root = pcmk_find_cib_element(existing_cib, section); + obj_root = pcmk_find_cib_element(cib, section); if (obj_root == NULL) { return ENXIO; } @@ -741,10 +741,10 @@ cib__process_query(const char *op, int options, const char *section, xmlNode **result_cib, xmlNode **answer) { if (pcmk__is_set(options, cib_xpath)) { - return process_query_xpath(op, options, section, existing_cib, answer); + return process_query_xpath(op, options, section, *result_cib, answer); } - return process_query_section(options, section, existing_cib, answer); + return process_query_section(options, section, *result_cib, answer); } static int From ea25071934ff81b987ebdbc3b7076ff9835c6e4c Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Tue, 30 Dec 2025 21:37:41 -0800 Subject: [PATCH 06/41] Refactor: libcib: Merge existing_cib and result_cib args of cib__op_fn_t Immediately prior to this commit, *result_cib was always either the existing CIB or a copy of it. - If *result_cib was a copy of the existing CIB, then we didn't want changes to *result_cib to affect the existing CIB until the operation succeeded. - If *result_cib was the existing CIB itself, then we didn't have a have a copy, and we wanted the changes to apply directly to the existing CIB. We maintain that behavior in this commit. Signed-off-by: Reid Wahl --- daemons/based/based_messages.c | 109 +++++++++++++-------------- daemons/based/based_messages.h | 51 ++++++------- include/crm/cib/internal.h | 38 +++++----- lib/cib/cib_file.c | 6 +- lib/cib/cib_ops.c | 132 ++++++++++++++++----------------- lib/cib/cib_utils.c | 46 ++++++------ 6 files changed, 184 insertions(+), 198 deletions(-) diff --git a/daemons/based/based_messages.c b/daemons/based/based_messages.c index feb5c8ba539..62e25de6488 100644 --- a/daemons/based/based_messages.c +++ b/daemons/based/based_messages.c @@ -45,14 +45,13 @@ static int sync_in_progress = 0; * \internal * \brief Process a \c PCMK__CIB_REQUEST_ABS_DELETE * - * \param[in] op Ignored - * \param[in] options Ignored - * \param[in] section Ignored - * \param[in] req Ignored - * \param[in] input Ignored - * \param[in] existing_cib Ignored - * \param[in] result_cib Ignored - * \param[in] answer Ignored + * \param[in] op Ignored + * \param[in] options Ignored + * \param[in] section Ignored + * \param[in] req Ignored + * \param[in] input Ignored + * \param[in] cib Ignored + * \param[in] answer Ignored * * \return \c EINVAL * @@ -60,8 +59,8 @@ static int sync_in_progress = 0; */ int based_process_abs_delete(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { /* @COMPAT Remove when PCMK__CIB_REQUEST_ABS_DELETE is removed. Note that * external clients with Pacemaker versions < 3.0.0 can send it. @@ -71,8 +70,8 @@ based_process_abs_delete(const char *op, int options, const char *section, int based_process_apply_patch(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { int rc = pcmk_rc_ok; @@ -98,14 +97,13 @@ based_process_apply_patch(const char *op, int options, const char *section, return pcmk_rc_diff_resync; } - rc = cib__process_apply_patch(op, options, section, req, input, - existing_cib, result_cib, answer); + rc = cib__process_apply_patch(op, options, section, req, input, cib, + answer); pcmk__trace("result: %s (%d), %s", pcmk_rc_str(rc), rc, (based_is_primary? "primary": "secondary")); if ((rc == pcmk_rc_diff_resync) && !based_is_primary) { - pcmk__xml_free(*result_cib); - *result_cib = NULL; + g_clear_pointer(cib, pcmk__xml_free); send_sync_request(); } else if (rc == pcmk_rc_diff_resync) { @@ -117,20 +115,19 @@ based_process_apply_patch(const char *op, int options, const char *section, int based_process_commit_transact(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, - xmlNode *existing_cib, xmlNode **result_cib, + xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer) { - /* On success, our caller will activate *result_cib locally, trigger a - * replace notification if appropriate, and sync *result_cib to all nodes. - * On failure, our caller will free *result_cib. + /* On success, our caller will activate *cib locally, trigger a replace + * notification if appropriate, and sync *cib to all nodes. On failure, our + * caller will free *cib. */ int rc = pcmk_rc_ok; const char *client_id = pcmk__xe_get(req, PCMK__XA_CIB_CLIENTID); const char *origin = pcmk__xe_get(req, PCMK__XA_SRC); pcmk__client_t *client = pcmk__find_client_by_id(client_id); - rc = based_commit_transaction(input, client, origin, result_cib); + rc = based_commit_transaction(input, client, origin, cib); if (rc != pcmk_rc_ok) { char *source = based_transaction_source_str(client, origin); @@ -144,8 +141,8 @@ based_process_commit_transact(const char *op, int options, const char *section, int based_process_is_primary(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { // @COMPAT Pacemaker Remote clients <3.0.0 may send this return (based_is_primary? pcmk_rc_ok : EPERM); @@ -154,8 +151,8 @@ based_process_is_primary(const char *op, int options, const char *section, // @COMPAT: Remove when PCMK__CIB_REQUEST_NOOP is removed int based_process_noop(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { *answer = NULL; return pcmk_rc_ok; @@ -163,10 +160,10 @@ based_process_noop(const char *op, int options, const char *section, int based_process_ping(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { - /* existing_cib and *result_cib should be identical. In the absence of ACL + /* existing_cib and *cib should be identical. In the absence of ACL * filtering, they should also match the_cib. However, they may be copies * filtered based on the current CIB user's ACLs. In that case, our log * messages can use info from the full CIB, and the answer can include the @@ -187,21 +184,21 @@ based_process_ping(const char *op, int options, const char *section, wrapper = pcmk__xe_create(*answer, PCMK__XE_CIB_CALLDATA); - if (*result_cib != NULL) { - // Use *result_cib so that ACL filtering is applied to the answer + if (*cib != NULL) { + // Use *cib so that ACL filtering is applied to the answer pcmk__if_tracing( { /* Append additional detail so the receiver can log the * differences */ - pcmk__xml_copy(wrapper, *result_cib); + pcmk__xml_copy(wrapper, *cib); }, { // Always include at least the version details - const char *name = (const char *) (*result_cib)->name; + const char *name = (const char *) (*cib)->name; xmlNode *shallow = pcmk__xe_create(wrapper, name); - pcmk__xe_copy_attrs(shallow, *result_cib, pcmk__xaf_none); + pcmk__xe_copy_attrs(shallow, *cib, pcmk__xaf_none); } ); } @@ -219,8 +216,8 @@ based_process_ping(const char *op, int options, const char *section, int based_process_primary(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode ** answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { if (!based_is_primary) { pcmk__info("We are now in R/W mode"); @@ -235,11 +232,11 @@ based_process_primary(const char *op, int options, const char *section, int based_process_replace(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { - int rc = cib__process_replace(op, options, section, req, input, - existing_cib, result_cib, answer); + int rc = cib__process_replace(op, options, section, req, input, cib, + answer); if ((rc == pcmk_rc_ok) && pcmk__xe_is(input, PCMK_XE_CIB)) { sync_in_progress = 0; @@ -249,8 +246,8 @@ based_process_replace(const char *op, int options, const char *section, int based_process_schemas(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { xmlNode *wrapper = NULL; xmlNode *data = NULL; @@ -295,8 +292,8 @@ based_process_schemas(const char *op, int options, const char *section, int based_process_secondary(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { if (based_is_primary) { pcmk__info("We are now in R/O mode"); @@ -311,8 +308,8 @@ based_process_secondary(const char *op, int options, const char *section, int based_process_shutdown(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { const char *host = pcmk__xe_get(req, PCMK__XA_SRC); @@ -335,24 +332,24 @@ based_process_shutdown(const char *op, int options, const char *section, int based_process_sync_to_all(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { return sync_our_cib(req, true); } int based_process_sync_to_one(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { return sync_our_cib(req, false); } int based_process_upgrade(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { int rc = pcmk_rc_ok; @@ -364,11 +361,11 @@ based_process_upgrade(const char *op, int options, const char *section, * re-broadcasts the request with PCMK__XA_CIB_SCHEMA_MAX, and each node * performs the upgrade (and notifies its local clients) here. */ - return cib__process_upgrade(op, options, section, req, input, - existing_cib, result_cib, answer); + return cib__process_upgrade(op, options, section, req, input, cib, + answer); } else { - xmlNode *scratch = pcmk__xml_copy(NULL, *result_cib); + xmlNode *scratch = pcmk__xml_copy(NULL, *cib); const char *host = pcmk__xe_get(req, PCMK__XA_SRC); const char *original_schema = NULL; const char *new_schema = NULL; @@ -376,7 +373,7 @@ based_process_upgrade(const char *op, int options, const char *section, const char *call_opts = pcmk__xe_get(req, PCMK__XA_CIB_CALLOPT); const char *call_id = pcmk__xe_get(req, PCMK__XA_CIB_CALLID); - original_schema = pcmk__xe_get(*result_cib, PCMK_XA_VALIDATE_WITH); + original_schema = pcmk__xe_get(*cib, PCMK_XA_VALIDATE_WITH); if (original_schema == NULL) { pcmk__info("Rejecting upgrade request from %s: No " PCMK_XA_VALIDATE_WITH, diff --git a/daemons/based/based_messages.h b/daemons/based/based_messages.h index fee6e089cb8..2cae380e8e6 100644 --- a/daemons/based/based_messages.h +++ b/daemons/based/based_messages.h @@ -18,66 +18,61 @@ extern bool based_is_primary; extern xmlNode *the_cib; int based_process_abs_delete(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, - xmlNode *existing_cib, xmlNode **result_cib, + xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); int based_process_apply_patch(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, - xmlNode *existing_cib, xmlNode **result_cib, + xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); int based_process_commit_transact(const char *op, int options, const char *section, xmlNode *req, - xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *input, xmlNode **cib, + xmlNode **answer); int based_process_is_primary(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, - xmlNode *existing_cib, xmlNode **result_cib, + xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); int based_process_noop(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int based_process_ping(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int based_process_primary(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int based_process_replace(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int based_process_schemas(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int based_process_secondary(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int based_process_shutdown(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int based_process_sync_to_all(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, - xmlNode *existing_cib, xmlNode **result_cib, + xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); int based_process_sync_to_one(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, - xmlNode *existing_cib, xmlNode **result_cib, + xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); int based_process_upgrade(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); void send_sync_request(void); int sync_our_cib(xmlNode *request, bool all); diff --git a/include/crm/cib/internal.h b/include/crm/cib/internal.h index e6b2f53f178..2220307497e 100644 --- a/include/crm/cib/internal.h +++ b/include/crm/cib/internal.h @@ -96,7 +96,7 @@ enum cib__op_type { }; typedef int (*cib__op_fn_t)(const char *, int, const char *, xmlNode *, - xmlNode *, xmlNode *, xmlNode **, xmlNode **); + xmlNode *, xmlNode **, xmlNode **); typedef struct { const char *name; @@ -203,40 +203,40 @@ void cib_native_notify(gpointer data, gpointer user_data); int cib__get_operation(const char *op, const cib__operation_t **operation); int cib__process_apply_patch(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int cib__process_bump(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int cib__process_create(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int cib__process_delete(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int cib__process_erase(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int cib__process_modify(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int cib__process_query(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int cib__process_replace(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int cib__process_upgrade(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer); + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int cib_internal_op(cib_t * cib, const char *op, const char *host, const char *section, xmlNode * data, diff --git a/lib/cib/cib_file.c b/lib/cib/cib_file.c index 69fa7168037..923aea96efc 100644 --- a/lib/cib/cib_file.c +++ b/lib/cib/cib_file.c @@ -322,8 +322,8 @@ commit_transaction(cib_t *cib, xmlNode *transaction, xmlNode **result_cib) static int process_commit_transact(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib_xml, + xmlNode **answer) { int rc = pcmk_rc_ok; const char *client_id = pcmk__xe_get(req, PCMK__XA_CIB_CLIENTID); @@ -334,7 +334,7 @@ process_commit_transact(const char *op, int options, const char *section, cib = get_client(client_id); CRM_CHECK(cib != NULL, return -EINVAL); - rc = commit_transaction(cib, input, result_cib); + rc = commit_transaction(cib, input, cib_xml); if (rc != pcmk_rc_ok) { file_opaque_t *private = cib->variant_opaque; diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c index 811feb7267a..2c0b2752e97 100644 --- a/lib/cib/cib_ops.c +++ b/lib/cib/cib_ops.c @@ -169,10 +169,10 @@ cib__get_operation(const char *op, const cib__operation_t **operation) int cib__process_apply_patch(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { - int rc = xml_apply_patchset(*result_cib, input, true); + int rc = xml_apply_patchset(*cib, input, true); return pcmk_legacy2rc(rc); } @@ -196,10 +196,9 @@ update_counter(xmlNode *xml, const char *field, bool reset) int cib__process_bump(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer) { - update_counter(*result_cib, PCMK_XA_EPOCH, false); + update_counter(*cib, PCMK_XA_EPOCH, false); return pcmk_rc_ok; } @@ -265,11 +264,11 @@ update_results(xmlNode *failed, xmlNode *target, const char *operation, int rc) static int process_create_xpath(const char *op, const char *xpath, xmlNode *input, - xmlNode *result_cib) + xmlNode *cib) { int num_results = 0; int rc = pcmk_rc_ok; - xmlXPathObject *xpath_obj = pcmk__xpath_search(result_cib->doc, xpath); + xmlXPathObject *xpath_obj = pcmk__xpath_search(cib->doc, xpath); xmlNode *match = NULL; xmlChar *path = NULL; @@ -298,8 +297,8 @@ process_create_xpath(const char *op, const char *xpath, xmlNode *input, int cib__process_create(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { xmlNode *failed = NULL; int rc = pcmk_rc_ok; @@ -323,14 +322,14 @@ cib__process_create(const char *op, int options, const char *section, } if (section == NULL) { - return cib__process_modify(op, options, section, req, input, - existing_cib, result_cib, answer); + return cib__process_modify(op, options, section, req, input, cib, + answer); } // @COMPAT Deprecated since 2.1.8 failed = pcmk__xe_create(NULL, PCMK__XE_FAILED); - update_section = pcmk_find_cib_element(*result_cib, section); + update_section = pcmk_find_cib_element(*cib, section); if (pcmk__xe_is(input, section)) { xmlNode *a_child = NULL; @@ -368,12 +367,12 @@ cib__process_create(const char *op, int options, const char *section, static int process_delete_xpath(const char *op, int options, const char *xpath, - xmlNode *result_cib) + xmlNode *cib) { int num_results = 0; int rc = pcmk_rc_ok; - xmlXPathObject *xpath_obj = pcmk__xpath_search(result_cib->doc, xpath); + xmlXPathObject *xpath_obj = pcmk__xpath_search(cib->doc, xpath); num_results = pcmk__xpath_num_results(xpath_obj); if (num_results == 0) { @@ -415,7 +414,7 @@ process_delete_xpath(const char *op, int options, const char *xpath, pcmk__debug("Processing %s op for %s with %s", op, xpath, path); free(path); - if (match == result_cib) { + if (match == cib) { pcmk__warn("Cannot perform %s for %s: the XPath is addressing the " "whole /cib", op, xpath); rc = EINVAL; @@ -447,7 +446,7 @@ delete_child(xmlNode *child, void *userdata) } static int -process_delete_section(const char *section, xmlNode *input, xmlNode *result_cib) +process_delete_section(const char *section, xmlNode *input, xmlNode *cib) { xmlNode *obj_root = NULL; @@ -456,7 +455,7 @@ process_delete_section(const char *section, xmlNode *input, xmlNode *result_cib) return EINVAL; } - obj_root = pcmk_find_cib_element(result_cib, section); + obj_root = pcmk_find_cib_element(cib, section); if (pcmk__xe_is(input, section)) { pcmk__xe_foreach_child(input, NULL, delete_child, obj_root); @@ -470,20 +469,20 @@ process_delete_section(const char *section, xmlNode *input, xmlNode *result_cib) int cib__process_delete(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { if (pcmk__is_set(options, cib_xpath)) { - return process_delete_xpath(op, options, section, *result_cib); + return process_delete_xpath(op, options, section, *cib); } - return process_delete_section(section, input, *result_cib); + return process_delete_section(section, input, *cib); } int cib__process_erase(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { xmlNode *empty = createEmptyCib(0); xmlNode *empty_config = pcmk__xe_first_child(empty, PCMK_XE_CONFIGURATION, @@ -492,20 +491,19 @@ cib__process_erase(const char *op, int options, const char *section, NULL); // Free all existing children, regardless of node type - while ((*result_cib)->children != NULL) { - pcmk__xml_free((*result_cib)->children); + while ((*cib)->children != NULL) { + pcmk__xml_free((*cib)->children); } /* Copying is wasteful here, but calling pcmk__xml_copy() adds the copy as a - * child of the existing *result_cib within the same document. This reduces - * the number of opportunities to make mistakes related to XML documents, - * change tracking, etc., compared to calling xmlUnlinkChild(), - * xmlAddChild(), etc. + * child of the existing *cib within the same document. This reduces the + * number of opportunities to make mistakes related to XML documents, change + * tracking, etc., compared to calling xmlUnlinkChild(), xmlAddChild(), etc. */ - pcmk__xml_copy(*result_cib, empty_config); - pcmk__xml_copy(*result_cib, empty_status); + pcmk__xml_copy(*cib, empty_config); + pcmk__xml_copy(*cib, empty_status); - update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false); + update_counter(*cib, PCMK_XA_ADMIN_EPOCH, false); pcmk__xml_free(empty); return pcmk_rc_ok; @@ -513,11 +511,11 @@ cib__process_erase(const char *op, int options, const char *section, static int process_modify_xpath(const char *op, int options, const char *xpath, - xmlNode *input, xmlNode *result_cib) + xmlNode *input, xmlNode *cib) { int num_results = 0; int rc = pcmk_rc_ok; - xmlXPathObject *xpath_obj = pcmk__xpath_search(result_cib->doc, xpath); + xmlXPathObject *xpath_obj = pcmk__xpath_search(cib->doc, xpath); const bool score = pcmk__is_set(options, cib_score_update); const uint32_t flags = (score? pcmk__xaf_score_update : pcmk__xaf_none); @@ -556,7 +554,7 @@ process_modify_xpath(const char *op, int options, const char *xpath, static int process_modify_section(int options, const char *section, xmlNode *input, - xmlNode *result_cib) + xmlNode *cib) { const bool score = pcmk__is_set(options, cib_score_update); const uint32_t flags = (score? pcmk__xaf_score_update : pcmk__xaf_none); @@ -567,7 +565,7 @@ process_modify_section(int options, const char *section, xmlNode *input, return EINVAL; } - obj_root = pcmk_find_cib_element(result_cib, section); + obj_root = pcmk_find_cib_element(cib, section); if (obj_root == NULL) { xmlNode *tmp_section = NULL; const char *path = pcmk_cib_parent_name_for(section); @@ -579,11 +577,10 @@ process_modify_section(int options, const char *section, xmlNode *input, tmp_section = pcmk__xe_create(NULL, section); // @TODO This feels hacky and is the only call to process_create_xpath() - process_create_xpath(PCMK__CIB_REQUEST_CREATE, path, tmp_section, - result_cib); + process_create_xpath(PCMK__CIB_REQUEST_CREATE, path, tmp_section, cib); pcmk__xml_free(tmp_section); - obj_root = pcmk_find_cib_element(result_cib, section); + obj_root = pcmk_find_cib_element(cib, section); } // Should be impossible, as we just created this section if it didn't exist @@ -603,14 +600,14 @@ process_modify_section(int options, const char *section, xmlNode *input, int cib__process_modify(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { if (pcmk__is_set(options, cib_xpath)) { - return process_modify_xpath(op, options, section, input, *result_cib); + return process_modify_xpath(op, options, section, input, *cib); } - return process_modify_section(options, section, input, *result_cib); + return process_modify_section(options, section, input, *cib); } static int @@ -737,23 +734,22 @@ process_query_section(int options, const char *section, xmlNode *cib, int cib__process_query(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer) { if (pcmk__is_set(options, cib_xpath)) { - return process_query_xpath(op, options, section, *result_cib, answer); + return process_query_xpath(op, options, section, *cib, answer); } - return process_query_section(options, section, *result_cib, answer); + return process_query_section(options, section, *cib, answer); } static int process_replace_xpath(const char *op, int options, const char *xpath, - xmlNode *input, xmlNode *result_cib) + xmlNode *input, xmlNode *cib) { int num_results = 0; int rc = pcmk_rc_ok; - xmlXPathObject *xpath_obj = pcmk__xpath_search(result_cib->doc, xpath); + xmlXPathObject *xpath_obj = pcmk__xpath_search(cib->doc, xpath); num_results = pcmk__xpath_num_results(xpath_obj); if (num_results == 0) { @@ -820,7 +816,7 @@ replace_cib_digest_matches(xmlNode *request, xmlNode *input) } static int -replace_cib(xmlNode *request, xmlNode *input, xmlNode **result_cib) +replace_cib(xmlNode *request, xmlNode *input, xmlNode **cib) { int updates = 0; int epoch = 0; @@ -833,7 +829,7 @@ replace_cib(xmlNode *request, xmlNode *input, xmlNode **result_cib) const char *reason = NULL; const char *peer = pcmk__xe_get(request, PCMK__XA_SRC); - cib_version_details(*result_cib, &admin_epoch, &epoch, &updates); + cib_version_details(*cib, &admin_epoch, &epoch, &updates); cib_version_details(input, &replace_admin_epoch, &replace_epoch, &replace_updates); @@ -868,7 +864,7 @@ replace_cib(xmlNode *request, xmlNode *input, xmlNode **result_cib) return pcmk_rc_old_data; } - *result_cib = pcmk__xml_replace_with_copy(*result_cib, input); + *cib = pcmk__xml_replace_with_copy(*cib, input); pcmk__info("Replaced %d.%d.%d with %d.%d.%d from %s", admin_epoch, epoch, updates, replace_admin_epoch, replace_epoch, replace_updates, @@ -878,7 +874,7 @@ replace_cib(xmlNode *request, xmlNode *input, xmlNode **result_cib) static int process_replace_section(const char *section, xmlNode *request, xmlNode *input, - xmlNode **result_cib) + xmlNode **cib) { int rc = pcmk_rc_ok; xmlNode *obj_root = NULL; @@ -889,7 +885,7 @@ process_replace_section(const char *section, xmlNode *request, xmlNode *input, } if (pcmk__xe_is(input, PCMK_XE_CIB)) { - return replace_cib(request, input, result_cib); + return replace_cib(request, input, cib); } if (pcmk__str_eq(PCMK__XE_ALL, section, pcmk__str_casei) @@ -898,7 +894,7 @@ process_replace_section(const char *section, xmlNode *request, xmlNode *input, section = NULL; } - obj_root = pcmk_find_cib_element(*result_cib, section); + obj_root = pcmk_find_cib_element(*cib, section); rc = pcmk__xe_replace_match(obj_root, input); if (rc != pcmk_rc_ok) { @@ -910,35 +906,35 @@ process_replace_section(const char *section, xmlNode *request, xmlNode *input, int cib__process_replace(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { if (pcmk__is_set(options, cib_xpath)) { - return process_replace_xpath(op, options, section, input, *result_cib); + return process_replace_xpath(op, options, section, input, *cib); } - return process_replace_section(section, req, input, result_cib); + return process_replace_section(section, req, input, cib); } int cib__process_upgrade(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode *existing_cib, - xmlNode **result_cib, xmlNode **answer) + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { int rc = pcmk_rc_ok; const char *max_schema = pcmk__xe_get(req, PCMK__XA_CIB_SCHEMA_MAX); const char *original_schema = NULL; const char *new_schema = NULL; - original_schema = pcmk__xe_get(*result_cib, PCMK_XA_VALIDATE_WITH); - rc = pcmk__update_schema(result_cib, max_schema, true, + original_schema = pcmk__xe_get(*cib, PCMK_XA_VALIDATE_WITH); + rc = pcmk__update_schema(cib, max_schema, true, !pcmk__is_set(options, cib_verbose)); - new_schema = pcmk__xe_get(*result_cib, PCMK_XA_VALIDATE_WITH); + new_schema = pcmk__xe_get(*cib, PCMK_XA_VALIDATE_WITH); if (pcmk__cmp_schemas_by_name(new_schema, original_schema) > 0) { - update_counter(*result_cib, PCMK_XA_ADMIN_EPOCH, false); - update_counter(*result_cib, PCMK_XA_EPOCH, true); - update_counter(*result_cib, PCMK_XA_NUM_UPDATES, true); + update_counter(*cib, PCMK_XA_ADMIN_EPOCH, false); + update_counter(*cib, PCMK_XA_EPOCH, true); + update_counter(*cib, PCMK_XA_NUM_UPDATES, true); return pcmk_rc_ok; } diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index ea272ff1f0f..e64c013393f 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -177,7 +177,7 @@ cib__perform_query(const char *op, uint32_t call_options, cib__op_fn_t fn, int rc = pcmk_rc_ok; const char *user = NULL; - xmlNode *cib_ro = NULL; + xmlNode *cib = NULL; xmlNode *cib_filtered = NULL; pcmk__assert((op != NULL) && (fn != NULL) && (req != NULL) @@ -185,7 +185,7 @@ cib__perform_query(const char *op, uint32_t call_options, cib__op_fn_t fn, && (output != NULL) && (*output == NULL)); user = pcmk__xe_get(req, PCMK__XA_CIB_USER); - cib_ro = *current_cib; + cib = *current_cib; if (cib_acl_enabled(*current_cib, user) && xml_acl_filtered_copy(user, *current_cib, *current_cib, @@ -195,15 +195,15 @@ cib__perform_query(const char *op, uint32_t call_options, cib__op_fn_t fn, pcmk__debug("Pre-filtered the entire cib"); return EACCES; } - cib_ro = cib_filtered; - pcmk__log_xml_trace(cib_ro, "filtered"); + cib = cib_filtered; + pcmk__log_xml_trace(cib, "filtered"); } pcmk__trace("Processing %s for section '%s', user '%s'", op, pcmk__s(section, "(null)"), pcmk__s(user, "(null)")); pcmk__log_xml_trace(req, "request"); - rc = fn(op, call_options, section, req, input, cib_ro, &cib_ro, output); + rc = fn(op, call_options, section, req, input, &cib, output); if (*output == NULL) { // Do nothing @@ -226,7 +226,6 @@ cib__perform_query(const char *op, uint32_t call_options, cib__op_fn_t fn, } pcmk__xml_free(cib_filtered); - return rc; } @@ -310,32 +309,32 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, if (!make_copy) { /* Conditional on v2 patch style */ - scratch = *current_cib; - // Make a copy of the top-level element to store version details - top = pcmk__xe_create(NULL, (const char *) scratch->name); - pcmk__xe_copy_attrs(top, scratch, pcmk__xaf_none); + top = pcmk__xe_create(NULL, (const char *) (*current_cib)->name); + pcmk__xe_copy_attrs(top, *current_cib, pcmk__xaf_none); patchset_cib = top; - pcmk__xml_commit_changes(scratch->doc); - pcmk__xml_doc_set_flags(scratch->doc, pcmk__xf_tracking); + pcmk__xml_commit_changes((*current_cib)->doc); + pcmk__xml_doc_set_flags((*current_cib)->doc, pcmk__xf_tracking); if (enable_acl) { - pcmk__enable_acls((*current_cib)->doc, scratch->doc, user); + pcmk__enable_acls((*current_cib)->doc, (*current_cib)->doc, user); } pcmk__trace("Processing %s for section '%s', user '%s'", op, pcmk__s(section, "(null)"), pcmk__s(user, "(null)")); pcmk__log_xml_trace(req, "request"); - rc = (*fn) (op, call_options, section, req, input, scratch, &scratch, output); + rc = (*fn) (op, call_options, section, req, input, current_cib, output); - /* If scratch points to a new object now (for example, after an erase - * operation), then *current_cib should point to the same object. - * - * @TODO Enable tracking and ACLs and calculate changes? Change tracking - * and unpacked ACLs didn't carry over to new object. + /* Set scratch to *current_cib after fn(), in case *current_cib points + * somewhere else now (for example, erase or full-CIB replace op). + */ + scratch = *current_cib; + + /* @TODO Enable tracking and ACLs and calculate changes? If + * scratch and *current_cib point to a new object, then change tracking + * and unpacked ACLs didn't carry over to it. */ - *current_cib = scratch; } else { scratch = pcmk__xml_copy(NULL, *current_cib); @@ -350,8 +349,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, pcmk__s(section, "(null)"), pcmk__s(user, "(null)")); pcmk__log_xml_trace(req, "request"); - rc = (*fn) (op, call_options, section, req, input, *current_cib, - &scratch, output); + rc = (*fn) (op, call_options, section, req, input, &scratch, output); /* @TODO This appears to be a hack to determine whether scratch points * to a new object now, without saving the old pointer (which may be @@ -823,8 +821,8 @@ cib_apply_patch_event(xmlNode *event, xmlNode *input, xmlNode **output, *output = pcmk__xml_copy(NULL, input); } - rc = cib__process_apply_patch(NULL, cib_none, NULL, event, diff, input, - output, NULL); + rc = cib__process_apply_patch(NULL, cib_none, NULL, event, diff, output, + NULL); rc = pcmk_rc2legacy(rc); if (rc == pcmk_ok) { return pcmk_ok; From d1e4510d6e5e76bc9167cc02f92de48951c75192 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Tue, 30 Dec 2025 22:55:25 -0800 Subject: [PATCH 07/41] Refactor: libcib: Return standard code from cib_file.c:process_request() Signed-off-by: Reid Wahl --- lib/cib/cib_file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/cib/cib_file.c b/lib/cib/cib_file.c index 923aea96efc..4cf3bc5dd63 100644 --- a/lib/cib/cib_file.c +++ b/lib/cib/cib_file.c @@ -138,7 +138,7 @@ get_client(const char *client_id) static int process_request(cib_t *cib, xmlNode *request, xmlNode **output) { - int rc = pcmk_ok; + int rc = pcmk_rc_ok; const cib__operation_t *operation = NULL; cib__op_fn_t op_function = NULL; @@ -211,7 +211,7 @@ process_request(cib_t *cib, xmlNode *request, xmlNode **output) pcmk__xml_free(result_cib); } pcmk__xml_free(cib_diff); - return pcmk_rc2legacy(rc); + return rc; } /*! @@ -241,7 +241,6 @@ process_transaction_requests(cib_t *cib, xmlNode *transaction) int rc = process_request(cib, request, &output); - rc = pcmk_legacy2rc(rc); if (rc != pcmk_rc_ok) { pcmk__err("Aborting transaction for CIB file client (%s) on file " "'%s' due to failed %s request: %s", @@ -465,6 +464,7 @@ file_perform_op_delegate(cib_t *cib, const char *op, const char *host, } rc = process_request(cib, request, &output); + rc = pcmk_rc2legacy(rc); if ((output_data != NULL) && (output != NULL)) { if (output->doc == private->cib_xml->doc) { From 1472a1c5ef11660546231ceafcdc5ed15df9df31 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Tue, 30 Dec 2025 23:05:19 -0800 Subject: [PATCH 08/41] Refactor: libcib: Return standard code from cib__extend_transaction() Signed-off-by: Reid Wahl --- lib/cib/cib_file.c | 1 + lib/cib/cib_native.c | 1 + lib/cib/cib_remote.c | 2 +- lib/cib/cib_utils.c | 22 +++++++++++----------- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/cib/cib_file.c b/lib/cib/cib_file.c index 4cf3bc5dd63..4340aea0431 100644 --- a/lib/cib/cib_file.c +++ b/lib/cib/cib_file.c @@ -460,6 +460,7 @@ file_perform_op_delegate(cib_t *cib, const char *op, const char *host, if (pcmk__is_set(call_options, cib_transaction)) { rc = cib__extend_transaction(cib, request); + rc = pcmk_rc2legacy(rc); goto done; } diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index db28bd2b120..06dd8419eac 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -74,6 +74,7 @@ cib_native_perform_op_delegate(cib_t *cib, const char *op, const char *host, if (pcmk__is_set(call_options, cib_transaction)) { rc = cib__extend_transaction(cib, op_msg); + rc = pcmk_rc2legacy(rc); goto done; } diff --git a/lib/cib/cib_remote.c b/lib/cib/cib_remote.c index 3ab07278d7e..b269db74b35 100644 --- a/lib/cib/cib_remote.c +++ b/lib/cib/cib_remote.c @@ -85,7 +85,7 @@ cib_remote_perform_op(cib_t *cib, const char *op, const char *host, if (pcmk__is_set(call_options, cib_transaction)) { rc = cib__extend_transaction(cib, op_msg); pcmk__xml_free(op_msg); - return rc; + return pcmk_rc2legacy(rc); } pcmk__trace("Sending %s message to the CIB manager", op); diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index e64c013393f..a537eb79ab7 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -639,11 +639,13 @@ validate_transaction_request(const xmlNode *request) * \param[in,out] cib CIB client whose transaction to extend * \param[in,out] request Request to add to transaction * - * \return Legacy Pacemaker return code + * \return Standard Pacemaker return code */ int cib__extend_transaction(cib_t *cib, xmlNode *request) { + const char *op = pcmk__xe_get(request, PCMK__XA_CIB_OP); + const char *client_id = NULL; int rc = pcmk_rc_ok; pcmk__assert((cib != NULL) && (request != NULL)); @@ -656,18 +658,16 @@ cib__extend_transaction(cib_t *cib, xmlNode *request) if (rc == pcmk_rc_ok) { pcmk__xml_copy(cib->transaction, request); + return pcmk_rc_ok; + } - } else { - const char *op = pcmk__xe_get(request, PCMK__XA_CIB_OP); - const char *client_id = NULL; + cib->cmds->client_id(cib, NULL, &client_id); - cib->cmds->client_id(cib, NULL, &client_id); - pcmk__err("Failed to add '%s' operation to transaction for client %s: " - "%s", - op, pcmk__s(client_id, "(unidentified)"), pcmk_rc_str(rc)); - pcmk__log_xml_info(request, "failed"); - } - return pcmk_rc2legacy(rc); + pcmk__err("Failed to add '%s' operation to transaction for client %s: %s", + op, pcmk__s(client_id, "(unidentified)"), pcmk_rc_str(rc)); + pcmk__log_xml_info(request, "failed"); + + return rc; } void From 1e151fe6cfaa84e5dce0c57f9e80165034802816 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Tue, 30 Dec 2025 23:08:15 -0800 Subject: [PATCH 09/41] Refactor: libcib: Return standard code from cib__create_op() Signed-off-by: Reid Wahl --- lib/cib/cib_file.c | 2 ++ lib/cib/cib_native.c | 2 ++ lib/cib/cib_remote.c | 1 + lib/cib/cib_utils.c | 4 ++-- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/cib/cib_file.c b/lib/cib/cib_file.c index 4340aea0431..a9bbf9246e8 100644 --- a/lib/cib/cib_file.c +++ b/lib/cib/cib_file.c @@ -452,9 +452,11 @@ file_perform_op_delegate(cib_t *cib, const char *op, const char *host, rc = cib__create_op(cib, op, host, section, data, call_options, user_name, NULL, &request); + rc = pcmk_rc2legacy(rc); if (rc != pcmk_ok) { return rc; } + pcmk__xe_set(request, PCMK__XA_ACL_TARGET, user_name); pcmk__xe_set(request, PCMK__XA_CIB_CLIENTID, private->id); diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 06dd8419eac..9f2de2a39ec 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -68,6 +68,7 @@ cib_native_perform_op_delegate(cib_t *cib, const char *op, const char *host, rc = cib__create_op(cib, op, host, section, data, call_options, user_name, NULL, &op_msg); + rc = pcmk_rc2legacy(rc); if (rc != pcmk_ok) { return rc; } @@ -312,6 +313,7 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) if (rc == pcmk_ok) { rc = cib__create_op(cib, CRM_OP_REGISTER, NULL, NULL, NULL, cib_sync_call, NULL, name, &hello); + rc = pcmk_rc2legacy(rc); } if (rc == pcmk_ok) { diff --git a/lib/cib/cib_remote.c b/lib/cib/cib_remote.c index b269db74b35..c4cdb2746cf 100644 --- a/lib/cib/cib_remote.c +++ b/lib/cib/cib_remote.c @@ -78,6 +78,7 @@ cib_remote_perform_op(cib_t *cib, const char *op, const char *host, rc = cib__create_op(cib, op, host, section, data, call_options, user_name, NULL, &op_msg); + rc = pcmk_rc2legacy(rc); if (rc != pcmk_ok) { return rc; } diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index a537eb79ab7..3ab2ccfc148 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -567,7 +567,7 @@ cib__create_op(cib_t *cib, const char *op, const char *host, const char *user_name, const char *client_name, xmlNode **op_msg) { - CRM_CHECK((cib != NULL) && (op_msg != NULL), return -EPROTO); + CRM_CHECK((cib != NULL) && (op_msg != NULL), return EPROTO); *op_msg = pcmk__xe_create(NULL, PCMK__XE_CIB_COMMAND); @@ -594,7 +594,7 @@ cib__create_op(cib_t *cib, const char *op, const char *host, pcmk__xml_copy(wrapper, data); } - return pcmk_ok; + return pcmk_rc_ok; } /*! From ee84255ccdc5fe2cc9d92e0fbecb7fa45c7a0e0d Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Tue, 30 Dec 2025 23:24:51 -0800 Subject: [PATCH 10/41] Refactor: libcib: Assert *current_cib != scratch when make_copy true We might as well assert fatally here, as that would mean a major programming error. Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 3ab2ccfc148..264e33c4c4e 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -363,7 +363,8 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, } pcmk__xml_mark_changes(*current_cib, scratch); } - CRM_CHECK(*current_cib != scratch, return EINVAL); + + pcmk__assert(*current_cib != scratch); } xml_acl_disable(scratch); /* Allow the system to make any additional changes */ From e37beb5f6282c1d2ff047e85a8157e1ed34e8bea Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Tue, 10 Feb 2026 14:22:29 -0800 Subject: [PATCH 11/41] Refactor: various: Simplify calling function variables Where fn is a pointer to function, "(*fn)(args)" is equivalent to "fn(args)". Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 4 ++-- lib/common/messages.c | 2 +- lib/common/xpath.c | 4 ++-- lib/pengine/remote.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 264e33c4c4e..ab142e2b76d 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -324,7 +324,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, pcmk__s(section, "(null)"), pcmk__s(user, "(null)")); pcmk__log_xml_trace(req, "request"); - rc = (*fn) (op, call_options, section, req, input, current_cib, output); + rc = fn(op, call_options, section, req, input, current_cib, output); /* Set scratch to *current_cib after fn(), in case *current_cib points * somewhere else now (for example, erase or full-CIB replace op). @@ -349,7 +349,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, pcmk__s(section, "(null)"), pcmk__s(user, "(null)")); pcmk__log_xml_trace(req, "request"); - rc = (*fn) (op, call_options, section, req, input, &scratch, output); + rc = fn(op, call_options, section, req, input, &scratch, output); /* @TODO This appears to be a hack to determine whether scratch points * to a new object now, without saving the old pointer (which may be diff --git a/lib/common/messages.c b/lib/common/messages.c index fe8a0921e9d..da226ee699f 100644 --- a/lib/common/messages.c +++ b/lib/common/messages.c @@ -229,7 +229,7 @@ pcmk__process_request(pcmk__request_t *request, GHashTable *handlers) } } - return (*handler)(request); + return handler(request); } /*! diff --git a/lib/common/xpath.c b/lib/common/xpath.c index 8bff702dcb0..96de7b01c42 100644 --- a/lib/common/xpath.c +++ b/lib/common/xpath.c @@ -182,7 +182,7 @@ pcmk__xpath_foreach_result(xmlDoc *doc, const char *path, xmlNode *result = pcmk__xpath_result(xpath_obj, i); if (result != NULL) { - (*fn)(result, user_data); + fn(result, user_data); } } xmlXPathFreeObject(xpath_obj); @@ -519,7 +519,7 @@ crm_foreach_xpath_result(xmlNode *xml, const char *xpath, CRM_LOG_ASSERT(result != NULL); if (result != NULL) { - (*helper)(result, user_data); + helper(result, user_data); } } } diff --git a/lib/pengine/remote.c b/lib/pengine/remote.c index 84b5ca4972c..45a15f7ee07 100644 --- a/lib/pengine/remote.c +++ b/lib/pengine/remote.c @@ -103,7 +103,7 @@ pe_foreach_guest_node(const pcmk_scheduler_t *scheduler, pcmk_node_t *guest_node = pcmk_find_node(scheduler, rsc->id); if (guest_node) { - (*helper)(guest_node, user_data); + helper(guest_node, user_data); } } } From f9292707dc5bd5c2569e9ccb83b7617bf28bd615 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Tue, 30 Dec 2025 23:30:38 -0800 Subject: [PATCH 12/41] Refactor: libcib: Rename scratch to working_cib in cib_perform_op() It may not be a copy, the changes to it may be accepted as permanent, and the name "scratch" didn't make it obvious that it was CIB XML. I think we need all the clarity we can get, as complicated as cib_perform_op() is. Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 105 +++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 51 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index ab142e2b76d..fe8203801b9 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -287,7 +287,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, int rc = pcmk_rc_ok; bool make_copy = true; xmlNode *top = NULL; - xmlNode *scratch = NULL; + xmlNode *working_cib = NULL; xmlNode *patchset_cib = NULL; xmlNode *local_diff = NULL; @@ -326,54 +326,56 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, rc = fn(op, call_options, section, req, input, current_cib, output); - /* Set scratch to *current_cib after fn(), in case *current_cib points - * somewhere else now (for example, erase or full-CIB replace op). + /* Set working_cib to *current_cib after fn(), in case *current_cib + * points somewhere else now (for example, after a erase or full-CIB + * replace op). */ - scratch = *current_cib; + working_cib = *current_cib; - /* @TODO Enable tracking and ACLs and calculate changes? If - * scratch and *current_cib point to a new object, then change tracking - * and unpacked ACLs didn't carry over to it. + /* @TODO Enable tracking and ACLs and calculate changes? If working_cib + * and *current_cib point to a new object, then change tracking and + * unpacked ACLs didn't carry over to it. */ } else { - scratch = pcmk__xml_copy(NULL, *current_cib); + working_cib = pcmk__xml_copy(NULL, *current_cib); patchset_cib = *current_cib; - pcmk__xml_doc_set_flags(scratch->doc, pcmk__xf_tracking); + pcmk__xml_doc_set_flags(working_cib->doc, pcmk__xf_tracking); if (enable_acl) { - pcmk__enable_acls((*current_cib)->doc, scratch->doc, user); + pcmk__enable_acls((*current_cib)->doc, working_cib->doc, user); } pcmk__trace("Processing %s for section '%s', user '%s'", op, pcmk__s(section, "(null)"), pcmk__s(user, "(null)")); pcmk__log_xml_trace(req, "request"); - rc = fn(op, call_options, section, req, input, &scratch, output); + rc = fn(op, call_options, section, req, input, &working_cib, output); - /* @TODO This appears to be a hack to determine whether scratch points - * to a new object now, without saving the old pointer (which may be - * invalid now) for comparison. Confirm this, and check more clearly. + /* @TODO This appears to be a hack to determine whether working_cib + * points to a new object now, without saving the old pointer (which may + * be invalid now) for comparison. Confirm this, and check more clearly. */ - if (!pcmk__xml_doc_all_flags_set(scratch->doc, pcmk__xf_tracking)) { + if (!pcmk__xml_doc_all_flags_set(working_cib->doc, pcmk__xf_tracking)) { pcmk__trace("Inferring changes after %s op", op); - pcmk__xml_commit_changes(scratch->doc); + pcmk__xml_commit_changes(working_cib->doc); if (enable_acl) { - pcmk__enable_acls((*current_cib)->doc, scratch->doc, user); + pcmk__enable_acls((*current_cib)->doc, working_cib->doc, user); } - pcmk__xml_mark_changes(*current_cib, scratch); + pcmk__xml_mark_changes(*current_cib, working_cib); } - pcmk__assert(*current_cib != scratch); + pcmk__assert(*current_cib != working_cib); } - xml_acl_disable(scratch); /* Allow the system to make any additional changes */ + // Allow ourselves to make any additional necessary changes + xml_acl_disable(working_cib); - if ((rc == pcmk_rc_ok) && (scratch == NULL)) { + if ((rc == pcmk_rc_ok) && (working_cib == NULL)) { rc = EINVAL; goto done; - } else if ((rc == pcmk_rc_ok) && xml_acl_denied(scratch)) { + } else if ((rc == pcmk_rc_ok) && xml_acl_denied(working_cib)) { pcmk__trace("ACL rejected part or all of the proposed changes"); rc = EACCES; goto done; @@ -386,8 +388,10 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, * supported. All we care about in that case is the schema version, which * is checked elsewhere. */ - if (scratch && (cib == NULL || cib->variant != cib_file)) { - const char *new_version = pcmk__xe_get(scratch, + if ((working_cib != NULL) + && ((cib == NULL) || (cib->variant != cib_file))) { + + const char *new_version = pcmk__xe_get(working_cib, PCMK_XA_CRM_FEATURE_SET); rc = pcmk__check_feature_set(new_version); @@ -403,7 +407,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, int old = 0; int new = 0; - pcmk__xe_get_int(scratch, PCMK_XA_ADMIN_EPOCH, &new); + pcmk__xe_get_int(working_cib, PCMK_XA_ADMIN_EPOCH, &new); pcmk__xe_get_int(patchset_cib, PCMK_XA_ADMIN_EPOCH, &old); if (old > new) { @@ -414,7 +418,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, rc = pcmk_rc_old_data; } else if (old == new) { - pcmk__xe_get_int(scratch, PCMK_XA_EPOCH, &new); + pcmk__xe_get_int(working_cib, PCMK_XA_EPOCH, &new); pcmk__xe_get_int(patchset_cib, PCMK_XA_EPOCH, &old); if (old > new) { pcmk__err("%s went backwards: %d -> %d (Opts: %#x)", @@ -427,7 +431,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, } pcmk__trace("Massaging CIB contents"); - pcmk__strip_xml_text(scratch); + pcmk__strip_xml_text(working_cib); if (make_copy) { static time_t expires = 0; @@ -439,15 +443,15 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, } } - local_diff = xml_create_patchset(0, patchset_cib, scratch, + local_diff = xml_create_patchset(0, patchset_cib, working_cib, config_changed, manage_counters); - pcmk__log_xml_changes(LOG_TRACE, scratch); - pcmk__xml_commit_changes(scratch->doc); + pcmk__log_xml_changes(LOG_TRACE, working_cib); + pcmk__xml_commit_changes(working_cib->doc); - if(local_diff) { + if (local_diff != NULL) { if (with_digest) { - pcmk__xml_patchset_add_digest(local_diff, scratch); + pcmk__xml_patchset_add_digest(local_diff, working_cib); } pcmk__log_xml_patchset(LOG_INFO, local_diff); pcmk__log_xml_trace(local_diff, "raw patch"); @@ -471,7 +475,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, NULL); pcmk__xml_write_temp_file(patchset_cib, "PatchApply:input", NULL); - pcmk__xml_write_temp_file(scratch, "PatchApply:actual", + pcmk__xml_write_temp_file(working_cib, "PatchApply:actual", NULL); pcmk__xml_write_temp_file(local_diff, "PatchApply:diff", NULL); @@ -486,43 +490,43 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, ); } - /* scratch must not be modified after this point, except for the attributes - * for which pcmk__xa_filterable() returns true + /* working_cib must not be modified after this point, except for the + * attributes for which pcmk__xa_filterable() returns true */ if (*config_changed && !pcmk__is_set(call_options, cib_no_mtime)) { - const char *schema = pcmk__xe_get(scratch, PCMK_XA_VALIDATE_WITH); + const char *schema = pcmk__xe_get(working_cib, PCMK_XA_VALIDATE_WITH); if (schema == NULL) { rc = pcmk_rc_cib_corrupt; } - pcmk__xe_add_last_written(scratch); + pcmk__xe_add_last_written(working_cib); pcmk__warn_if_schema_deprecated(schema); - /* Make values of origin, client, and user in scratch match - * the ones in req (if the schema allows the attributes) + /* Make values of origin, client, and user in working_cib match the ones + * in req (if the schema allows the attributes) */ if (pcmk__cmp_schemas_by_name(schema, "pacemaker-1.2") >= 0) { const char *origin = pcmk__xe_get(req, PCMK__XA_SRC); const char *client = pcmk__xe_get(req, PCMK__XA_CIB_CLIENTNAME); if (origin != NULL) { - pcmk__xe_set(scratch, PCMK_XA_UPDATE_ORIGIN, origin); + pcmk__xe_set(working_cib, PCMK_XA_UPDATE_ORIGIN, origin); } else { - pcmk__xe_remove_attr(scratch, PCMK_XA_UPDATE_ORIGIN); + pcmk__xe_remove_attr(working_cib, PCMK_XA_UPDATE_ORIGIN); } if (client != NULL) { - pcmk__xe_set(scratch, PCMK_XA_UPDATE_CLIENT, client); + pcmk__xe_set(working_cib, PCMK_XA_UPDATE_CLIENT, client); } else { - pcmk__xe_remove_attr(scratch, PCMK_XA_UPDATE_CLIENT); + pcmk__xe_remove_attr(working_cib, PCMK_XA_UPDATE_CLIENT); } if (user != NULL) { - pcmk__xe_set(scratch, PCMK_XA_UPDATE_USER, user); + pcmk__xe_set(working_cib, PCMK_XA_UPDATE_USER, user); } else { - pcmk__xe_remove_attr(scratch, PCMK_XA_UPDATE_USER); + pcmk__xe_remove_attr(working_cib, PCMK_XA_UPDATE_USER); } } } @@ -530,25 +534,24 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, // Skip validation for status-only updates, since we allow anything there if ((rc == pcmk_rc_ok) && !pcmk__str_eq(section, PCMK_XE_STATUS, pcmk__str_casei) - && !pcmk__configured_schema_validates(scratch)) { + && !pcmk__configured_schema_validates(working_cib)) { rc = pcmk_rc_schema_validation; } - done: - - *result_cib = scratch; +done: + *result_cib = working_cib; /* @TODO: This may not work correctly with !make_copy, since we don't * keep the original CIB. */ if ((rc != pcmk_rc_ok) && cib_acl_enabled(patchset_cib, user) - && xml_acl_filtered_copy(user, patchset_cib, scratch, result_cib)) { + && xml_acl_filtered_copy(user, patchset_cib, working_cib, result_cib)) { if (*result_cib == NULL) { pcmk__debug("Pre-filtered the entire cib result"); } - pcmk__xml_free(scratch); + pcmk__xml_free(working_cib); } if(diff) { From 2d5d01834304e426304bd40f1a51aeed89b48e12 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Tue, 30 Dec 2025 23:40:31 -0800 Subject: [PATCH 13/41] Refactor: libcib: New set_update_origin() for cib_perform_op() Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 86 ++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index fe8203801b9..40a4817e3c4 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -277,6 +277,56 @@ should_copy_cib(const char *op, const char *section, int call_options) return true; } +/*! + * \internal + * \brief Set values for update origin host, client, and user in new CIB + * + * \param[in,out] new_cib Result CIB after performing operation + * \param[in] request CIB request (source of origin info) + * + * \return Standard Pacemaker return code + */ +static int +set_update_origin(xmlNode *new_cib, const xmlNode *request) +{ + const char *origin = pcmk__xe_get(request, PCMK__XA_SRC); + const char *client = pcmk__xe_get(request, PCMK__XA_CIB_CLIENTNAME); + const char *user = pcmk__xe_get(request, PCMK__XA_CIB_USER); + const char *schema = pcmk__xe_get(new_cib, PCMK_XA_VALIDATE_WITH); + + if (schema == NULL) { + return pcmk_rc_cib_corrupt; + } + + pcmk__xe_add_last_written(new_cib); + pcmk__warn_if_schema_deprecated(schema); + + // pacemaker-1.2 is the earliest schema version that allow these attributes + if (pcmk__cmp_schemas_by_name(schema, "pacemaker-1.2") < 0) { + return pcmk_rc_ok; + } + + if (origin != NULL) { + pcmk__xe_set(new_cib, PCMK_XA_UPDATE_ORIGIN, origin); + } else { + pcmk__xe_remove_attr(new_cib, PCMK_XA_UPDATE_ORIGIN); + } + + if (client != NULL) { + pcmk__xe_set(new_cib, PCMK_XA_UPDATE_CLIENT, client); + } else { + pcmk__xe_remove_attr(new_cib, PCMK_XA_UPDATE_CLIENT); + } + + if (user != NULL) { + pcmk__xe_set(new_cib, PCMK_XA_UPDATE_USER, user); + } else { + pcmk__xe_remove_attr(new_cib, PCMK_XA_UPDATE_USER); + } + + return pcmk_rc_ok; +} + int cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, cib__op_fn_t fn, const char *section, xmlNode *req, @@ -495,39 +545,9 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, */ if (*config_changed && !pcmk__is_set(call_options, cib_no_mtime)) { - const char *schema = pcmk__xe_get(working_cib, PCMK_XA_VALIDATE_WITH); - - if (schema == NULL) { - rc = pcmk_rc_cib_corrupt; - } - - pcmk__xe_add_last_written(working_cib); - pcmk__warn_if_schema_deprecated(schema); - - /* Make values of origin, client, and user in working_cib match the ones - * in req (if the schema allows the attributes) - */ - if (pcmk__cmp_schemas_by_name(schema, "pacemaker-1.2") >= 0) { - const char *origin = pcmk__xe_get(req, PCMK__XA_SRC); - const char *client = pcmk__xe_get(req, PCMK__XA_CIB_CLIENTNAME); - - if (origin != NULL) { - pcmk__xe_set(working_cib, PCMK_XA_UPDATE_ORIGIN, origin); - } else { - pcmk__xe_remove_attr(working_cib, PCMK_XA_UPDATE_ORIGIN); - } - - if (client != NULL) { - pcmk__xe_set(working_cib, PCMK_XA_UPDATE_CLIENT, client); - } else { - pcmk__xe_remove_attr(working_cib, PCMK_XA_UPDATE_CLIENT); - } - - if (user != NULL) { - pcmk__xe_set(working_cib, PCMK_XA_UPDATE_USER, user); - } else { - pcmk__xe_remove_attr(working_cib, PCMK_XA_UPDATE_USER); - } + rc = set_update_origin(working_cib, req); + if (rc != pcmk_rc_ok) { + goto done; } } From 48e3a90e20a3a17ae90d161134bcd3ca6380b885 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Tue, 30 Dec 2025 23:43:59 -0800 Subject: [PATCH 14/41] Log: libcib: Drop unhelpful trace message Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 40a4817e3c4..d5796acde25 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -480,7 +480,6 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, } } - pcmk__trace("Massaging CIB contents"); pcmk__strip_xml_text(working_cib); if (make_copy) { From 937c0d03d526758ba127c22693c8155d1be40da2 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 01:25:39 -0800 Subject: [PATCH 15/41] Low: libcrmcommon: Handle NULL PCMK_XA_FORMAT and PCMK_XA_DIGEST A patchset doesn't necessarily contain a digest. A patchset from a Pacemaker version recent enough to be supported should contain a format, but let's check just in case. Signed-off-by: Reid Wahl --- lib/common/patchset_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/common/patchset_display.c b/lib/common/patchset_display.c index 9cc1663eaf0..110e56e3a98 100644 --- a/lib/common/patchset_display.c +++ b/lib/common/patchset_display.c @@ -50,9 +50,10 @@ xml_show_patchset_header(pcmk__output_t *out, const xmlNode *patchset) const char *fmt = pcmk__xe_get(patchset, PCMK_XA_FORMAT); const char *digest = pcmk__xe_get(patchset, PCMK_XA_DIGEST); - out->info(out, "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], fmt); + out->info(out, "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], + pcmk__s(fmt, "(no format)")); rc = out->info(out, "Diff: +++ %d.%d.%d %s", - add[0], add[1], add[2], digest); + add[0], add[1], add[2], pcmk__s(digest, "(no digest)")); } else if ((add[0] != 0) || (add[1] != 0) || (add[2] != 0)) { rc = out->info(out, "Local-only Change: %d.%d.%d", From e7ea3fb6c2708cc2b228113b340299585a7c8aeb Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 02:55:45 -0800 Subject: [PATCH 16/41] Test: cts-cli: Update outputs for "(no digest)" Signed-off-by: Reid Wahl --- cts/cli/regression.crm_shadow.exp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cts/cli/regression.crm_shadow.exp b/cts/cli/regression.crm_shadow.exp index bccf28bdb13..84fae0fdf17 100644 --- a/cts/cli/regression.crm_shadow.exp +++ b/cts/cli/regression.crm_shadow.exp @@ -743,7 +743,7 @@ cts-cli * Passed: crm_shadow - Get active shadow instance's diff (copied) (XML) =#=#=#= Begin test: Get active shadow instance's diff (after changes) =#=#=#= Diff: --- 1.1.173 2 -Diff: +++ 1.4.1 (null) +Diff: +++ 1.4.1 (no digest) -- /cib/configuration/op_defaults + /cib: @epoch=4, @num_updates=1 + /cib/configuration/resources/primitive[@id='dummy']: @description=desc @@ -800,7 +800,7 @@ To prevent accidental destruction of the cluster, the --force flag is required i * Passed: crm_shadow - Commit shadow instance (force) =#=#=#= Begin test: Get active shadow instance's diff (after commit) =#=#=#= Diff: --- 1.2.0 2 -Diff: +++ 1.4.1 (null) +Diff: +++ 1.4.1 (no digest) + /cib: @epoch=4, @num_updates=1 ++ /cib/status: =#=#=#= End test: Get active shadow instance's diff (after commit) - Error occurred (1) =#=#=#= @@ -810,7 +810,7 @@ Diff: +++ 1.4.1 (null) * Passed: crm_shadow - Commit shadow instance (force) (all) =#=#=#= Begin test: Get active shadow instance's diff (after commit all) =#=#=#= Diff: --- 1.4.2 2 -Diff: +++ 1.4.1 (null) +Diff: +++ 1.4.1 (no digest) + /cib: @num_updates=1 =#=#=#= End test: Get active shadow instance's diff (after commit all) - Error occurred (1) =#=#=#= * Passed: crm_shadow - Get active shadow instance's diff (after commit all) @@ -1353,7 +1353,7 @@ A new shadow instance was created. To begin using it, enter the following into y * Passed: crm_shadow - Get active shadow instance's contents (empty CIB) (XML) =#=#=#= Begin test: Get active shadow instance's diff (empty CIB) =#=#=#= Diff: --- 1.1.173 2 -Diff: +++ 0.1.0 (null) +Diff: +++ 0.1.0 (no digest) -- /cib/configuration/crm_config/cluster_property_set[@id='cib-bootstrap-options'] -- /cib/configuration/nodes/node[@id='1'] -- /cib/configuration/nodes/node[@id='2'] @@ -1446,7 +1446,7 @@ A new shadow instance was created. To begin using it, enter the following into y * Passed: crm_shadow - Active shadow instance no different from active CIB after reset =#=#=#= Begin test: Active shadow instance differs from active CIB after change =#=#=#= Diff: --- 1.1.173 2 -Diff: +++ 1.2.0 (null) +Diff: +++ 1.2.0 (no digest) + /cib: @epoch=2, @num_updates=0 ++ /cib/configuration/crm_config/cluster_property_set[@id='cib-bootstrap-options']: =#=#=#= End test: Active shadow instance differs from active CIB after change - Error occurred (1) =#=#=#= From 35fb26bb6c4257d2b708c29229777ea248109893 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 01:38:25 -0800 Subject: [PATCH 17/41] Refactor: libcib: Add digest in cib_perform_op if and only if tracing Checking the digest once per minute is an apparently arbitrary interval for sanity-checking. However, we don't actually USE the digest and do the check unless we're tracing (although we would log it at info level prior to this commit). Since we're almost never tracing, only add the digest if we're tracing. This lets us drop the expires/tm_now code. This functionality was added by commit 6a2ffe20 with no explanation beyond what's in the code comment. Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index d5796acde25..c31380e7aef 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -343,7 +343,6 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, const char *user = NULL; bool enable_acl = false; - bool with_digest = false; pcmk__assert((op != NULL) && (fn != NULL) && (req != NULL) && (config_changed != NULL) && (!*config_changed) @@ -482,16 +481,6 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, pcmk__strip_xml_text(working_cib); - if (make_copy) { - static time_t expires = 0; - time_t tm_now = time(NULL); - - if (expires < tm_now) { - expires = tm_now + 60; /* Validate clients are correctly applying v2-style diffs at most once a minute */ - with_digest = true; - } - } - local_diff = xml_create_patchset(0, patchset_cib, working_cib, config_changed, manage_counters); @@ -499,9 +488,6 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, pcmk__xml_commit_changes(working_cib->doc); if (local_diff != NULL) { - if (with_digest) { - pcmk__xml_patchset_add_digest(local_diff, working_cib); - } pcmk__log_xml_patchset(LOG_INFO, local_diff); pcmk__log_xml_trace(local_diff, "raw patch"); } @@ -515,6 +501,8 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, int format = 1; xmlNode *cib_copy = pcmk__xml_copy(NULL, patchset_cib); + pcmk__xml_patchset_add_digest(local_diff, working_cib); + pcmk__xe_get_int(local_diff, PCMK_XA_FORMAT, &format); test_rc = xml_apply_patchset(cib_copy, local_diff, manage_counters); From 5c6a51ef299562694a18f5e2876c88cac4d73a5f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 01:47:46 -0800 Subject: [PATCH 18/41] Refactor: libcib: Drop test apply-patchset when tracing cib_perform_op() In theory, this could be a nice sanity-check, to catch a mistake if we mess up xml_apply_patchset() or something related. In practice, we never enable tracing for cib_perform_op(), so we would never actually SEE an error here. By the time we've enabled tracing, we already know there's a problem. At that point, we can add tracing and recompile, or run under gdb, or whatever other debugging strategy we prefer. We don't need to leave all this tracing lying around just in case, when we're unlikely to ever use it. This tracing was introduced over the course of a few commits. c96c99ae and c55115d5 look like the main relevant ones. This may have been more relevant or useful when v2 patchsets were being developed and we may have been uncertain that they would work. Also drop a comment about v2 patchsets that probably hasn't been relevant since we dropped support for rolling upgrades from Pacemaker versions that create v1 patchsets. We only support v2. Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index c31380e7aef..6b5ca63e3d4 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -356,8 +356,6 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, make_copy = should_copy_cib(op, section, call_options); if (!make_copy) { - /* Conditional on v2 patch style */ - // Make a copy of the top-level element to store version details top = pcmk__xe_create(NULL, (const char *) (*current_cib)->name); pcmk__xe_copy_attrs(top, *current_cib, pcmk__xaf_none); @@ -492,41 +490,6 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, pcmk__log_xml_trace(local_diff, "raw patch"); } - if (make_copy && (local_diff != NULL)) { - // Original to compare against doesn't exist - pcmk__if_tracing( - { - // Validate the calculated patch set - int test_rc = pcmk_ok; - int format = 1; - xmlNode *cib_copy = pcmk__xml_copy(NULL, patchset_cib); - - pcmk__xml_patchset_add_digest(local_diff, working_cib); - - pcmk__xe_get_int(local_diff, PCMK_XA_FORMAT, &format); - test_rc = xml_apply_patchset(cib_copy, local_diff, - manage_counters); - - if (test_rc != pcmk_ok) { - pcmk__xml_write_temp_file(cib_copy, "PatchApply:calculated", - NULL); - pcmk__xml_write_temp_file(patchset_cib, "PatchApply:input", - NULL); - pcmk__xml_write_temp_file(working_cib, "PatchApply:actual", - NULL); - pcmk__xml_write_temp_file(local_diff, "PatchApply:diff", - NULL); - pcmk__err("v%d patchset error, patch failed to apply: %s " - "(%d)", - format, pcmk_rc_str(pcmk_legacy2rc(test_rc)), - test_rc); - } - pcmk__xml_free(cib_copy); - }, - {} - ); - } - /* working_cib must not be modified after this point, except for the * attributes for which pcmk__xa_filterable() returns true */ From d47dbf9e001a71dcf62e19a8b0a95206109500e4 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 01:58:57 -0800 Subject: [PATCH 19/41] Refactor: libcib: Drop make_copy variable After dropping some code, we now use the variable in only one place after setting it. Let's get rid of some more clutter. Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 6b5ca63e3d4..4d6963a5cc0 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -335,7 +335,6 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, xmlNode **output) { int rc = pcmk_rc_ok; - bool make_copy = true; xmlNode *top = NULL; xmlNode *working_cib = NULL; xmlNode *patchset_cib = NULL; @@ -353,9 +352,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, user = pcmk__xe_get(req, PCMK__XA_CIB_USER); enable_acl = cib_acl_enabled(*current_cib, user); - make_copy = should_copy_cib(op, section, call_options); - - if (!make_copy) { + if (!should_copy_cib(op, section, call_options)) { // Make a copy of the top-level element to store version details top = pcmk__xe_create(NULL, (const char *) (*current_cib)->name); pcmk__xe_copy_attrs(top, *current_cib, pcmk__xaf_none); @@ -512,7 +509,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, done: *result_cib = working_cib; - /* @TODO: This may not work correctly with !make_copy, since we don't + /* @TODO This may not work correctly when !should_copy_cib(), since we don't * keep the original CIB. */ if ((rc != pcmk_rc_ok) && cib_acl_enabled(patchset_cib, user) From 89b18578b208c630fa50252aa29de3835c3ebfef Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 02:50:24 -0800 Subject: [PATCH 20/41] Refactor: libcib: Functionize checking versions in cib_perform_op() Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 113 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 4d6963a5cc0..ccad38acd28 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -277,6 +277,92 @@ should_copy_cib(const char *op, const char *section, int call_options) return true; } +/*! + * \internal + * \brief Validate that a new CIB has a newer version attribute than an old CIB + * + * Return an error if the value of the given attribute is higher in the old CIB + * than in the new CIB. + * + * \param[in] attr Name of version attribute to check + * \param[in] old_cib \c PCMK_XE_CIB element before performing operation + * \param[in] new_cib \c PCMK_XE_CIB element from result of operation + * \param[in] request CIB request + * \param[in] input Input data for CIB request + * + * \return Standard Pacemaker return code + * + * \note \p old_cib only has to contain the top-level \c PCMK_XE_CIB element. It + * might not be a full CIB. + */ +static int +check_cib_version_attr(const char *attr, const xmlNode *old_cib, + const xmlNode *new_cib, const xmlNode *request, + const xmlNode *input) +{ + const char *op = pcmk__xe_get(request, PCMK__XA_CIB_OP); + int old_version = 0; + int new_version = 0; + + pcmk__xe_get_int(old_cib, attr, &old_version); + pcmk__xe_get_int(new_cib, attr, &new_version); + + if (old_version < new_version) { + return pcmk_rc_ok; + } + + if (old_version == new_version) { + return pcmk_rc_undetermined; + } + + pcmk__err("%s went backwards in %s request: %d -> %d", attr, op, + old_version, new_version); + pcmk__log_xml_warn(request, "bad-request"); + pcmk__log_xml_warn(input, "bad-input"); + + return pcmk_rc_old_data; +} + +/*! + * \internal + * \brief Validate that a new CIB has newer versions than an old CIB + * + * Return an error if: + * - \c PCMK_XA_ADMIN_EPOCH is newer in the old CIB than in the new CIB; or + * - The \c PCMK_XA_ADMIN_EPOCH attributes are equal and \c PCMK_XA_EPOCH is + * newer in the old CIB than in the new CIB. + * + * \param[in] old_cib \c PCMK_XE_CIB element before performing operation + * \param[in] new_cib \c PCMK_XE_CIB element from result of operation + * \param[in] request CIB request + * \param[in] input Input data for CIB request + * + * \return Standard Pacemaker return code + * + * \note \p old_cib only has to contain the top-level \c PCMK_XE_CIB element. It + * might not be a full CIB. + */ +static int +check_cib_versions(const xmlNode *old_cib, const xmlNode *new_cib, + const xmlNode *request, const xmlNode *input) +{ + int rc = check_cib_version_attr(PCMK_XA_ADMIN_EPOCH, old_cib, new_cib, + request, input); + + if (rc != pcmk_rc_undetermined) { + return rc; + } + + // @TODO Why aren't we checking PCMK_XA_NUM_UPDATES if epochs are equal? + rc = check_cib_version_attr(PCMK_XA_EPOCH, old_cib, new_cib, request, + input); + if (rc == pcmk_rc_undetermined) { + rc = pcmk_rc_ok; + } + + return rc; +} + /*! * \internal * \brief Set values for update origin host, client, and user in new CIB @@ -447,32 +533,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, } } - if (patchset_cib != NULL) { - int old = 0; - int new = 0; - - pcmk__xe_get_int(working_cib, PCMK_XA_ADMIN_EPOCH, &new); - pcmk__xe_get_int(patchset_cib, PCMK_XA_ADMIN_EPOCH, &old); - - if (old > new) { - pcmk__err("%s went backwards: %d -> %d (Opts: %#x)", - PCMK_XA_ADMIN_EPOCH, old, new, call_options); - pcmk__log_xml_warn(req, "Bad Op"); - pcmk__log_xml_warn(input, "Bad Data"); - rc = pcmk_rc_old_data; - - } else if (old == new) { - pcmk__xe_get_int(working_cib, PCMK_XA_EPOCH, &new); - pcmk__xe_get_int(patchset_cib, PCMK_XA_EPOCH, &old); - if (old > new) { - pcmk__err("%s went backwards: %d -> %d (Opts: %#x)", - PCMK_XA_EPOCH, old, new, call_options); - pcmk__log_xml_warn(req, "Bad Op"); - pcmk__log_xml_warn(input, "Bad Data"); - rc = pcmk_rc_old_data; - } - } - } + rc = check_cib_versions(patchset_cib, working_cib, req, input); pcmk__strip_xml_text(working_cib); From 885b4bb30bc3df726677014f73e7b0f0daf4304d Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 03:35:40 -0800 Subject: [PATCH 21/41] Refactor: libcib: Simplify some return-code handling in cib_perform_op() Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index ccad38acd28..296789438c8 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -501,17 +501,19 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, // Allow ourselves to make any additional necessary changes xml_acl_disable(working_cib); - if ((rc == pcmk_rc_ok) && (working_cib == NULL)) { + if (rc != pcmk_rc_ok) { + goto done; + } + + if (working_cib == NULL) { rc = EINVAL; goto done; + } - } else if ((rc == pcmk_rc_ok) && xml_acl_denied(working_cib)) { + if (xml_acl_denied(working_cib)) { pcmk__trace("ACL rejected part or all of the proposed changes"); rc = EACCES; goto done; - - } else if (rc != pcmk_rc_ok) { - goto done; } /* If the CIB is from a file, we don't need to check that the feature set is From 1bea489088e0e32c955541a8996bda50fe2fc485 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 03:37:40 -0800 Subject: [PATCH 22/41] Refactor: libcib: Drop redundant NULL check in cib_perform_op() We've already ensured that working_cib is not NULL. Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 296789438c8..64f1e14b56d 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -520,9 +520,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, * supported. All we care about in that case is the schema version, which * is checked elsewhere. */ - if ((working_cib != NULL) - && ((cib == NULL) || (cib->variant != cib_file))) { - + if ((cib == NULL) || (cib->variant != cib_file)) { const char *new_version = pcmk__xe_get(working_cib, PCMK_XA_CRM_FEATURE_SET); From 3913201e644facbf1f810e3b607ec8b5526a78ef Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 03:44:24 -0800 Subject: [PATCH 23/41] Refactor: libcib: cib_perform_op() takes enum cib_variant arg It wasn't using the cib_t * argument for anything except checking the variant. Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 12 ++++++++---- include/crm/cib/internal.h | 10 +++++----- lib/cib/cib_file.c | 2 +- lib/cib/cib_utils.c | 4 ++-- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index 48d4a9f31a7..5641a168711 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -628,10 +628,14 @@ cib_process_command(xmlNode *request, const cib__operation_t *operation, ping_modified_since = true; - // result_cib must not be modified after cib_perform_op() returns - rc = cib_perform_op(NULL, op, call_options, op_function, section, request, - input, manage_counters, &config_changed, &the_cib, - &result_cib, &cib_diff, &output); + /* result_cib must not be modified after cib_perform_op() returns. + * + * It's not important whether the client variant is cib_native or + * cib_remote. + */ + rc = cib_perform_op(cib_undefined, op, call_options, op_function, section, + request, input, manage_counters, &config_changed, + &the_cib, &result_cib, &cib_diff, &output); /* Always write to disk for successful ops with the flag set. This also * negates the need to detect ordering changes. diff --git a/include/crm/cib/internal.h b/include/crm/cib/internal.h index 2220307497e..29f0aa6110f 100644 --- a/include/crm/cib/internal.h +++ b/include/crm/cib/internal.h @@ -184,11 +184,11 @@ int cib__perform_query(const char *op, uint32_t call_options, cib__op_fn_t fn, const char *section, xmlNode *req, xmlNode *input, xmlNode **current_cib, xmlNode **output); -int cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, - cib__op_fn_t fn, const char *section, xmlNode *req, - xmlNode *input, bool manage_counters, bool *config_changed, - xmlNode **current_cib, xmlNode **result_cib, xmlNode **diff, - xmlNode **output); +int cib_perform_op(enum cib_variant variant, const char *op, + uint32_t call_options, cib__op_fn_t fn, const char *section, + xmlNode *req, xmlNode *input, bool manage_counters, + bool *config_changed, xmlNode **current_cib, + xmlNode **result_cib, xmlNode **diff, xmlNode **output); int cib__create_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, int call_options, diff --git a/lib/cib/cib_file.c b/lib/cib/cib_file.c index a9bbf9246e8..b397ae70736 100644 --- a/lib/cib/cib_file.c +++ b/lib/cib/cib_file.c @@ -180,7 +180,7 @@ process_request(cib_t *cib, xmlNode *request, xmlNode **output) rc = cib__perform_query(op, call_options, op_function, section, request, data, &private->cib_xml, output); } else { - rc = cib_perform_op(cib, op, call_options, op_function, section, + rc = cib_perform_op(cib_file, op, call_options, op_function, section, request, data, true, &changed, &private->cib_xml, &result_cib, &cib_diff, output); } diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 64f1e14b56d..48ef4f4f8ba 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -414,7 +414,7 @@ set_update_origin(xmlNode *new_cib, const xmlNode *request) } int -cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, +cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, cib__op_fn_t fn, const char *section, xmlNode *req, xmlNode *input, bool manage_counters, bool *config_changed, xmlNode **current_cib, xmlNode **result_cib, xmlNode **diff, @@ -520,7 +520,7 @@ cib_perform_op(cib_t *cib, const char *op, uint32_t call_options, * supported. All we care about in that case is the schema version, which * is checked elsewhere. */ - if ((cib == NULL) || (cib->variant != cib_file)) { + if (variant != cib_file) { const char *new_version = pcmk__xe_get(working_cib, PCMK_XA_CRM_FEATURE_SET); From 5b788c7c2e1db0b35d42d8e1858cae7215c8f0bb Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 03:53:16 -0800 Subject: [PATCH 24/41] Refactor: libcib: Functionize checking new feature set in cib_perform_op Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 48ef4f4f8ba..67d8823fc4b 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -277,6 +277,31 @@ should_copy_cib(const char *op, const char *section, int call_options) return true; } +/*! + * \internal + * \brief Validate that a new CIB's feature set is not newer than ours + * + * Return an error if the new CIB's feature set is newer than ours. + * + * \param[in] new_cib Result CIB after performing operation + * + * \return Standard Pacemaker return code + */ +static int +check_new_feature_set(const xmlNode *new_cib) +{ + const char *new_version = pcmk__xe_get(new_cib, PCMK_XA_CRM_FEATURE_SET); + int rc = pcmk__check_feature_set(new_version); + + if (rc == pcmk_rc_ok) { + return pcmk_rc_ok; + } + + pcmk__err("Discarding update with feature set %s greater than our own (%s)", + new_version, CRM_FEATURE_SET); + return rc; +} + /*! * \internal * \brief Validate that a new CIB has a newer version attribute than an old CIB @@ -521,14 +546,8 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, * is checked elsewhere. */ if (variant != cib_file) { - const char *new_version = pcmk__xe_get(working_cib, - PCMK_XA_CRM_FEATURE_SET); - - rc = pcmk__check_feature_set(new_version); + rc = check_new_feature_set(working_cib); if (rc != pcmk_rc_ok) { - pcmk__err("Discarding update with feature set '%s' greater than " - "our own '%s'", - new_version, CRM_FEATURE_SET); goto done; } } From 2a079827ac3cb99161c0931d53d74dcea7df6fa9 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 04:00:00 -0800 Subject: [PATCH 25/41] API: libcrmcommon: xml_create_patchset() source argument is now const Signed-off-by: Reid Wahl --- include/crm/common/xml.h | 4 ++-- lib/common/patchset.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/crm/common/xml.h b/include/crm/common/xml.h index b5a5b08f0e5..ceb6cddf390 100644 --- a/include/crm/common/xml.h +++ b/include/crm/common/xml.h @@ -33,8 +33,8 @@ extern "C" { * undeprecated until we create replacements */ -xmlNode *xml_create_patchset( - int format, xmlNode *source, xmlNode *target, bool *config, bool manage_version); +xmlNode *xml_create_patchset(int format, const xmlNode *source, xmlNode *target, + bool *config, bool manage_version); int xml_apply_patchset(xmlNode *xml, const xmlNode *patchset, bool check_version); diff --git a/lib/common/patchset.c b/lib/common/patchset.c index f4a25d38f30..a6063a9dc43 100644 --- a/lib/common/patchset.c +++ b/lib/common/patchset.c @@ -181,7 +181,7 @@ is_config_change(xmlNode *xml) } static xmlNode * -xml_create_patchset_v2(xmlNode *source, xmlNode *target) +xml_create_patchset_v2(const xmlNode *source, xmlNode *target) { int lpc = 0; GList *gIter = NULL; @@ -241,7 +241,7 @@ xml_create_patchset_v2(xmlNode *source, xmlNode *target) } xmlNode * -xml_create_patchset(int format, xmlNode *source, xmlNode *target, +xml_create_patchset(int format, const xmlNode *source, xmlNode *target, bool *config_changed, bool manage_version) { bool local_config_changed = false; From b5e5a00e63b89433bc9dea4ee15d323dc378d0cf Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 04:06:36 -0800 Subject: [PATCH 26/41] Refactor: libcib: Clarify patchset_cib variable And rename it to old_versions. Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 67d8823fc4b..5bea0aed8f1 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -446,9 +446,15 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, xmlNode **output) { int rc = pcmk_rc_ok; + + /* PCMK_XE_CIB element containing version numbers from before the operation. + * This may or may not point to a full CIB XML tree. Do not free, as this + * will be used as an alias for another pointer. + */ + xmlNode *old_versions = NULL; + xmlNode *top = NULL; xmlNode *working_cib = NULL; - xmlNode *patchset_cib = NULL; xmlNode *local_diff = NULL; const char *user = NULL; @@ -467,7 +473,7 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, // Make a copy of the top-level element to store version details top = pcmk__xe_create(NULL, (const char *) (*current_cib)->name); pcmk__xe_copy_attrs(top, *current_cib, pcmk__xaf_none); - patchset_cib = top; + old_versions = top; pcmk__xml_commit_changes((*current_cib)->doc); pcmk__xml_doc_set_flags((*current_cib)->doc, pcmk__xf_tracking); @@ -494,7 +500,7 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, } else { working_cib = pcmk__xml_copy(NULL, *current_cib); - patchset_cib = *current_cib; + old_versions = *current_cib; pcmk__xml_doc_set_flags(working_cib->doc, pcmk__xf_tracking); if (enable_acl) { @@ -552,11 +558,14 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, } } - rc = check_cib_versions(patchset_cib, working_cib, req, input); + rc = check_cib_versions(old_versions, working_cib, req, input); pcmk__strip_xml_text(working_cib); - local_diff = xml_create_patchset(0, patchset_cib, working_cib, + /* If we didn't make a copy, the diff will only be accurate for the + * top-level PCMK_XE_CIB element + */ + local_diff = xml_create_patchset(0, old_versions, working_cib, config_changed, manage_counters); pcmk__log_xml_changes(LOG_TRACE, working_cib); @@ -592,8 +601,8 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, /* @TODO This may not work correctly when !should_copy_cib(), since we don't * keep the original CIB. */ - if ((rc != pcmk_rc_ok) && cib_acl_enabled(patchset_cib, user) - && xml_acl_filtered_copy(user, patchset_cib, working_cib, result_cib)) { + if ((rc != pcmk_rc_ok) && cib_acl_enabled(old_versions, user) + && xml_acl_filtered_copy(user, old_versions, working_cib, result_cib)) { if (*result_cib == NULL) { pcmk__debug("Pre-filtered the entire cib result"); From 2d6631d51223b1107f74ae908b29f974e3765b0f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 23:27:41 -0800 Subject: [PATCH 27/41] Refactor: libcib: Assert on NULL diff in cib_perform_op() Both callers currently always pass a non-NULL diff argument. Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 5bea0aed8f1..069960c3489 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -455,7 +455,6 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, xmlNode *top = NULL; xmlNode *working_cib = NULL; - xmlNode *local_diff = NULL; const char *user = NULL; bool enable_acl = false; @@ -464,6 +463,7 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, && (config_changed != NULL) && (!*config_changed) && (current_cib != NULL) && (*current_cib != NULL) && (result_cib != NULL) && (*result_cib == NULL) + && (diff != NULL) && (*diff == NULL) && (output != NULL) && (*output == NULL)); user = pcmk__xe_get(req, PCMK__XA_CIB_USER); @@ -565,15 +565,15 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, /* If we didn't make a copy, the diff will only be accurate for the * top-level PCMK_XE_CIB element */ - local_diff = xml_create_patchset(0, old_versions, working_cib, - config_changed, manage_counters); + *diff = xml_create_patchset(0, old_versions, working_cib, config_changed, + manage_counters); pcmk__log_xml_changes(LOG_TRACE, working_cib); pcmk__xml_commit_changes(working_cib->doc); - if (local_diff != NULL) { - pcmk__log_xml_patchset(LOG_INFO, local_diff); - pcmk__log_xml_trace(local_diff, "raw patch"); + if (*diff != NULL) { + pcmk__log_xml_patchset(LOG_INFO, *diff); + pcmk__log_xml_trace(*diff, "raw patch"); } /* working_cib must not be modified after this point, except for the @@ -610,12 +610,6 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, pcmk__xml_free(working_cib); } - if(diff) { - *diff = local_diff; - } else { - pcmk__xml_free(local_diff); - } - pcmk__xml_free(top); pcmk__trace("Done"); return rc; From fe8973e035fa6b5909329788a8b5040dbfa9b3d4 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 31 Dec 2025 23:50:20 -0800 Subject: [PATCH 28/41] Refactor: libcrmcommon: Drop redundant check in xml_create_patchset_v2() This is a static function with one caller (xml_create_patchset()), which already checks whether the doc has the dirty flag set. This lets us clearly make two guarantees: * xml_create_patchset_v2() returns non-NULL. * xml_create_patchset() doesn't change *config_changed if its return value is NULL. Signed-off-by: Reid Wahl --- lib/common/patchset.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/common/patchset.c b/lib/common/patchset.c index a6063a9dc43..eeed17d54ee 100644 --- a/lib/common/patchset.c +++ b/lib/common/patchset.c @@ -180,6 +180,7 @@ is_config_change(xmlNode *xml) return FALSE; } +// Guaranteed to return non-NULL static xmlNode * xml_create_patchset_v2(const xmlNode *source, xmlNode *target) { @@ -192,11 +193,6 @@ xml_create_patchset_v2(const xmlNode *source, xmlNode *target) xmlNode *patchset = NULL; pcmk__assert(target != NULL); - - if (!pcmk__xml_doc_all_flags_set(target->doc, pcmk__xf_dirty)) { - return NULL; - } - pcmk__assert(target->doc != NULL); docpriv = target->doc->_private; @@ -240,6 +236,7 @@ xml_create_patchset_v2(const xmlNode *source, xmlNode *target) return patchset; } +// *config_changed is unchanged if the return value is NULL xmlNode * xml_create_patchset(int format, const xmlNode *source, xmlNode *target, bool *config_changed, bool manage_version) From 901f78f2ac8f7e2d48b6cf96ed3898f0ccf28f2f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 00:03:53 -0800 Subject: [PATCH 29/41] Refactor: libcib: goto done if *diff is NULL in cib_perform_op() If *diff is NULL, then nothing changed. There's nothing to log, *config_changed will be false, and there's no reason to validate against the schema. Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 069960c3489..fa5fe357473 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -1,6 +1,6 @@ /* * Original copyright 2004 International Business Machines - * Later changes copyright 2008-2025 the Pacemaker project contributors + * Later changes copyright 2008-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -568,13 +568,20 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, *diff = xml_create_patchset(0, old_versions, working_cib, config_changed, manage_counters); + if (*diff == NULL) { + // pcmk__xml_commit_changes() resets document private data + pcmk__xml_commit_changes(working_cib->doc); + + // If nothing changed, nothing else to do + goto done; + } + + // Committing changes removes attrs marked as deleted, so log first pcmk__log_xml_changes(LOG_TRACE, working_cib); pcmk__xml_commit_changes(working_cib->doc); - if (*diff != NULL) { - pcmk__log_xml_patchset(LOG_INFO, *diff); - pcmk__log_xml_trace(*diff, "raw patch"); - } + pcmk__log_xml_patchset(LOG_INFO, *diff); + pcmk__log_xml_trace(*diff, "raw patch"); /* working_cib must not be modified after this point, except for the * attributes for which pcmk__xa_filterable() returns true From fa3caba44d649a73d201115c98142ad4c40248c4 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 00:17:15 -0800 Subject: [PATCH 30/41] Log: libcib: Drop logging XML changes and raw patchset in cib_perform_op I don't see any reason to log these. We already log the patchset at info level using pcmk__log_xml_patchset(). Unless there's something wrong with patchset creation or logging, the (pretty) patchset logs make the change logs and raw patchset logs redundant. They contain the same info. We're not going to have tracing enabled unless we're trying to troubleshoot something. Those particular trace logs aren't going to be helpful unless we're specifically trying to troubleshoot patchset creation or logging. If that's the case, then we can add logging lines and recompile as needed. Whatever the issue is with patchset creation/logging, it ought to be reproducible for developers. Also drop patchset logging in the callers. Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 2 -- lib/cib/cib_file.c | 4 +--- lib/cib/cib_utils.c | 4 ---- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index 5641a168711..4ba03c4000b 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -699,8 +699,6 @@ cib_process_command(xmlNode *request, const cib__operation_t *operation, client_name, originator, cib_diff); } - pcmk__log_xml_patchset(LOG_TRACE, cib_diff); - done: if (!pcmk__is_set(call_options, cib_discard_reply)) { *reply = create_cib_reply(op, call_id, client_id, call_options, diff --git a/lib/cib/cib_file.c b/lib/cib/cib_file.c index b397ae70736..310ffdd0cca 100644 --- a/lib/cib/cib_file.c +++ b/lib/cib/cib_file.c @@ -1,6 +1,6 @@ /* * Original copyright 2004 International Business Machines - * Later changes copyright 2008-2025 the Pacemaker project contributors + * Later changes copyright 2008-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -197,8 +197,6 @@ process_request(cib_t *cib, xmlNode *request, xmlNode **output) pcmk__validate_xml(result_cib, NULL, NULL, NULL); } else if ((rc == pcmk_rc_ok) && !read_only) { - pcmk__log_xml_patchset(LOG_DEBUG, cib_diff); - if (result_cib != private->cib_xml) { pcmk__xml_free(private->cib_xml); private->cib_xml = result_cib; diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index fa5fe357473..6b587bad8e8 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -576,12 +576,8 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, goto done; } - // Committing changes removes attrs marked as deleted, so log first - pcmk__log_xml_changes(LOG_TRACE, working_cib); pcmk__xml_commit_changes(working_cib->doc); - pcmk__log_xml_patchset(LOG_INFO, *diff); - pcmk__log_xml_trace(*diff, "raw patch"); /* working_cib must not be modified after this point, except for the * attributes for which pcmk__xa_filterable() returns true From c9f2d4c92604b32f6345f451d593d4593e048f3d Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 00:07:59 -0800 Subject: [PATCH 31/41] Refactor: libcib: Move pcmk__xml_commit_changes() call Signed-off-by: Reid Wahl --- lib/cib/cib_utils.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 6b587bad8e8..387a130660b 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -568,15 +568,15 @@ cib_perform_op(enum cib_variant variant, const char *op, uint32_t call_options, *diff = xml_create_patchset(0, old_versions, working_cib, config_changed, manage_counters); - if (*diff == NULL) { - // pcmk__xml_commit_changes() resets document private data - pcmk__xml_commit_changes(working_cib->doc); + /* pcmk__xml_commit_changes() resets document private data, so call it even + * if there were no changes. + */ + pcmk__xml_commit_changes(working_cib->doc); - // If nothing changed, nothing else to do + if (*diff == NULL) { goto done; } - pcmk__xml_commit_changes(working_cib->doc); pcmk__log_xml_patchset(LOG_INFO, *diff); /* working_cib must not be modified after this point, except for the From eaa66bd397b9fce1d27fd4efef762bd671f949cd Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 20:21:33 -0800 Subject: [PATCH 32/41] Refactor: based: Drop dead code for PCMK__XA_CIB_UPDATE If we reached the dropped "if" block, then op is not PCMK__CIB_REQUEST_REPLACE. That was tested by the first "if" block. But as of Pacemaker 2.0.0, PCMK__XA_CIB_UPDATE can be true only if the op is PCMK__CIB_REQUEST_REPLACE (it's set by sync_our_cib()), unless there's an even older node in the cluster that would cause the CIB manager to run in legacy mode. (See broadcast argument of send_peer_reply() in 2.0.0.) However, rolling upgrades from versions earlier than 2.0.0 are no longer supported, so that's not a concern. Similarly, we can drop PCMK__CIB_REQUEST_APPLY_PATCH from the CRM_LOG_ASSERT() call. Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index 4ba03c4000b..1bbacdc7fc2 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -416,11 +416,6 @@ parse_peer_options(const cib__operation_t *operation, xmlNode *request, return false; } - } else if (pcmk__xe_attr_is_true(request, PCMK__XA_CIB_UPDATE)) { - pcmk__info("Detected legacy %s global update from %s", op, originator); - send_sync_request(); - return false; - } else if (is_reply && pcmk__is_set(operation->flags, cib__op_attr_modifies)) { @@ -615,15 +610,14 @@ cib_process_command(xmlNode *request, const cib__operation_t *operation, /* @COMPAT: Handle a valid write action (legacy) * - * @TODO: Re-evaluate whether this is all truly legacy. PCMK__XA_CIB_UPDATE - * may be set by a sync operation even in non-legacy mode, and - * manage_counters tells xml_create_patchset() whether to update - * version/epoch info. + * @TODO: Re-evaluate whether this is truly legacy. PCMK__XA_CIB_UPDATE may + * be set by a sync operation even in non-legacy mode, and manage_counters + * tells xml_create_patchset() whether to update version/epoch info. */ if (pcmk__xe_attr_is_true(request, PCMK__XA_CIB_UPDATE)) { manage_counters = false; - CRM_LOG_ASSERT(pcmk__str_any_of(op, PCMK__CIB_REQUEST_APPLY_PATCH, - PCMK__CIB_REQUEST_REPLACE, NULL)); + CRM_LOG_ASSERT(pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE, + pcmk__str_none)); } ping_modified_since = true; From d32f2842270ede534aa0a5f31a247fb5d18dc4bb Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 21:04:12 -0800 Subject: [PATCH 33/41] Refactor: based: Drop based_process_apply_patch, send_sync_request, etc. All of this is legacy code based on the legacy mode (pre-Pacemaker-1.1.12) sync process. We maintained support for that until Pacemaker 3.0.0, enabling it if any node in the cluster was running a Pacemaker earlier than 1.1.12, because we supported rolling upgrades from 1.1.11 to 2.y.z. We removed that support in 3.0.0, however. You can see a call to send_peer_reply() with broadcast=TRUE guarded by "if (cib_legacy_mode() ...)" from 1.1.13 through the latest 2.y.z. That's the PCMK__CIB_REQUEST_APPLY_PATCH/CIB_OP_APPLY_DIFF request that this dropped code was dealing with. Back then, a CIB manager itself would send an apply-patch request. pcmk_rc_diff_resync means that the source version (not the target version) in the patchset is newer than our current CIB version. So the idea was apparently that we received a sync request from a node with a newer CIB, and we didn't want to apply it before first getting the newer CIB ourselves. However, outside of legacy mode (which we dropped in 3.0.0), cibadmin is the only thing that sends an apply-patch request. cib__process_apply_diff() simply calls xml_apply_patchset() with check_version=true and returns the result. That's all we need in the CIB manager, now that we know that the request is coming from a client rather than from a peer. Failure to process a user-submitted patchset doesn't affect our ability to keep correct cluster state. We don't need to request a resync (via send_sync_request()); we can just fail, and the user can submit a new patchset with compatible versions. Since send_sync_request() is the only thing that sets sync_in_progress from 0 to a nonzero value, all of the other supporting code is dead and can be removed if we're dropping send_sync_request(). Note: this enables more changes, which will follow in upcoming commits. Signed-off-by: Reid Wahl --- daemons/based/based_messages.c | 78 +-------------------------------- daemons/based/based_messages.h | 3 +- daemons/based/based_operation.c | 2 +- 3 files changed, 3 insertions(+), 80 deletions(-) diff --git a/daemons/based/based_messages.c b/daemons/based/based_messages.c index 62e25de6488..d94d3758d6d 100644 --- a/daemons/based/based_messages.c +++ b/daemons/based/based_messages.c @@ -29,18 +29,10 @@ #include "pacemaker-based.h" -/* Maximum number of diffs to ignore while waiting for a resync */ -#define MAX_DIFF_RETRY 5 - bool based_is_primary = false; xmlNode *the_cib = NULL; -/* Set to 1 when a sync is requested, incremented when a diff is ignored, - * reset to 0 when a sync is received - */ -static int sync_in_progress = 0; - /*! * \internal * \brief Process a \c PCMK__CIB_REQUEST_ABS_DELETE @@ -68,51 +60,6 @@ based_process_abs_delete(const char *op, int options, const char *section, return EINVAL; } -int -based_process_apply_patch(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode **cib, - xmlNode **answer) -{ - int rc = pcmk_rc_ok; - - if (sync_in_progress > MAX_DIFF_RETRY) { - /* Don't ignore diffs forever; the last request may have been lost. - * If the diff fails, we'll ask for another full resync. - */ - sync_in_progress = 0; - } - - // The primary instance should never ignore a diff - if (sync_in_progress && !based_is_primary) { - int source[] = { 0, 0, 0 }; - int target[] = { 0, 0, 0 }; - - pcmk__xml_patchset_versions(input, source, target); - - sync_in_progress++; - pcmk__notice("Not applying diff %d.%d.%d -> %d.%d.%d (sync in " - "progress)", - source[0], source[1], source[2], - target[0], target[1], target[2]); - return pcmk_rc_diff_resync; - } - - rc = cib__process_apply_patch(op, options, section, req, input, cib, - answer); - pcmk__trace("result: %s (%d), %s", pcmk_rc_str(rc), rc, - (based_is_primary? "primary": "secondary")); - - if ((rc == pcmk_rc_diff_resync) && !based_is_primary) { - g_clear_pointer(cib, pcmk__xml_free); - send_sync_request(); - - } else if (rc == pcmk_rc_diff_resync) { - rc = pcmk_rc_diff_failed; - } - - return rc; -} - int based_process_commit_transact(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, @@ -235,13 +182,7 @@ based_process_replace(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer) { - int rc = cib__process_replace(op, options, section, req, input, cib, - answer); - - if ((rc == pcmk_rc_ok) && pcmk__xe_is(input, PCMK_XE_CIB)) { - sync_in_progress = 0; - } - return rc; + return cib__process_replace(op, options, section, req, input, cib, answer); } int @@ -440,23 +381,6 @@ based_process_upgrade(const char *op, int options, const char *section, return rc; } -void -send_sync_request(void) -{ - xmlNode *sync_me = pcmk__xe_create(NULL, "sync-me"); - pcmk__node_status_t *peer = NULL; - - pcmk__info("Requesting re-sync from all peers"); - sync_in_progress = 1; - - pcmk__xe_set(sync_me, PCMK__XA_T, PCMK__VALUE_CIB); - pcmk__xe_set(sync_me, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_SYNC_TO_ONE); - pcmk__xe_set(sync_me, PCMK__XA_CIB_DELEGATED_FROM, OUR_NODENAME); - - pcmk__cluster_send_message(peer, pcmk_ipc_based, sync_me); - pcmk__xml_free(sync_me); -} - static xmlNode * cib_msg_copy(xmlNode *msg) { diff --git a/daemons/based/based_messages.h b/daemons/based/based_messages.h index 2cae380e8e6..cb5100f9e37 100644 --- a/daemons/based/based_messages.h +++ b/daemons/based/based_messages.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -74,7 +74,6 @@ int based_process_upgrade(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); -void send_sync_request(void); int sync_our_cib(xmlNode *request, bool all); #endif // BASED_MESSAGES__H diff --git a/daemons/based/based_operation.c b/daemons/based/based_operation.c index 9189a374354..fa9b387d0bf 100644 --- a/daemons/based/based_operation.c +++ b/daemons/based/based_operation.c @@ -18,7 +18,7 @@ static const cib__op_fn_t op_functions[] = { [cib__op_abs_delete] = based_process_abs_delete, - [cib__op_apply_patch] = based_process_apply_patch, + [cib__op_apply_patch] = cib__process_apply_patch, [cib__op_bump] = cib__process_bump, [cib__op_commit_transact] = based_process_commit_transact, [cib__op_create] = cib__process_create, From cf016f8624b08413ed88041b5a7d093532ecaa22 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 21:28:58 -0800 Subject: [PATCH 34/41] Refactor: based: Drop based_process_replace() All it did immediately prior to this commit was to call cib__process_replace(). Signed-off-by: Reid Wahl --- daemons/based/based_messages.c | 8 -------- daemons/based/based_messages.h | 4 ---- daemons/based/based_operation.c | 2 +- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/daemons/based/based_messages.c b/daemons/based/based_messages.c index d94d3758d6d..4eacd740db0 100644 --- a/daemons/based/based_messages.c +++ b/daemons/based/based_messages.c @@ -177,14 +177,6 @@ based_process_primary(const char *op, int options, const char *section, return pcmk_rc_ok; } -int -based_process_replace(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode **cib, - xmlNode **answer) -{ - return cib__process_replace(op, options, section, req, input, cib, answer); -} - int based_process_schemas(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, diff --git a/daemons/based/based_messages.h b/daemons/based/based_messages.h index cb5100f9e37..087723e88df 100644 --- a/daemons/based/based_messages.h +++ b/daemons/based/based_messages.h @@ -46,10 +46,6 @@ int based_process_primary(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); -int based_process_replace(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode **cib, - xmlNode **answer); - int based_process_schemas(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); diff --git a/daemons/based/based_operation.c b/daemons/based/based_operation.c index fa9b387d0bf..fdf6baae86a 100644 --- a/daemons/based/based_operation.c +++ b/daemons/based/based_operation.c @@ -30,7 +30,7 @@ static const cib__op_fn_t op_functions[] = { [cib__op_ping] = based_process_ping, [cib__op_primary] = based_process_primary, [cib__op_query] = cib__process_query, - [cib__op_replace] = based_process_replace, + [cib__op_replace] = cib__process_replace, [cib__op_schemas] = based_process_schemas, [cib__op_secondary] = based_process_secondary, [cib__op_shutdown] = based_process_shutdown, From 367e6c8f43895948e73a83938c0e7e434634955b Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 21:32:55 -0800 Subject: [PATCH 35/41] Refactor: libcib, based: Drop cib__op_sync_to_one and related things Nothing makes a "sync to one" request anymore since we dropped send_sync_request(). Signed-off-by: Reid Wahl --- daemons/based/based_messages.c | 8 -------- daemons/based/based_messages.h | 4 ---- daemons/based/based_operation.c | 1 - include/crm/cib/internal.h | 2 -- lib/cib/cib_ops.c | 4 ---- 5 files changed, 19 deletions(-) diff --git a/daemons/based/based_messages.c b/daemons/based/based_messages.c index 4eacd740db0..56c71c05647 100644 --- a/daemons/based/based_messages.c +++ b/daemons/based/based_messages.c @@ -271,14 +271,6 @@ based_process_sync_to_all(const char *op, int options, const char *section, return sync_our_cib(req, true); } -int -based_process_sync_to_one(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode **cib, - xmlNode **answer) -{ - return sync_our_cib(req, false); -} - int based_process_upgrade(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, diff --git a/daemons/based/based_messages.h b/daemons/based/based_messages.h index 087723e88df..41d91dd3a3e 100644 --- a/daemons/based/based_messages.h +++ b/daemons/based/based_messages.h @@ -62,10 +62,6 @@ int based_process_sync_to_all(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); -int based_process_sync_to_one(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode **cib, - xmlNode **answer); - int based_process_upgrade(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); diff --git a/daemons/based/based_operation.c b/daemons/based/based_operation.c index fdf6baae86a..7a19622aedf 100644 --- a/daemons/based/based_operation.c +++ b/daemons/based/based_operation.c @@ -35,7 +35,6 @@ static const cib__op_fn_t op_functions[] = { [cib__op_secondary] = based_process_secondary, [cib__op_shutdown] = based_process_shutdown, [cib__op_sync_to_all] = based_process_sync_to_all, - [cib__op_sync_to_one] = based_process_sync_to_one, [cib__op_upgrade] = based_process_upgrade, }; diff --git a/include/crm/cib/internal.h b/include/crm/cib/internal.h index 29f0aa6110f..8c021f66cb8 100644 --- a/include/crm/cib/internal.h +++ b/include/crm/cib/internal.h @@ -24,7 +24,6 @@ extern "C" { #define PCMK__CIB_REQUEST_SECONDARY "cib_slave" #define PCMK__CIB_REQUEST_PRIMARY "cib_master" #define PCMK__CIB_REQUEST_SYNC_TO_ALL "cib_sync" -#define PCMK__CIB_REQUEST_SYNC_TO_ONE "cib_sync_one" #define PCMK__CIB_REQUEST_IS_PRIMARY "cib_ismaster" #define PCMK__CIB_REQUEST_BUMP "cib_bump" #define PCMK__CIB_REQUEST_QUERY "cib_query" @@ -91,7 +90,6 @@ enum cib__op_type { cib__op_secondary, cib__op_shutdown, cib__op_sync_to_all, - cib__op_sync_to_one, cib__op_upgrade, }; diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c index 2c0b2752e97..4558707ad1f 100644 --- a/lib/cib/cib_ops.c +++ b/lib/cib/cib_ops.c @@ -121,10 +121,6 @@ static const cib__operation_t cib_ops[] = { PCMK__CIB_REQUEST_SYNC_TO_ALL, cib__op_sync_to_all, cib__op_attr_privileged }, - { - PCMK__CIB_REQUEST_SYNC_TO_ONE, cib__op_sync_to_one, - cib__op_attr_privileged - }, { PCMK__CIB_REQUEST_UPGRADE, cib__op_upgrade, cib__op_attr_modifies From 8e21f8702068a0c25c88f1bbe105f1a49cccd21a Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 21:37:17 -0800 Subject: [PATCH 36/41] Refactor: libcib: Rename *_sync_to_all to *_sync We removed *_sync_to_one in a previous commit, so there is no longer any ambiguity. Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 4 ++-- daemons/based/based_messages.c | 6 +++--- daemons/based/based_messages.h | 6 +++--- daemons/based/based_operation.c | 2 +- include/crm/cib/internal.h | 4 ++-- lib/cib/cib_client.c | 6 +++--- lib/cib/cib_ops.c | 3 +-- 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index 1bbacdc7fc2..d492ad6cab5 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -371,9 +371,9 @@ parse_peer_options(const cib__operation_t *operation, xmlNode *request, delegated = reply_to; } goto skip_is_reply; + } - } else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_SYNC_TO_ALL, - pcmk__str_none)) { + if (pcmk__str_eq(op, PCMK__CIB_REQUEST_SYNC, pcmk__str_none)) { // Nothing to do } else if (is_reply && pcmk__str_eq(op, CRM_OP_PING, pcmk__str_casei)) { diff --git a/daemons/based/based_messages.c b/daemons/based/based_messages.c index 56c71c05647..e21544a43b1 100644 --- a/daemons/based/based_messages.c +++ b/daemons/based/based_messages.c @@ -264,9 +264,9 @@ based_process_shutdown(const char *op, int options, const char *section, } int -based_process_sync_to_all(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode **cib, - xmlNode **answer) +based_process_sync(const char *op, int options, const char *section, + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer) { return sync_our_cib(req, true); } diff --git a/daemons/based/based_messages.h b/daemons/based/based_messages.h index 41d91dd3a3e..a3e986536d2 100644 --- a/daemons/based/based_messages.h +++ b/daemons/based/based_messages.h @@ -58,9 +58,9 @@ int based_process_shutdown(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, xmlNode **answer); -int based_process_sync_to_all(const char *op, int options, const char *section, - xmlNode *req, xmlNode *input, xmlNode **cib, - xmlNode **answer); +int based_process_sync(const char *op, int options, const char *section, + xmlNode *req, xmlNode *input, xmlNode **cib, + xmlNode **answer); int based_process_upgrade(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode **cib, diff --git a/daemons/based/based_operation.c b/daemons/based/based_operation.c index 7a19622aedf..04d1c5417e8 100644 --- a/daemons/based/based_operation.c +++ b/daemons/based/based_operation.c @@ -34,7 +34,7 @@ static const cib__op_fn_t op_functions[] = { [cib__op_schemas] = based_process_schemas, [cib__op_secondary] = based_process_secondary, [cib__op_shutdown] = based_process_shutdown, - [cib__op_sync_to_all] = based_process_sync_to_all, + [cib__op_sync] = based_process_sync, [cib__op_upgrade] = based_process_upgrade, }; diff --git a/include/crm/cib/internal.h b/include/crm/cib/internal.h index 8c021f66cb8..6eaf1516d7d 100644 --- a/include/crm/cib/internal.h +++ b/include/crm/cib/internal.h @@ -23,7 +23,7 @@ extern "C" { // Request types for CIB manager IPC/CPG #define PCMK__CIB_REQUEST_SECONDARY "cib_slave" #define PCMK__CIB_REQUEST_PRIMARY "cib_master" -#define PCMK__CIB_REQUEST_SYNC_TO_ALL "cib_sync" +#define PCMK__CIB_REQUEST_SYNC "cib_sync" #define PCMK__CIB_REQUEST_IS_PRIMARY "cib_ismaster" #define PCMK__CIB_REQUEST_BUMP "cib_bump" #define PCMK__CIB_REQUEST_QUERY "cib_query" @@ -89,7 +89,7 @@ enum cib__op_type { cib__op_schemas, cib__op_secondary, cib__op_shutdown, - cib__op_sync_to_all, + cib__op_sync, cib__op_upgrade, }; diff --git a/lib/cib/cib_client.c b/lib/cib/cib_client.c index 38fae89be7c..2009c5d4739 100644 --- a/lib/cib/cib_client.c +++ b/lib/cib/cib_client.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -290,8 +290,8 @@ cib_client_sync(cib_t * cib, const char *section, int call_options) static int cib_client_sync_from(cib_t * cib, const char *host, const char *section, int call_options) { - return cib_internal_op(cib, PCMK__CIB_REQUEST_SYNC_TO_ALL, host, section, - NULL, NULL, call_options, cib->user); + return cib_internal_op(cib, PCMK__CIB_REQUEST_SYNC, host, section, NULL, + NULL, call_options, cib->user); } static int diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c index 4558707ad1f..ab4a341bc6e 100644 --- a/lib/cib/cib_ops.c +++ b/lib/cib/cib_ops.c @@ -118,8 +118,7 @@ static const cib__operation_t cib_ops[] = { PCMK__CIB_REQUEST_SHUTDOWN, cib__op_shutdown, cib__op_attr_privileged }, { - PCMK__CIB_REQUEST_SYNC_TO_ALL, cib__op_sync_to_all, - cib__op_attr_privileged + PCMK__CIB_REQUEST_SYNC, cib__op_sync, cib__op_attr_privileged }, { PCMK__CIB_REQUEST_UPGRADE, cib__op_upgrade, From ef028fd65e7a6c20d6b29174f916edf0e40b88f6 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 22:12:46 -0800 Subject: [PATCH 37/41] Fix: libcib: Don't convert -pcmk_err_diff_resync to pcmk_ok The note that "internal value that clients do not and should not care about" is false or at best outdated. When a cluster had at least one node running Pacemaker 1.1.11 or earlier (see other recent commit messages), certain changes were "broadcast" using an apply-patch request. This request may fail with -pcmk_err_diff_resync if it came from a node with a newer CIB than ours. This error means the source version of the patchset is newer than our CIB version. Now, however, an apply-patch request can only come from cibadmin. If applying a patch fails because the patchset source version is too new, then a client should report that as an error. Signed-off-by: Reid Wahl --- lib/cib/cib_native.c | 5 ----- lib/cib/cib_remote.c | 5 ----- lib/cib/cib_utils.c | 5 ----- 3 files changed, 15 deletions(-) diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 9f2de2a39ec..9cb585d9747 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -143,11 +143,6 @@ cib_native_perform_op_delegate(cib_t *cib, const char *op, const char *host, case -EPERM: break; - /* This is an internal value that clients do not and should not care about */ - case -pcmk_err_diff_resync: - rc = pcmk_ok; - break; - /* These indicate internal problems */ case -EPROTO: case -ENOMSG: diff --git a/lib/cib/cib_remote.c b/lib/cib/cib_remote.c index c4cdb2746cf..1b3a8c08574 100644 --- a/lib/cib/cib_remote.c +++ b/lib/cib/cib_remote.c @@ -163,11 +163,6 @@ cib_remote_perform_op(cib_t *cib, const char *op, const char *host, rc = -EPROTO; } - if (rc == -pcmk_err_diff_resync) { - /* This is an internal value that clients do not and should not care about */ - rc = pcmk_ok; - } - if (rc == pcmk_ok || rc == -EPERM) { pcmk__log_xml_debug(op_reply, "passed"); diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 387a130660b..505080591fc 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -752,11 +752,6 @@ cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc) pcmk__debug("No cib object supplied"); } - if (rc == -pcmk_err_diff_resync) { - /* This is an internal value that clients do not and should not care about */ - rc = pcmk_ok; - } - if (blob && blob->callback && (rc == pcmk_ok || blob->only_success == FALSE)) { pcmk__trace("Invoking callback %s for call %d", pcmk__s(blob->id, "without ID"), call_id); From 5a7c88bba9e8f682cec47a2b7f59dbbf0963b8c3 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 22:17:48 -0800 Subject: [PATCH 38/41] Feature: libcrmcommon: xml_apply_patchset doesn't return diff_resync err This shouldn't affect cibadmin even though it can call xml_apply_patchset(), since pcmk_rc_diff_resync and pcmk_rc_diff_failed map to the same exit code. Signed-off-by: Reid Wahl --- daemons/fenced/fenced_cib.c | 3 +-- lib/common/patchset.c | 2 +- tools/crm_mon.c | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/daemons/fenced/fenced_cib.c b/daemons/fenced/fenced_cib.c index f030c1b2b06..9ecf635f371 100644 --- a/daemons/fenced/fenced_cib.c +++ b/daemons/fenced/fenced_cib.c @@ -1,5 +1,5 @@ /* - * Copyright 2009-2025 the Pacemaker project contributors + * Copyright 2009-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -516,7 +516,6 @@ update_cib_cache_cb(const char *event, xmlNode * msg) * old diff. */ break; - case -pcmk_err_diff_resync: case -pcmk_err_diff_failed: pcmk__notice("[%s] Patch aborted: %s (%d)", event, pcmk_strerror(rc), rc); diff --git a/lib/common/patchset.c b/lib/common/patchset.c index eeed17d54ee..311478717b1 100644 --- a/lib/common/patchset.c +++ b/lib/common/patchset.c @@ -464,7 +464,7 @@ check_patchset_versions(const xmlNode *cib_root, const xmlNode *patchset) vfields[i], current[0], current[1], current[2], source[0], source[1], source[2], target[0], target[1], target[2]); - return pcmk_rc_diff_resync; + return pcmk_rc_diff_failed; } if (current[i] > source[i]) { pcmk__info("Current %s is too high " diff --git a/tools/crm_mon.c b/tools/crm_mon.c index ab42c3bac96..8853e6ba52e 100644 --- a/tools/crm_mon.c +++ b/tools/crm_mon.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -1948,7 +1948,6 @@ crm_diff_update(const char *event, xmlNode * msg) rc = xml_apply_patchset(current_cib, diff, TRUE); switch (rc) { - case -pcmk_err_diff_resync: case -pcmk_err_diff_failed: pcmk__notice("[%s] Patch aborted: %s (%d)", event, pcmk_strerror(rc), rc); @@ -1961,6 +1960,7 @@ crm_diff_update(const char *event, xmlNode * msg) pcmk__notice("[%s] ABORTED: %s (%d)", event, pcmk_strerror(rc), rc); pcmk__xml_free(current_cib); current_cib = NULL; + break; } } From ca285c5f8500eec21c9a9425a47968c257cee52a Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 22:37:52 -0800 Subject: [PATCH 39/41] Log: controller: Don't treat patchset-apply errors as OK It is in fact an error if we get -pcmk_err_diff_failed or -pcmk_err_diff_resync. This "ignore" goes back to commit a0cecc0c. We probably treated diff-related errors as OK because of how diffs were used in legacy mode (for compatibility with Pacemaker versions 1.1.11 and earlier) -- see recent commit messages. However, this shouldn't make any difference. * Nothing returns -pcmk_err_diff_resync/pcmk_rc_diff_resync anymore. * The return code we're checking is from a CIB modify operation, which can't return a diff_failed error because it doesn't apply a patchset. Signed-off-by: Reid Wahl --- daemons/controld/controld_cib.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/daemons/controld/controld_cib.c b/daemons/controld/controld_cib.c index 0e4849ad4db..017bdab4516 100644 --- a/daemons/controld/controld_cib.c +++ b/daemons/controld/controld_cib.c @@ -729,22 +729,17 @@ controld_record_pending_op(const char *node_name, const lrmd_rsc_info_t *rsc, static void cib_rsc_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data) { - switch (rc) { - case pcmk_ok: - case -pcmk_err_diff_failed: - case -pcmk_err_diff_resync: - pcmk__trace("Resource history update completed (call=%d rc=%d)", - call_id, rc); - break; - default: - if (call_id > 0) { - pcmk__warn("Resource history update %d failed: %s " - QB_XS " rc=%d", - call_id, pcmk_strerror(rc), rc); - } else { - pcmk__warn("Resource history update failed: %s " QB_XS " rc=%d", - pcmk_strerror(rc), rc); - } + if (rc == pcmk_ok) { + pcmk__trace("Resource history update completed (call=%d rc=%d)", + call_id, rc); + + } else if (call_id > 0) { + pcmk__warn("Resource history update %d failed: %s " QB_XS " rc=%d", + call_id, pcmk_strerror(rc), rc); + + } else { + pcmk__warn("Resource history update failed: %s " QB_XS " rc=%d", + pcmk_strerror(rc), rc); } if (call_id == pending_rsc_update) { From 4853a9790742c60db5879b14f4036da696aad590 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 22:42:45 -0800 Subject: [PATCH 40/41] Refactor: based: Drop pcmk_rc_diff_resync from switch Nothing returns that code anymore. Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 1 - 1 file changed, 1 deletion(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index d492ad6cab5..9d9076db82e 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -743,7 +743,6 @@ log_op_result(const xmlNode *request, const cib__operation_t *operation, int rc, break; case pcmk_rc_old_data: - case pcmk_rc_diff_resync: case pcmk_rc_diff_failed: level = LOG_TRACE; break; From 9dd165d38627ea6e96e6fcf2edada86e170c6036 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 1 Jan 2026 22:44:11 -0800 Subject: [PATCH 41/41] Log: based: Don't log specially for PCMK__XA_CIB_UPDATE As discussed in several recent commit messages, PCMK__XA_CIB_UPDATE used to get set when broadcasting changes while in legacy mode. We haven't supported that since 3.0.0, so PCMK__XA_CIB_UPDATE is set only for sync requests (in sync_our_cib()). I don't see any reason to treat the return code differently for sync operations than for other modifying operations. Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index 9d9076db82e..ce49437253c 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -736,21 +736,6 @@ log_op_result(const xmlNode *request, const cib__operation_t *operation, int rc, if (!pcmk__is_set(operation->flags, cib__op_attr_modifies)) { level = LOG_TRACE; - } else if (pcmk__xe_attr_is_true(request, PCMK__XA_CIB_UPDATE)) { - switch (rc) { - case pcmk_rc_ok: - level = LOG_INFO; - break; - - case pcmk_rc_old_data: - case pcmk_rc_diff_failed: - level = LOG_TRACE; - break; - - default: - level = LOG_ERR; - } - } else if (rc != pcmk_rc_ok) { level = LOG_WARNING; }