diff --git a/cts/cli/regression.rules.exp b/cts/cli/regression.rules.exp
index 86e937c314..6e35c44e7b 100644
--- a/cts/cli/regression.rules.exp
+++ b/cts/cli/regression.rules.exp
@@ -1,629 +1,629 @@
 Created new pacemaker configuration
 Setting up shadow instance
 A new shadow instance was created.  To begin using it paste the following into your shell:
   CIB_shadow=cts-cli ; export CIB_shadow
 =#=#=#= Begin test: Try to check a rule that doesn't exist =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 No rule found with ID=blahblah
 Error checking rule: No such device or address
 =#=#=#= Current cib after: Try to check a rule that doesn't exist =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Try to check a rule that doesn't exist - No such object (105) =#=#=#=
 * Passed: crm_rule       - Try to check a rule that doesn't exist
 =#=#=#= Begin test: Try to check a rule that has too many date_expressions =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Can't check rule cli-rule-too-many-date-expressions because it does not have exactly one date_expression
 Error checking rule: Operation not supported
 =#=#=#= Current cib after: Try to check a rule that has too many date_expressions =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Try to check a rule that has too many date_expressions - Unimplemented (3) =#=#=#=
 * Passed: crm_rule       - Try to check a rule that has too many date_expressions
 =#=#=#= Begin test: Verify basic rule is expired =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Rule cli-prefer-rule-dummy-expired is expired
 =#=#=#= Current cib after: Verify basic rule is expired =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Verify basic rule is expired - Requested item has expired (110) =#=#=#=
 * Passed: crm_rule       - Verify basic rule is expired
 =#=#=#= Begin test: Verify basic rule worked in the past =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Rule cli-prefer-rule-dummy-expired is still in effect
 =#=#=#= Current cib after: Verify basic rule worked in the past =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Verify basic rule worked in the past - OK (0) =#=#=#=
 * Passed: crm_rule       - Verify basic rule worked in the past
 =#=#=#= Begin test: Verify basic rule is not yet in effect =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Rule cli-prefer-rule-dummy-not-yet has not yet taken effect
 =#=#=#= Current cib after: Verify basic rule is not yet in effect =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Verify basic rule is not yet in effect - Requested item is not yet in effect (111) =#=#=#=
 * Passed: crm_rule       - Verify basic rule is not yet in effect
 =#=#=#= Begin test: Verify date_spec rule with years has expired =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Rule cli-prefer-rule-dummy-date_spec-only-years is expired
 =#=#=#= Current cib after: Verify date_spec rule with years has expired =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Verify date_spec rule with years has expired - Requested item has expired (110) =#=#=#=
 * Passed: crm_rule       - Verify date_spec rule with years has expired
 =#=#=#= Begin test: Verify date_spec rule with years is in effect =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Rule cli-prefer-rule-dummy-date_spec-only-years satisfies conditions
 =#=#=#= Current cib after: Verify date_spec rule with years is in effect =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Verify date_spec rule with years is in effect - OK (0) =#=#=#=
 * Passed: crm_rule       - Verify date_spec rule with years is in effect
 =#=#=#= Begin test: Try to check a rule whose date_spec does not contain years= =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Rule either must not use date_spec, or use date_spec with years= but not moon=
 Error checking rule: No such device or address
 =#=#=#= Current cib after: Try to check a rule whose date_spec does not contain years= =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Try to check a rule whose date_spec does not contain years= - No such object (105) =#=#=#=
 * Passed: crm_rule       - Try to check a rule whose date_spec does not contain years=
 =#=#=#= Begin test: Try to check a rule whose date_spec contains years= and moon= =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Rule either must not use date_spec, or use date_spec with years= but not moon=
 Error checking rule: No such device or address
 =#=#=#= Current cib after: Try to check a rule whose date_spec contains years= and moon= =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Try to check a rule whose date_spec contains years= and moon= - No such object (105) =#=#=#=
 * Passed: crm_rule       - Try to check a rule whose date_spec contains years= and moon=
 =#=#=#= Begin test: Try to check a rule with no date_expression =#=#=#=
-unpack_resources       error: Resource start-up disabled since no STONITH resources have been defined
-unpack_resources       error: Either configure some or disable STONITH with the stonith-enabled option
-unpack_resources       error: NOTE: Clusters with shared data need STONITH to ensure data integrity
+unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
+unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
+unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Can't check rule cli-no-date_expression-rule because it does not have exactly one date_expression
 Error checking rule: Operation not supported
 =#=#=#= Current cib after: Try to check a rule with no date_expression =#=#=#=
 
   
     
     
     
       
     
     
       
         
           
           
         
       
       
         
           
         
       
       
         
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
             
           
         
       
       
         
           
         
       
     
   
   
 
 =#=#=#= End test: Try to check a rule with no date_expression - Unimplemented (3) =#=#=#=
 * Passed: crm_rule       - Try to check a rule with no date_expression
diff --git a/cts/cli/regression.upgrade.exp b/cts/cli/regression.upgrade.exp
index d1435395c5..28ca057004 100644
--- a/cts/cli/regression.upgrade.exp
+++ b/cts/cli/regression.upgrade.exp
@@ -1,144 +1,147 @@
 Created new pacemaker configuration
 Setting up shadow instance
 A new shadow instance was created.  To begin using it paste the following into your shell:
   CIB_shadow=cts-cli ; export CIB_shadow
 =#=#=#= Begin test: Set stonith-enabled=false =#=#=#=
 =#=#=#= Current cib after: Set stonith-enabled=false =#=#=#=
 
   
     
       
         
       
     
     
     
     
   
   
 
 =#=#=#= End test: Set stonith-enabled=false - OK (0) =#=#=#=
 * Passed: crm_attribute  - Set stonith-enabled=false
 =#=#=#= Begin test: Configure the initial resource =#=#=#=
 =#=#=#= Current cib after: Configure the initial resource =#=#=#=
 
   
     
       
         
       
     
     
     
       
         
           
           
             
               
             
           
           
             
               
             
           
         
         
           
         
         
         
       
     
     
   
   
 
 =#=#=#= End test: Configure the initial resource - OK (0) =#=#=#=
 * Passed: cibadmin       - Configure the initial resource
 =#=#=#= Begin test: Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping) =#=#=#=
 update_validation 	debug: Testing 'pacemaker-2.10' validation (13 of X)
 update_validation 	debug: Upgrading pacemaker-2.10-style configuration to pacemaker-3.0 with upgrade-2.10.xsl
 apply_upgrade 	debug: Upgrading pacemaker-2.10-style configuration, pre-upgrade phase with upgrade-2.10-enter.xsl
 apply_upgrade 	debug: Upgrading pacemaker-2.10-style configuration, main phase with upgrade-2.10.xsl
 INFO: Resources-operation instance_attributes: mySmartFuse-monitor-inputpower (rsc=mySmartFuse, meta=mySmartFuse-inputpower-instanceparams): dropping requires
 INFO: Resources-operation instance_attributes: ... only start/promote operation taken into account
 INFO: Resources-operation instance_attributes: mySmartFuse-monitor-outputpower (rsc=mySmartFuse, meta=mySmartFuse-outputpower-instanceparams): dropping requires
 INFO: Resources-operation instance_attributes: ... only start/promote operation taken into account
 apply_upgrade 	debug: Upgrading pacemaker-2.10-style configuration, post-upgrade phase with upgrade-2.10-leave.xsl
 DEBUG: instance_attributes: original element pointed to with @id-ref (mySmartFuse-outputpower-instanceparams) disappeared during upgrade
 update_validation 	info: Transformation upgrade-2.10.xsl successful
 update_validation 	debug: Testing 'pacemaker-3.0' validation (14 of X)
 update_validation 	debug: pacemaker-3.0-style configuration is also valid for pacemaker-3.1
 update_validation 	debug: Testing 'pacemaker-3.1' validation (15 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-3.1
 update_validation 	debug: pacemaker-3.1-style configuration is also valid for pacemaker-3.2
 update_validation 	debug: Testing 'pacemaker-3.2' validation (16 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-3.2
-update_validation 	trace: Stopping at pacemaker-3.2
-update_validation 	info: Transformed the configuration from pacemaker-2.10 to pacemaker-3.2
+update_validation 	debug: pacemaker-3.2-style configuration is also valid for pacemaker-3.3
+update_validation 	debug: Testing 'pacemaker-3.3' validation (17 of X)
+update_validation 	debug: Configuration valid for schema: pacemaker-3.3
+update_validation 	trace: Stopping at pacemaker-3.3
+update_validation 	info: Transformed the configuration from pacemaker-2.10 to pacemaker-3.3
 =#=#=#= Current cib after: Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping) =#=#=#=
 
   
     
       
         
       
     
     
     
       
         
           
           
           
         
         
           
         
         
         
           
         
       
     
     
   
   
 
 =#=#=#= End test: Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping) - OK (0) =#=#=#=
 * Passed: cibadmin       - Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping)
 =#=#=#= Begin test: Query a resource instance attribute (shall survive) =#=#=#=
 outputpower
 =#=#=#= Current cib after: Query a resource instance attribute (shall survive) =#=#=#=
 
   
     
       
         
       
     
     
     
       
         
           
           
           
         
         
           
         
         
         
           
         
       
     
     
   
   
 
 =#=#=#= End test: Query a resource instance attribute (shall survive) - OK (0) =#=#=#=
 * Passed: crm_resource   - Query a resource instance attribute (shall survive)
diff --git a/cts/cli/regression.validity.exp b/cts/cli/regression.validity.exp
index bccea42087..46e54b5095 100644
--- a/cts/cli/regression.validity.exp
+++ b/cts/cli/regression.validity.exp
@@ -1,462 +1,476 @@
 Created new pacemaker configuration
 Setting up shadow instance
 A new shadow instance was created.  To begin using it paste the following into your shell:
   CIB_shadow=cts-cli ; export CIB_shadow
 =#=#=#= Begin test: Try to make resulting CIB invalid (enum violation) =#=#=#=
    1 
    2   
    3     
    4     
    5     
    6       
    7       
    8     
    9     
   10       
   11     
   12   
   13   
   14 
   15 
 Call failed: Update does not conform to the configured schema
 =#=#=#= Current cib after: Try to make resulting CIB invalid (enum violation) =#=#=#=
 
   
     
     
     
       
       
     
     
       
     
   
   
 
 =#=#=#= End test: Try to make resulting CIB invalid (enum violation) - Invalid configuration (78) =#=#=#=
 * Passed: cibadmin       - Try to make resulting CIB invalid (enum violation)
 =#=#=#= Begin test: Run crm_simulate with invalid CIB (enum violation) =#=#=#=
 update_validation 	debug: Testing 'pacemaker-1.2' validation (1 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-1.2 validation failed
 update_validation 	debug: Testing 'pacemaker-1.3' validation (2 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-1.3 validation failed
 update_validation 	debug: Testing 'pacemaker-2.0' validation (3 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.0 validation failed
 update_validation 	debug: Testing 'pacemaker-2.1' validation (4 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.1 validation failed
 update_validation 	debug: Testing 'pacemaker-2.2' validation (5 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.2 validation failed
 update_validation 	debug: Testing 'pacemaker-2.3' validation (6 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.3 validation failed
 update_validation 	debug: Testing 'pacemaker-2.4' validation (7 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.4 validation failed
 update_validation 	debug: Testing 'pacemaker-2.5' validation (8 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.5 validation failed
 update_validation 	debug: Testing 'pacemaker-2.6' validation (9 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.6 validation failed
 update_validation 	debug: Testing 'pacemaker-2.7' validation (10 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.7 validation failed
 update_validation 	debug: Testing 'pacemaker-2.8' validation (11 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.8 validation failed
 update_validation 	debug: Testing 'pacemaker-2.9' validation (12 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.9 validation failed
 update_validation 	debug: Testing 'pacemaker-2.10' validation (13 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-2.10 validation failed
 update_validation 	debug: Testing 'pacemaker-3.0' validation (14 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-3.0 validation failed
 update_validation 	debug: Testing 'pacemaker-3.1' validation (15 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-3.1 validation failed
 update_validation 	debug: Testing 'pacemaker-3.2' validation (16 of X)
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 update_validation 	trace: pacemaker-3.2 validation failed
-Cannot upgrade configuration (claiming schema pacemaker-1.2) to at least pacemaker-3.0 because it does not validate with any schema from pacemaker-1.2 to pacemaker-3.2
+update_validation 	debug: Testing 'pacemaker-3.3' validation (17 of X)
+element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
+element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
+update_validation 	trace: pacemaker-3.3 validation failed
+Cannot upgrade configuration (claiming schema pacemaker-1.2) to at least pacemaker-3.0 because it does not validate with any schema from pacemaker-1.2 to pacemaker-3.3
 =#=#=#= End test: Run crm_simulate with invalid CIB (enum violation) - Invalid configuration (78) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with invalid CIB (enum violation)
 =#=#=#= Begin test: Try to make resulting CIB invalid (unrecognized validate-with) =#=#=#=
    1 
    2   
    3     
    4     
    5     
    6       
    7       
    8     
    9     
   10       
   11     
   12   
   13   
   14 
   15 
 Call failed: Update does not conform to the configured schema
 =#=#=#= Current cib after: Try to make resulting CIB invalid (unrecognized validate-with) =#=#=#=
 
   
     
     
     
       
       
     
     
       
     
   
   
 
 =#=#=#= End test: Try to make resulting CIB invalid (unrecognized validate-with) - Invalid configuration (78) =#=#=#=
 * Passed: cibadmin       - Try to make resulting CIB invalid (unrecognized validate-with)
 =#=#=#= Begin test: Run crm_simulate with invalid CIB (unrecognized validate-with) =#=#=#=
 update_validation 	debug: Unknown validation schema
 update_validation 	debug: Testing 'pacemaker-1.0' validation (0 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-1.0 validation failed
 update_validation 	debug: Testing 'pacemaker-1.2' validation (1 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-1.2 validation failed
 update_validation 	debug: Testing 'pacemaker-1.3' validation (2 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-1.3 validation failed
 update_validation 	debug: Testing 'pacemaker-2.0' validation (3 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.0 validation failed
 update_validation 	debug: Testing 'pacemaker-2.1' validation (4 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.1 validation failed
 update_validation 	debug: Testing 'pacemaker-2.2' validation (5 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.2 validation failed
 update_validation 	debug: Testing 'pacemaker-2.3' validation (6 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.3 validation failed
 update_validation 	debug: Testing 'pacemaker-2.4' validation (7 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.4 validation failed
 update_validation 	debug: Testing 'pacemaker-2.5' validation (8 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.5 validation failed
 update_validation 	debug: Testing 'pacemaker-2.6' validation (9 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.6 validation failed
 update_validation 	debug: Testing 'pacemaker-2.7' validation (10 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.7 validation failed
 update_validation 	debug: Testing 'pacemaker-2.8' validation (11 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.8 validation failed
 update_validation 	debug: Testing 'pacemaker-2.9' validation (12 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.9 validation failed
 update_validation 	debug: Testing 'pacemaker-2.10' validation (13 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-2.10 validation failed
 update_validation 	debug: Testing 'pacemaker-3.0' validation (14 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-3.0 validation failed
 update_validation 	debug: Testing 'pacemaker-3.1' validation (15 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-3.1 validation failed
 update_validation 	debug: Testing 'pacemaker-3.2' validation (16 of X)
 element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
 update_validation 	trace: pacemaker-3.2 validation failed
-Cannot upgrade configuration (claiming schema pacemaker-9999.0) to at least pacemaker-3.0 because it does not validate with any schema from unknown to pacemaker-3.2
+update_validation 	debug: Testing 'pacemaker-3.3' validation (17 of X)
+element cib: Relax-NG validity error : Invalid attribute validate-with for element cib
+update_validation 	trace: pacemaker-3.3 validation failed
+Cannot upgrade configuration (claiming schema pacemaker-9999.0) to at least pacemaker-3.0 because it does not validate with any schema from unknown to pacemaker-3.3
 =#=#=#= End test: Run crm_simulate with invalid CIB (unrecognized validate-with) - Invalid configuration (78) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with invalid CIB (unrecognized validate-with)
 =#=#=#= Begin test: Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) =#=#=#=
    1 
    2   
    3     
    4     
    5     
    6       
    7       
    8     
    9     
   10       
   11     
   12     
   13   
   14   
   15 
   16 
 Call failed: Update does not conform to the configured schema
 =#=#=#= Current cib after: Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) =#=#=#=
 
   
     
     
     
       
       
     
     
       
     
   
   
 
 =#=#=#= End test: Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1) - Invalid configuration (78) =#=#=#=
 * Passed: cibadmin       - Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1)
 =#=#=#= Begin test: Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1) =#=#=#=
 update_validation 	debug: Testing 'pacemaker-1.2' validation (1 of X)
 element tags: Relax-NG validity error : Element configuration has extra content: tags
 update_validation 	trace: pacemaker-1.2 validation failed
 update_validation 	debug: Testing 'pacemaker-1.3' validation (2 of X)
 update_validation 	debug: pacemaker-1.3-style configuration is also valid for pacemaker-2.0
 update_validation 	debug: Testing 'pacemaker-2.0' validation (3 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.0
 update_validation 	debug: pacemaker-2.0-style configuration is also valid for pacemaker-2.1
 update_validation 	debug: Testing 'pacemaker-2.1' validation (4 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.1
 update_validation 	debug: pacemaker-2.1-style configuration is also valid for pacemaker-2.2
 update_validation 	debug: Testing 'pacemaker-2.2' validation (5 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.2
 update_validation 	debug: pacemaker-2.2-style configuration is also valid for pacemaker-2.3
 update_validation 	debug: Testing 'pacemaker-2.3' validation (6 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.3
 update_validation 	debug: pacemaker-2.3-style configuration is also valid for pacemaker-2.4
 update_validation 	debug: Testing 'pacemaker-2.4' validation (7 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.4
 update_validation 	debug: pacemaker-2.4-style configuration is also valid for pacemaker-2.5
 update_validation 	debug: Testing 'pacemaker-2.5' validation (8 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.5
 update_validation 	debug: pacemaker-2.5-style configuration is also valid for pacemaker-2.6
 update_validation 	debug: Testing 'pacemaker-2.6' validation (9 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.6
 update_validation 	debug: pacemaker-2.6-style configuration is also valid for pacemaker-2.7
 update_validation 	debug: Testing 'pacemaker-2.7' validation (10 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.7
 update_validation 	debug: pacemaker-2.7-style configuration is also valid for pacemaker-2.8
 update_validation 	debug: Testing 'pacemaker-2.8' validation (11 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.8
 update_validation 	debug: pacemaker-2.8-style configuration is also valid for pacemaker-2.9
 update_validation 	debug: Testing 'pacemaker-2.9' validation (12 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.9
 update_validation 	debug: pacemaker-2.9-style configuration is also valid for pacemaker-2.10
 update_validation 	debug: Testing 'pacemaker-2.10' validation (13 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-2.10
 update_validation 	debug: pacemaker-2.10-style configuration is also valid for pacemaker-3.0
 update_validation 	debug: Testing 'pacemaker-3.0' validation (14 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-3.0
 update_validation 	debug: pacemaker-3.0-style configuration is also valid for pacemaker-3.1
 update_validation 	debug: Testing 'pacemaker-3.1' validation (15 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-3.1
 update_validation 	debug: pacemaker-3.1-style configuration is also valid for pacemaker-3.2
 update_validation 	debug: Testing 'pacemaker-3.2' validation (16 of X)
 update_validation 	debug: Configuration valid for schema: pacemaker-3.2
-update_validation 	trace: Stopping at pacemaker-3.2
-update_validation 	info: Transformed the configuration from pacemaker-1.2 to pacemaker-3.2
+update_validation 	debug: pacemaker-3.2-style configuration is also valid for pacemaker-3.3
+update_validation 	debug: Testing 'pacemaker-3.3' validation (17 of X)
+update_validation 	debug: Configuration valid for schema: pacemaker-3.3
+update_validation 	trace: Stopping at pacemaker-3.3
+update_validation 	info: Transformed the configuration from pacemaker-1.2 to pacemaker-3.3
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Current cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 Transition Summary:
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Executing cluster transition:
 
 Revised cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 =#=#=#= End test: Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1) - OK (0) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1)
 =#=#=#= Begin test: Make resulting CIB valid, although without validate-with attribute =#=#=#=
 =#=#=#= Current cib after: Make resulting CIB valid, although without validate-with attribute =#=#=#=
 
   
     
     
     
       
       
     
     
       
     
   
   
 
 =#=#=#= End test: Make resulting CIB valid, although without validate-with attribute - OK (0) =#=#=#=
 * Passed: cibadmin       - Make resulting CIB valid, although without validate-with attribute
 =#=#=#= Begin test: Run crm_simulate with valid CIB, but without validate-with attribute =#=#=#=
 Schema validation of configuration is disabled (enabling is encouraged and prevents common misconfigurations)
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Current cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 Transition Summary:
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Executing cluster transition:
 
 Revised cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 =#=#=#= End test: Run crm_simulate with valid CIB, but without validate-with attribute - OK (0) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with valid CIB, but without validate-with attribute
 =#=#=#= Begin test: Make resulting CIB invalid, and without validate-with attribute =#=#=#=
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
+element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
+element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 =#=#=#= Current cib after: Make resulting CIB invalid, and without validate-with attribute =#=#=#=
 
   
     
     
     
       
       
     
     
       
     
   
   
 
 =#=#=#= End test: Make resulting CIB invalid, and without validate-with attribute - OK (0) =#=#=#=
 * Passed: cibadmin       - Make resulting CIB invalid, and without validate-with attribute
 =#=#=#= Begin test: Run crm_simulate with invalid CIB, also without validate-with attribute =#=#=#=
 Schema validation of configuration is disabled (enabling is encouraged and prevents common misconfigurations)
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
 validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
+validity.bad.xml:10: element rsc_order: Relax-NG validity error : Invalid attribute first-action for element rsc_order
+validity.bad.xml:10: element rsc_order: Relax-NG validity error : Element constraints has extra content: rsc_order
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 unpack_simple_rsc_order 	error: Cannot invert constraint 'ord_1-2' (please specify inverse manually)
 
 Current cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 Transition Summary:
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 
 Executing cluster transition:
 
 Revised cluster status:
 
  dummy1	(ocf::pacemaker:Dummy):	Stopped
  dummy2	(ocf::pacemaker:Dummy):	Stopped
 
 =#=#=#= End test: Run crm_simulate with invalid CIB, also without validate-with attribute - OK (0) =#=#=#=
 * Passed: crm_simulate   - Run crm_simulate with invalid CIB, also without validate-with attribute
diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h
index b4ce1574cd..cc0f168fd7 100644
--- a/include/crm/pengine/internal.h
+++ b/include/crm/pengine/internal.h
@@ -1,444 +1,447 @@
 /*
  * Copyright 2004-2020 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #ifndef PE_INTERNAL__H
 #  define PE_INTERNAL__H
 #  include 
 #  include 
 #  include 
 #  include 
 
 #  define pe_rsc_info(rsc, fmt, args...)  crm_log_tag(LOG_INFO,  rsc ? rsc->id : "", fmt, ##args)
 #  define pe_rsc_debug(rsc, fmt, args...) crm_log_tag(LOG_DEBUG, rsc ? rsc->id : "", fmt, ##args)
 #  define pe_rsc_trace(rsc, fmt, args...) crm_log_tag(LOG_TRACE, rsc ? rsc->id : "", fmt, ##args)
 
 #  define pe_err(fmt...) { was_processing_error = TRUE; crm_config_error = TRUE; crm_err(fmt); }
 #  define pe_warn(fmt...) { was_processing_warning = TRUE; crm_config_warning = TRUE; crm_warn(fmt); }
 #  define pe_proc_err(fmt...) { was_processing_error = TRUE; crm_err(fmt); }
 #  define pe_proc_warn(fmt...) { was_processing_warning = TRUE; crm_warn(fmt); }
 #  define pe_set_action_bit(action, bit) action->flags = crm_set_bit(__FUNCTION__, __LINE__, action->uuid, action->flags, bit)
 #  define pe_clear_action_bit(action, bit) action->flags = crm_clear_bit(__FUNCTION__, __LINE__, action->uuid, action->flags, bit)
 
 typedef struct pe__location_constraint_s {
     char *id;                           // Constraint XML ID
     pe_resource_t *rsc_lh;              // Resource being located
     enum rsc_role_e role_filter;        // Role to locate
     enum pe_discover_e discover_mode;   // Resource discovery
     GListPtr node_list_rh;              // List of pe_node_t*
 } pe__location_t;
 
 typedef struct pe__order_constraint_s {
     int id;
     enum pe_ordering type;
 
     void *lh_opaque;
     pe_resource_t *lh_rsc;
     pe_action_t *lh_action;
     char *lh_action_task;
 
     void *rh_opaque;
     pe_resource_t *rh_rsc;
     pe_action_t *rh_action;
     char *rh_action_task;
 } pe__ordering_t;
 
 typedef struct notify_data_s {
     GSList *keys;               // Environment variable name/value pairs
 
     const char *action;
 
     pe_action_t *pre;
     pe_action_t *post;
     pe_action_t *pre_done;
     pe_action_t *post_done;
 
     GListPtr active;            /* notify_entry_t*  */
     GListPtr inactive;          /* notify_entry_t*  */
     GListPtr start;             /* notify_entry_t*  */
     GListPtr stop;              /* notify_entry_t*  */
     GListPtr demote;            /* notify_entry_t*  */
     GListPtr promote;           /* notify_entry_t*  */
     GListPtr master;            /* notify_entry_t*  */
     GListPtr slave;             /* notify_entry_t*  */
     GHashTable *allowed_nodes;
 
 } notify_data_t;
 
 bool pe_can_fence(pe_working_set_t *data_set, pe_node_t *node);
 
 int merge_weights(int w1, int w2);
 void add_hash_param(GHashTable * hash, const char *name, const char *value);
 
 char *native_parameter(pe_resource_t * rsc, pe_node_t * node, gboolean create, const char *name,
                        pe_working_set_t * data_set);
 pe_node_t *native_location(const pe_resource_t *rsc, GList **list, int current);
 
 void pe_metadata(void);
 void verify_pe_options(GHashTable * options);
 
 void common_update_score(pe_resource_t * rsc, const char *id, int score);
 void native_add_running(pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * data_set);
 
 gboolean native_unpack(pe_resource_t * rsc, pe_working_set_t * data_set);
 gboolean group_unpack(pe_resource_t * rsc, pe_working_set_t * data_set);
 gboolean clone_unpack(pe_resource_t * rsc, pe_working_set_t * data_set);
 gboolean pe__unpack_bundle(pe_resource_t *rsc, pe_working_set_t *data_set);
 
 pe_resource_t *native_find_rsc(pe_resource_t *rsc, const char *id, const pe_node_t *node,
                                int flags);
 
 gboolean native_active(pe_resource_t * rsc, gboolean all);
 gboolean group_active(pe_resource_t * rsc, gboolean all);
 gboolean clone_active(pe_resource_t * rsc, gboolean all);
 gboolean pe__bundle_active(pe_resource_t *rsc, gboolean all);
 
 void native_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data);
 void group_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data);
 void clone_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data);
 void pe__print_bundle(pe_resource_t *rsc, const char *pre_text, long options,
                       void *print_data);
 
 int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name
                          , size_t pairs_count, ...);
 char *pe__node_display_name(pe_node_t *node, bool print_detail);
 
 int pe__ban_html(pcmk__output_t *out, va_list args);
 int pe__ban_text(pcmk__output_t *out, va_list args);
 int pe__ban_xml(pcmk__output_t *out, va_list args);
 int pe__clone_xml(pcmk__output_t *out, va_list args);
 int pe__clone_html(pcmk__output_t *out, va_list args);
 int pe__clone_text(pcmk__output_t *out, va_list args);
 int pe__cluster_counts_html(pcmk__output_t *out, va_list args);
 int pe__cluster_counts_text(pcmk__output_t *out, va_list args);
 int pe__cluster_counts_xml(pcmk__output_t *out, va_list args);
 int pe__cluster_dc_html(pcmk__output_t *out, va_list args);
 int pe__cluster_dc_text(pcmk__output_t *out, va_list args);
 int pe__cluster_dc_xml(pcmk__output_t *out, va_list args);
 int pe__cluster_maint_mode_html(pcmk__output_t *out, va_list args);
 int pe__cluster_maint_mode_text(pcmk__output_t *out, va_list args);
 int pe__cluster_options_html(pcmk__output_t *out, va_list args);
 int pe__cluster_options_log(pcmk__output_t *out, va_list args);
 int pe__cluster_options_text(pcmk__output_t *out, va_list args);
 int pe__cluster_options_xml(pcmk__output_t *out, va_list args);
 int pe__cluster_stack_html(pcmk__output_t *out, va_list args);
 int pe__cluster_stack_text(pcmk__output_t *out, va_list args);
 int pe__cluster_stack_xml(pcmk__output_t *out, va_list args);
 int pe__cluster_summary(pcmk__output_t *out, va_list args);
 int pe__cluster_summary_html(pcmk__output_t *out, va_list args);
 int pe__cluster_times_html(pcmk__output_t *out, va_list args);
 int pe__cluster_times_xml(pcmk__output_t *out, va_list args);
 int pe__cluster_times_text(pcmk__output_t *out, va_list args);
 int pe__failed_action_text(pcmk__output_t *out, va_list args);
 int pe__failed_action_xml(pcmk__output_t *out, va_list args);
 int pe__group_xml(pcmk__output_t *out, va_list args);
 int pe__group_html(pcmk__output_t *out, va_list args);
 int pe__group_text(pcmk__output_t *out, va_list args);
 int pe__bundle_xml(pcmk__output_t *out, va_list args);
 int pe__bundle_html(pcmk__output_t *out, va_list args);
 int pe__bundle_text(pcmk__output_t *out, va_list args);
 int pe__node_html(pcmk__output_t *out, va_list args);
 int pe__node_text(pcmk__output_t *out, va_list args);
 int pe__node_xml(pcmk__output_t *out, va_list args);
 int pe__node_attribute_html(pcmk__output_t *out, va_list args);
 int pe__node_attribute_text(pcmk__output_t *out, va_list args);
 int pe__node_attribute_xml(pcmk__output_t *out, va_list args);
 int pe__op_history_text(pcmk__output_t *out, va_list args);
 int pe__op_history_xml(pcmk__output_t *out, va_list args);
 int pe__resource_history_text(pcmk__output_t *out, va_list args);
 int pe__resource_history_xml(pcmk__output_t *out, va_list args);
 int pe__resource_xml(pcmk__output_t *out, va_list args);
 int pe__resource_html(pcmk__output_t *out, va_list args);
 int pe__resource_text(pcmk__output_t *out, va_list args);
 int pe__ticket_html(pcmk__output_t *out, va_list args);
 int pe__ticket_text(pcmk__output_t *out, va_list args);
 int pe__ticket_xml(pcmk__output_t *out, va_list args);
 
 void native_free(pe_resource_t * rsc);
 void group_free(pe_resource_t * rsc);
 void clone_free(pe_resource_t * rsc);
 void pe__free_bundle(pe_resource_t *rsc);
 
 enum rsc_role_e native_resource_state(const pe_resource_t * rsc, gboolean current);
 enum rsc_role_e group_resource_state(const pe_resource_t * rsc, gboolean current);
 enum rsc_role_e clone_resource_state(const pe_resource_t * rsc, gboolean current);
 enum rsc_role_e pe__bundle_resource_state(const pe_resource_t *rsc,
                                           gboolean current);
 
 void pe__count_common(pe_resource_t *rsc);
 void pe__count_bundle(pe_resource_t *rsc);
 
 gboolean common_unpack(xmlNode * xml_obj, pe_resource_t ** rsc, pe_resource_t * parent,
                        pe_working_set_t * data_set);
 void common_free(pe_resource_t * rsc);
 
 extern pe_node_t *node_copy(const pe_node_t *this_node);
 extern time_t get_effective_time(pe_working_set_t * data_set);
 
 /* Failure handling utilities (from failcounts.c) */
 
 // bit flags for fail count handling options
 enum pe_fc_flags_e {
     pe_fc_default   = 0x00,
     pe_fc_effective = 0x01, // don't count expired failures
     pe_fc_fillers   = 0x02, // if container, include filler failures in count
 };
 
 int pe_get_failcount(pe_node_t *node, pe_resource_t *rsc, time_t *last_failure,
                      uint32_t flags, xmlNode *xml_op,
                      pe_working_set_t *data_set);
 
 pe_action_t *pe__clear_failcount(pe_resource_t *rsc, pe_node_t *node,
                                  const char *reason,
                                  pe_working_set_t *data_set);
 
 /* Functions for finding/counting a resource's active nodes */
 
 pe_node_t *pe__find_active_on(const pe_resource_t *rsc,
                               unsigned int *count_all,
                               unsigned int *count_clean);
 pe_node_t *pe__find_active_requires(const pe_resource_t *rsc,
                                     unsigned int *count);
 
 static inline pe_node_t *
 pe__current_node(const pe_resource_t *rsc)
 {
     return pe__find_active_on(rsc, NULL, NULL);
 }
 
 
 /* Binary like operators for lists of nodes */
 extern void node_list_exclude(GHashTable * list, GListPtr list2, gboolean merge_scores);
 extern GListPtr node_list_dup(GListPtr list, gboolean reset, gboolean filter);
 
 extern GHashTable *node_hash_from_list(GListPtr list);
 static inline gpointer
 pe_hash_table_lookup(GHashTable * hash, gconstpointer key)
 {
     if (hash) {
         return g_hash_table_lookup(hash, key);
     }
     return NULL;
 }
 
 extern pe_action_t *get_pseudo_op(const char *name, pe_working_set_t * data_set);
 extern gboolean order_actions(pe_action_t * lh_action, pe_action_t * rh_action, enum pe_ordering order);
 
 GHashTable *node_hash_dup(GHashTable * hash);
 
 /* Printing functions for debug */
 extern void print_node(const char *pre_text, pe_node_t * node, gboolean details);
 extern void print_str_str(gpointer key, gpointer value, gpointer user_data);
 extern void pe__output_node(pe_node_t * node, gboolean details, pcmk__output_t *out);
 
 extern void dump_node_capacity(int level, const char *comment, pe_node_t * node);
 extern void dump_rsc_utilization(int level, const char *comment, pe_resource_t * rsc, pe_node_t * node);
 
 void pe__show_node_weights_as(const char *file, const char *function,
                               int line, bool to_log, pe_resource_t *rsc,
                               const char *comment, GHashTable *nodes);
 
 #define pe__show_node_weights(level, rsc, text, nodes)              \
         pe__show_node_weights_as(__FILE__, __FUNCTION__, __LINE__,  \
                                  (level), (rsc), (text), (nodes))
 
 /* Sorting functions */
 extern gint sort_rsc_priority(gconstpointer a, gconstpointer b);
 extern gint sort_rsc_index(gconstpointer a, gconstpointer b);
 
 extern xmlNode *find_rsc_op_entry(pe_resource_t * rsc, const char *key);
 
 extern pe_action_t *custom_action(pe_resource_t * rsc, char *key, const char *task, pe_node_t * on_node,
                                   gboolean optional, gboolean foo, pe_working_set_t * data_set);
 
 #  define delete_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_DELETE, 0)
 #  define delete_action(rsc, node, optional) custom_action(		\
 		rsc, delete_key(rsc), CRMD_ACTION_DELETE, node,		\
 		optional, TRUE, data_set);
 
 #  define stopped_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_STOPPED, 0)
 #  define stopped_action(rsc, node, optional) custom_action(		\
 		rsc, stopped_key(rsc), CRMD_ACTION_STOPPED, node,	\
 		optional, TRUE, data_set);
 
 #  define stop_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_STOP, 0)
 #  define stop_action(rsc, node, optional) custom_action(			\
 		rsc, stop_key(rsc), CRMD_ACTION_STOP, node,		\
 		optional, TRUE, data_set);
 
 #  define reload_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_RELOAD, 0)
 #  define start_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_START, 0)
 #  define start_action(rsc, node, optional) custom_action(		\
 		rsc, start_key(rsc), CRMD_ACTION_START, node,		\
 		optional, TRUE, data_set)
 
 #  define started_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_STARTED, 0)
 #  define started_action(rsc, node, optional) custom_action(		\
 		rsc, started_key(rsc), CRMD_ACTION_STARTED, node,	\
 		optional, TRUE, data_set)
 
 #  define promote_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_PROMOTE, 0)
 #  define promote_action(rsc, node, optional) custom_action(		\
 		rsc, promote_key(rsc), CRMD_ACTION_PROMOTE, node,	\
 		optional, TRUE, data_set)
 
 #  define promoted_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_PROMOTED, 0)
 #  define promoted_action(rsc, node, optional) custom_action(		\
 		rsc, promoted_key(rsc), CRMD_ACTION_PROMOTED, node,	\
 		optional, TRUE, data_set)
 
 #  define demote_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_DEMOTE, 0)
 #  define demote_action(rsc, node, optional) custom_action(		\
 		rsc, demote_key(rsc), CRMD_ACTION_DEMOTE, node,		\
 		optional, TRUE, data_set)
 
 #  define demoted_key(rsc) pcmk__op_key(rsc->id, CRMD_ACTION_DEMOTED, 0)
 #  define demoted_action(rsc, node, optional) custom_action(		\
 		rsc, demoted_key(rsc), CRMD_ACTION_DEMOTED, node,	\
 		optional, TRUE, data_set)
 
 extern int pe_get_configured_timeout(pe_resource_t *rsc, const char *action,
                                      pe_working_set_t *data_set);
 
 extern pe_action_t *find_first_action(GListPtr input, const char *uuid, const char *task,
                                       pe_node_t * on_node);
 extern enum action_tasks get_complex_task(pe_resource_t * rsc, const char *name,
                                           gboolean allow_non_atomic);
 
 extern GListPtr find_actions(GListPtr input, const char *key, const pe_node_t *on_node);
 GList *find_actions_exact(GList *input, const char *key,
                           const pe_node_t *on_node);
 extern GListPtr find_recurring_actions(GListPtr input, pe_node_t * not_on_node);
 GList *pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node,
                             const char *task, bool require_node);
 
 extern void pe_free_action(pe_action_t * action);
 
 extern void resource_location(pe_resource_t * rsc, pe_node_t * node, int score, const char *tag,
                               pe_working_set_t * data_set);
 
 extern gint sort_op_by_callid(gconstpointer a, gconstpointer b);
 extern gboolean get_target_role(pe_resource_t * rsc, enum rsc_role_e *role);
 
 extern pe_resource_t *find_clone_instance(pe_resource_t * rsc, const char *sub_id,
                                           pe_working_set_t * data_set);
 
 extern void destroy_ticket(gpointer data);
 extern pe_ticket_t *ticket_new(const char *ticket_id, pe_working_set_t * data_set);
 
 // Resources for manipulating resource names
 const char *pe_base_name_end(const char *id);
 char *clone_strip(const char *last_rsc_id);
 char *clone_zero(const char *last_rsc_id);
 
 static inline bool
 pe_base_name_eq(pe_resource_t *rsc, const char *id)
 {
     if (id && rsc && rsc->id) {
         // Number of characters in rsc->id before any clone suffix
         size_t base_len = pe_base_name_end(rsc->id) - rsc->id + 1;
 
         return (strlen(id) == base_len) && !strncmp(id, rsc->id, base_len);
     }
     return FALSE;
 }
 
 int pe__target_rc_from_xml(xmlNode *xml_op);
 
 gint sort_node_uname(gconstpointer a, gconstpointer b);
 bool is_set_recursive(pe_resource_t * rsc, long long flag, bool any);
 
 enum rsc_digest_cmp_val {
     /*! Digests are the same */
     RSC_DIGEST_MATCH = 0,
     /*! Params that require a restart changed */
     RSC_DIGEST_RESTART,
     /*! Some parameter changed.  */
     RSC_DIGEST_ALL,
     /*! rsc op didn't have a digest associated with it, so
      *  it is unknown if parameters changed or not. */
     RSC_DIGEST_UNKNOWN,
 };
 
 typedef struct op_digest_cache_s {
     enum rsc_digest_cmp_val rc;
     xmlNode *params_all;
     xmlNode *params_secure;
     xmlNode *params_restart;
     char *digest_all_calc;
     char *digest_secure_calc;
     char *digest_restart_calc;
 } op_digest_cache_t;
 
 op_digest_cache_t *rsc_action_digest_cmp(pe_resource_t * rsc, xmlNode * xml_op, pe_node_t * node,
                                          pe_working_set_t * data_set);
 
 pe_action_t *pe_fence_op(pe_node_t * node, const char *op, bool optional, const char *reason, bool priority_delay, pe_working_set_t * data_set);
 void trigger_unfencing(
     pe_resource_t * rsc, pe_node_t *node, const char *reason, pe_action_t *dependency, pe_working_set_t * data_set);
 
 void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite);
 void pe_action_set_flag_reason(const char *function, long line, pe_action_t *action, pe_action_t *reason, const char *text, enum pe_action_flags flags, bool overwrite);
 
 #define pe_action_required(action, reason, text) pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, reason, text, pe_action_optional, FALSE)
 #define pe_action_implies(action, reason, flag) pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, reason, NULL, flag, FALSE)
 
 void set_bit_recursive(pe_resource_t * rsc, unsigned long long flag);
 void clear_bit_recursive(pe_resource_t * rsc, unsigned long long flag);
 
 gboolean add_tag_ref(GHashTable * tags, const char * tag_name,  const char * obj_ref);
 
 void print_rscs_brief(GListPtr rsc_list, const char * pre_text, long options,
                       void * print_data, gboolean print_all);
 int pe__rscs_brief_output(pcmk__output_t *out, GListPtr rsc_list, long options, gboolean print_all);
 void pe_fence_node(pe_working_set_t * data_set, pe_node_t * node, const char *reason, bool priority_delay);
 
 pe_node_t *pe_create_node(const char *id, const char *uname, const char *type,
                           const char *score, pe_working_set_t * data_set);
 void common_print(pe_resource_t * rsc, const char *pre_text, const char *name, pe_node_t *node, long options, void *print_data);
 int pe__common_output_text(pcmk__output_t *out, pe_resource_t * rsc, const char *name, pe_node_t *node, long options);
 int pe__common_output_html(pcmk__output_t *out, pe_resource_t * rsc, const char *name, pe_node_t *node, long options);
 pe_resource_t *pe__find_bundle_replica(const pe_resource_t *bundle,
                                        const pe_node_t *node);
 bool pe__bundle_needs_remote_name(pe_resource_t *rsc);
 const char *pe__add_bundle_remote_name(pe_resource_t *rsc, xmlNode *xml,
                                        const char *field);
 const char *pe_node_attribute_calculated(const pe_node_t *node,
                                          const char *name,
                                          const pe_resource_t *rsc);
 const char *pe_node_attribute_raw(pe_node_t *node, const char *name);
 bool pe__is_universal_clone(pe_resource_t *rsc,
                             pe_working_set_t *data_set);
 void pe__add_param_check(xmlNode *rsc_op, pe_resource_t *rsc, pe_node_t *node,
                          enum pe_check_parameters, pe_working_set_t *data_set);
 void pe__foreach_param_check(pe_working_set_t *data_set,
                              void (*cb)(pe_resource_t*, pe_node_t*, xmlNode*,
                                         enum pe_check_parameters,
                                         pe_working_set_t*));
 void pe__free_param_checks(pe_working_set_t *data_set);
 
 bool pe__shutdown_requested(pe_node_t *node);
 void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set);
 
 #define BOOL2STR(x) ((x) ? "true" : "false")
 /*!
  * \internal
  * \brief Register xml formatting message functions.
  */
 void pe__register_messages(pcmk__output_t *out);
 
 void pe__unpack_dataset_nvpairs(xmlNode *xml_obj, const char *set_name,
                                 GHashTable *node_hash, GHashTable *hash,
                                 const char *always_first, gboolean overwrite,
                                 pe_working_set_t *data_set);
 
 bool pe__resource_is_disabled(pe_resource_t *rsc);
 pe_action_t *pe__clear_resource_history(pe_resource_t *rsc, pe_node_t *node,
                                         pe_working_set_t *data_set);
 
+gchar **pe__unames_with_tag(pe_working_set_t *data_set, const char *tag_name);
+bool pe__uname_has_tag(pe_working_set_t *data_set, const char *node, const char *tag);
+
 #endif
diff --git a/lib/pengine/Makefile.am b/lib/pengine/Makefile.am
index eb981c93ae..4aa81797aa 100644
--- a/lib/pengine/Makefile.am
+++ b/lib/pengine/Makefile.am
@@ -1,50 +1,51 @@
 #
 # Copyright 2004-2018 the Pacemaker project contributors
 #
 # The version control history for this file may have further details.
 #
 # This source code is licensed under the GNU General Public License version 2
 # or later (GPLv2+) WITHOUT ANY WARRANTY.
 #
 include $(top_srcdir)/mk/common.mk
 
 SUBDIRS = tests
 
 ## libraries
 lib_LTLIBRARIES		= libpe_rules.la libpe_status.la
 
 ## SOURCES
 noinst_HEADERS		= unpack.h variant.h pe_status_private.h
 
 libpe_rules_la_LDFLAGS	= -version-info 27:0:1
 
 libpe_rules_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
 libpe_rules_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
 
 libpe_rules_la_LIBADD	= $(top_builddir)/lib/common/libcrmcommon.la
 libpe_rules_la_SOURCES	= rules.c rules_alerts.c common.c
 
 libpe_status_la_LDFLAGS	= -version-info 29:0:1
 
 libpe_status_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
 libpe_status_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
 
 libpe_status_la_LIBADD	= @CURSESLIBS@ $(top_builddir)/lib/common/libcrmcommon.la
 # Use += rather than backlashed continuation lines for parsing by bumplibs.sh
 libpe_status_la_SOURCES	=
 libpe_status_la_SOURCES	+= bundle.c
 libpe_status_la_SOURCES	+= clone.c
 libpe_status_la_SOURCES	+= common.c
 libpe_status_la_SOURCES	+= complex.c
 libpe_status_la_SOURCES	+= failcounts.c
 libpe_status_la_SOURCES	+= group.c
 libpe_status_la_SOURCES	+= native.c
 libpe_status_la_SOURCES	+= remote.c
 libpe_status_la_SOURCES	+= rules.c
 libpe_status_la_SOURCES	+= status.c
+libpe_status_la_SOURCES	+= tags.c
 libpe_status_la_SOURCES	+= unpack.c
 libpe_status_la_SOURCES	+= utils.c
 libpe_status_la_SOURCES	+= pe_output.c
 
 clean-generic:
 	rm -f *.log *.debug *~
diff --git a/lib/pengine/tags.c b/lib/pengine/tags.c
new file mode 100644
index 0000000000..9cfb7c474a
--- /dev/null
+++ b/lib/pengine/tags.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU Lesser General Public License
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+gchar **
+pe__unames_with_tag(pe_working_set_t *data_set, const char *tag_name)
+{
+    gpointer value;
+    GPtrArray *arr = NULL;
+    gchar **retval = NULL;
+
+    if (data_set->tags == NULL) {
+        return retval;
+    }
+
+    value = g_hash_table_lookup(data_set->tags, tag_name);
+
+    if (value == NULL) {
+        return retval;
+    }
+
+    /* Iterate over the list of node IDs. */
+    for (GListPtr refs = ((pe_tag_t *) value)->refs; refs; refs = refs->next) {
+        /* Find the node that has this ID. */
+        const char *id = (const char *) refs->data;
+        pe_node_t *node = pe_find_node_id(data_set->nodes, id);
+
+        if (!node) {
+            continue;
+        }
+
+        if (arr == NULL) {
+            arr = g_ptr_array_new();
+        }
+
+        /* Get the uname for the node and add it to the return list. */
+        g_ptr_array_add(arr, g_strdup((gchar *) node->details->uname));
+    }
+
+    if (arr == NULL) {
+        return NULL;
+    }
+
+    /* Convert the GPtrArray into a gchar **. */
+    retval = calloc(arr->len+1, sizeof(gchar *));
+    for (int i = 0; i < arr->len; i++) {
+        retval[i] = (gchar *) g_ptr_array_index(arr, i);
+    }
+
+    g_ptr_array_free(arr, FALSE);
+    return retval;
+}
+
+bool
+pe__uname_has_tag(pe_working_set_t *data_set, const char *node_name, const char *tag_name)
+{
+    gchar **unames = pe__unames_with_tag(data_set, tag_name);
+    bool retval = false;
+
+    if (unames == NULL) {
+        return retval;
+    }
+
+    retval = g_strv_contains((const gchar * const *) unames, node_name);
+    g_strfreev(unames);
+    return retval;
+}
diff --git a/tools/crm_diff.c b/tools/crm_diff.c
index 9c81da174f..c5690483e1 100644
--- a/tools/crm_diff.c
+++ b/tools/crm_diff.c
@@ -1,399 +1,399 @@
 /*
  * Copyright 2005-2018 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
  */
 
 #include 
 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
 #define SUMMARY "Compare two Pacemaker configurations (in XML format) to produce a custom diff-like output, " \
                 "or apply such an output as a patch"
 
 struct {
     gboolean apply;
     gboolean as_cib;
     gboolean no_version;
     gboolean raw_1;
     gboolean raw_2;
     gboolean use_stdin;
     char *xml_file_1;
     char *xml_file_2;
 } options;
 
 gboolean new_string_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 gboolean original_string_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 gboolean patch_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
 
 static GOptionEntry original_xml_entries[] = {
     { "original", 'o', 0, G_OPTION_ARG_STRING, &options.xml_file_1,
       "XML is contained in the named file",
       "FILE" },
     { "original-string", 'O', 0, G_OPTION_ARG_CALLBACK, original_string_cb,
       "XML is contained in the supplied string",
       "STRING" },
 
     { NULL }
 };
 
 static GOptionEntry operation_entries[] = {
     { "new", 'n', 0, G_OPTION_ARG_STRING, &options.xml_file_2,
       "Compare the original XML to the contents of the named file",
       "FILE" },
     { "new-string", 'N', 0, G_OPTION_ARG_CALLBACK, new_string_cb,
       "Compare the original XML with the contents of the supplied string",
       "STRING" },
     { "patch", 'p', 0, G_OPTION_ARG_CALLBACK, patch_cb,
       "Patch the original XML with the contents of the named file",
       "FILE" },
 
     { NULL }
 };
 
 static GOptionEntry addl_entries[] = {
     { "cib", 'c', 0, G_OPTION_ARG_NONE, &options.as_cib,
       "Compare/patch the inputs as a CIB (includes versions details)",
       NULL },
     { "stdin", 's', 0, G_OPTION_ARG_NONE, &options.use_stdin,
       "",
       NULL },
     { "no-version", 'u', 0, G_OPTION_ARG_NONE, &options.no_version,
       "Generate the difference without versions details",
       NULL },
 
     { NULL }
 };
 
 gboolean
 new_string_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     options.raw_2 = TRUE;
 
     if (options.xml_file_2 != NULL) {
         free(options.xml_file_2);
     }
 
     options.xml_file_2 = strdup(optarg);
     return TRUE;
 }
 
 gboolean
 original_string_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     options.raw_1 = TRUE;
 
     if (options.xml_file_1 != NULL) {
         free(options.xml_file_1);
     }
 
     options.xml_file_1 = strdup(optarg);
     return TRUE;
 }
 
 gboolean
 patch_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
     options.apply = TRUE;
 
     if (options.xml_file_2 != NULL) {
         free(options.xml_file_2);
     }
 
     options.xml_file_2 = strdup(optarg);
     return TRUE;
 }
 
 static void
 print_patch(xmlNode *patch)
 {
     char *buffer = dump_xml_formatted(patch);
 
     printf("%s\n", crm_str(buffer));
     free(buffer);
     fflush(stdout);
 }
 
 static int
 apply_patch(xmlNode *input, xmlNode *patch, gboolean as_cib)
 {
     int rc;
     xmlNode *output = copy_xml(input);
 
     rc = xml_apply_patchset(output, patch, as_cib);
     if (rc != pcmk_ok) {
         fprintf(stderr, "Could not apply patch: %s\n", pcmk_strerror(rc));
         free_xml(output);
         return rc;
     }
 
     if (output != NULL) {
         const char *version;
         char *buffer;
 
         print_patch(output);
 
         version = crm_element_value(output, XML_ATTR_CRM_VERSION);
         buffer = calculate_xml_versioned_digest(output, FALSE, TRUE, version);
         crm_trace("Digest: %s\n", crm_str(buffer));
         free(buffer);
         free_xml(output);
     }
     return pcmk_ok;
 }
 
 static void
 log_patch_cib_versions(xmlNode *patch)
 {
     int add[] = { 0, 0, 0 };
     int del[] = { 0, 0, 0 };
 
     const char *fmt = NULL;
     const char *digest = NULL;
 
     xml_patch_versions(patch, add, del);
     fmt = crm_element_value(patch, "format");
     digest = crm_element_value(patch, XML_ATTR_DIGEST);
 
     if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) {
         crm_info("Patch: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
         crm_info("Patch: +++ %d.%d.%d %s", add[0], add[1], add[2], digest);
     }
 }
 
 static void
 strip_patch_cib_version(xmlNode *patch, const char **vfields, size_t nvfields)
 {
     int format = 1;
 
     crm_element_value_int(patch, "format", &format);
     if (format == 2) {
         xmlNode *version_xml = find_xml_node(patch, "version", FALSE);
 
         if (version_xml) {
             free_xml(version_xml);
         }
 
     } else {
         int i = 0;
 
         const char *tags[] = {
             XML_TAG_DIFF_REMOVED,
             XML_TAG_DIFF_ADDED,
         };
 
         for (i = 0; i < DIMOF(tags); i++) {
             xmlNode *tmp = NULL;
             int lpc;
 
             tmp = find_xml_node(patch, tags[i], FALSE);
             if (tmp) {
                 for (lpc = 0; lpc < nvfields; lpc++) {
                     xml_remove_prop(tmp, vfields[lpc]);
                 }
 
                 tmp = find_xml_node(tmp, XML_TAG_CIB, FALSE);
                 if (tmp) {
                     for (lpc = 0; lpc < nvfields; lpc++) {
                         xml_remove_prop(tmp, vfields[lpc]);
                     }
                 }
             }
         }
     }
 }
 
 static int
 generate_patch(xmlNode *object_1, xmlNode *object_2, const char *xml_file_2,
                gboolean as_cib, gboolean no_version)
 {
     xmlNode *output = NULL;
 
     const char *vfields[] = {
         XML_ATTR_GENERATION_ADMIN,
         XML_ATTR_GENERATION,
         XML_ATTR_NUMUPDATES,
     };
 
     /* If we're ignoring the version, make the version information
      * identical, so it isn't detected as a change. */
     if (no_version) {
         int lpc;
 
         for (lpc = 0; lpc < DIMOF(vfields); lpc++) {
             crm_copy_xml_element(object_1, object_2, vfields[lpc]);
         }
     }
 
     xml_track_changes(object_2, NULL, object_2, FALSE);
     if(as_cib) {
         xml_calculate_significant_changes(object_1, object_2);
     } else {
         xml_calculate_changes(object_1, object_2);
     }
     crm_log_xml_debug(object_2, (xml_file_2? xml_file_2: "target"));
 
     output = xml_create_patchset(0, object_1, object_2, NULL, FALSE);
 
     xml_log_changes(LOG_INFO, __FUNCTION__, object_2);
     xml_accept_changes(object_2);
 
     if (output == NULL) {
         return pcmk_ok;
     }
 
     patchset_process_digest(output, object_1, object_2, as_cib);
 
     if (as_cib) {
         log_patch_cib_versions(output);
 
     } else if (no_version) {
         strip_patch_cib_version(output, vfields, DIMOF(vfields));
     }
 
     xml_log_patchset(LOG_NOTICE, __FUNCTION__, output);
     print_patch(output);
     free_xml(output);
     return -pcmk_err_generic;
 }
 
 static GOptionContext *
 build_arg_context(pcmk__common_args_t *args) {
     GOptionContext *context = NULL;
 
-    const char *description = "*Examples*\n\n"
+    const char *description = "Examples:\n\n"
                               "Obtain the two different configuration files by running cibadmin on the two cluster setups to compare:\n\n"
-                              "\tcibadmin --query > cib-old.xml\n"
-                              "\tcibadmin --query > cib-new.xml\n\n"
+                              "\t# cibadmin --query > cib-old.xml\n\n"
+                              "\t# cibadmin --query > cib-new.xml\n\n"
                               "Calculate and save the difference between the two files:\n\n"
-                              "\tcrm_diff --original cib-old.xml --new cib-new.xml > patch.xml\n\n"
+                              "\t# crm_diff --original cib-old.xml --new cib-new.xml > patch.xml\n\n"
                               "Apply the patch to the original file:\n\n"
-                              "\tcrm_diff --original cib-old.xml --patch patch.xml > updated.xml\n\n"
+                              "\t# crm_diff --original cib-old.xml --patch patch.xml > updated.xml\n\n"
                               "Apply the patch to the running cluster:\n\n"
-                              "\tcibadmin --patch patch.xml\n";
+                              "\t# cibadmin --patch -x patch.xml\n";
 
     context = pcmk__build_arg_context(args, NULL, NULL);
     g_option_context_set_description(context, description);
 
     pcmk__add_arg_group(context, "xml", "Original XML:",
                         "Show original XML options", original_xml_entries);
     pcmk__add_arg_group(context, "operation", "Operation:",
                         "Show operation options", operation_entries);
     pcmk__add_arg_group(context, "additional", "Additional Options:",
                         "Show additional options", addl_entries);
     return context;
 }
 
 int
 main(int argc, char **argv)
 {
     int rc = pcmk_ok;
     xmlNode *object_1 = NULL;
     xmlNode *object_2 = NULL;
 
     pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
 
     GError *error = NULL;
     GOptionContext *context = NULL;
     gchar **processed_args = NULL;
 
     context = build_arg_context(args);
 
     crm_log_cli_init("crm_diff");
 
     processed_args = pcmk__cmdline_preproc(argv, "nopNO");
 
     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
         fprintf(stderr, "%s: %s\n", g_get_prgname(), error->message);
         rc = CRM_EX_USAGE;
         goto done;
     }
 
     for (int i = 0; i < args->verbosity; i++) {
         crm_bump_log_level(argc, argv);
     }
 
     if (args->version) {
         /* FIXME:  When crm_diff is converted to use formatted output, this can go. */
         pcmk__cli_help('v', CRM_EX_USAGE);
     }
 
     if (optind > argc) {
         char *help = g_option_context_get_help(context, TRUE, NULL);
 
         fprintf(stderr, "%s", help);
         g_free(help);
         rc = CRM_EX_USAGE;
         goto done;
     }
 
     if (options.apply && options.no_version) {
         fprintf(stderr, "warning: -u/--no-version ignored with -p/--patch\n");
     } else if (options.as_cib && options.no_version) {
         fprintf(stderr, "error: -u/--no-version incompatible with -c/--cib\n");
         rc = CRM_EX_USAGE;
         goto done;
     }
 
     if (options.raw_1) {
         object_1 = string2xml(options.xml_file_1);
 
     } else if (options.use_stdin) {
         fprintf(stderr, "Input first XML fragment:");
         object_1 = stdin2xml();
 
     } else if (options.xml_file_1 != NULL) {
         object_1 = filename2xml(options.xml_file_1);
     }
 
     if (options.raw_2) {
         object_2 = string2xml(options.xml_file_2);
 
     } else if (options.use_stdin) {
         fprintf(stderr, "Input second XML fragment:");
         object_2 = stdin2xml();
 
     } else if (options.xml_file_2 != NULL) {
         object_2 = filename2xml(options.xml_file_2);
     }
 
     if (object_1 == NULL) {
         fprintf(stderr, "Could not parse the first XML fragment\n");
         rc = CRM_EX_DATAERR;
         goto done;
     }
     if (object_2 == NULL) {
         fprintf(stderr, "Could not parse the second XML fragment\n");
         rc = CRM_EX_DATAERR;
         goto done;
     }
 
     if (options.apply) {
         rc = apply_patch(object_1, object_2, options.as_cib);
     } else {
         rc = generate_patch(object_1, object_2, options.xml_file_2, options.as_cib, options.no_version);
     }
 
 done:
     g_strfreev(processed_args);
     g_clear_error(&error);
     pcmk__free_arg_context(context);
     free(options.xml_file_1);
     free(options.xml_file_2);
     free_xml(object_1);
     free_xml(object_2);
     return crm_errno2exit(rc);
 }
diff --git a/xml/Readme.md b/xml/Readme.md
index a8f414d2cb..65c331d93e 100644
--- a/xml/Readme.md
+++ b/xml/Readme.md
@@ -1,142 +1,143 @@
 # Schema Reference
 
 Pacemaker's XML schema has a version of its own, independent of the version of
 Pacemaker itself.
 
 ## Versioned Schema Evolution
 
 A versioned schema offers transparent backward and forward compatibility.
 
 - It reflects the timeline of schema-backed features (introduction,
   changes to the syntax, possibly deprecation) through the versioned
   stable schema increments, while keeping schema versions used by default
   by older Pacemaker versions untouched.
 
 - Pacemaker internally uses the latest stable schema version, and relies on
   supplemental transformations to promote cluster configurations based on
   older, incompatible schema versions into the desired form.
 
 - It allows experimental features with a possibly unstable configuration
   interface to be developed using the special `next` version of the schema.
 
 ## Mapping Pacemaker Versions to Schema Versions
 
 | Pacemaker | Latest Schema | Changed
 | --------- | ------------- | ----------------------------------------------
+| `2.0.4`   | `3.3`         | `tags`
 | `2.0.1`   | `3.2`         | `resources`
 | `2.0.0`   | `3.1`         | `constraints`, `resources`
 | `1.1.18`  | `2.10`        | `resources`, `alerts`
 | `1.1.17`  | `2.9`         | `resources`, `rule`
 | `1.1.16`  | `2.6`         | `constraints`
 | `1.1.15`  | `2.5`         | `alerts`
 | `1.1.14`  | `2.4`         | `fencing`
 | `1.1.13`  | `2.3`         | `constraints`
 | `1.1.12`  | `2.0`         | `nodes`, `nvset`, `resources`, `tags`, `acls`
 | `1.1.8`+  | `1.2`         |
 
 ## Schema generation
 
 Each logical portion of the schema goes into its own RNG file, named like
 `${base}-${X}.${Y}.rng`. `${base}` identifies the portion of the schema
 (e.g. constraints, resources); ${X}.${Y} is the latest schema version that
 contained changes in this portion of the schema.
 
 The complete, overall schema, `pacemaker-${X}.${Y}.rng`, is automatically
 generated from the other files via the Makefile.
 
 # Updating schema files #
 
 ## Experimental features ##
 
 Experimental features go into `${base}-next.rng` where `${base}` is the
 affected portion of the schema. If such a file does not already exist,
 create it by copying the most recent `${base}-${X}.${Y}.rng`.
 
 Pacemaker will not use the experimental schema by default; the cluster
 administrator must explicitly set the `validate-with` property appropriately to
 use it.
 
 ## Stable features ##
 
 The current stable version is determined at runtime when
 crm\_schema\_init() scans the CRM\_SCHEMA\_DIRECTORY.
 
 It will have the form `pacemaker-${X}.${Y}` and the highest
 `${X}.${Y}` wins.
 
 ### Simple Additions
 
 When the new syntax is a simple addition to the previous one, create a
 new entry, incrementing `${Y}`.
 
 ### Feature Removal or otherwise Incompatible Changes
 
 When the new syntax is not a simple addition to the previous one,
 create a new entry, incrementing `${X}` and setting `${Y} = 0`.
 
 An XSLT file is also required that converts an old syntax to the new
 one and must be named `upgrade-${Xold}.${Yold}.xsl`.
 
 See `xml/upgrade-1.3.xsl` for an example.
 
 Since `xml/upgrade-2.10.xsl`, rather self-descriptive approach is taken,
 separating metadata of the replacements and other modifications to
 perform from the actual executive parts, which is leveraged, e.g., with
 the on-the-fly overview as obtained with `./regression.sh -X test2to3`.
 Also this was the first time particular key names of `nvpair`s,
 i.e. below the granularity of the schemas so far, received attention,
 and consequently, no longer expected names became systemically banned
 in the after-upgrade schemas, using `` construct in the
 data type specification pertaining the affected XML path.
 
 The implied complexity also resulted in establishing a new compound,
 stepwise transformation, alleviating the procedural burden from the
 core upgrade recipe.  In particular, `id-ref` based syntactic
 simplification granted in the CIB format introduces nonnegligible
 internal "noise" because of the extra indirection encumbered with
 generally non-bijective character of such a scheme (context-dependent
 interpretation).  To reduce this strain, a symmetric arrangement is
 introduced as a pair of _enter_/_leave_ (pre-upgrade/post-upgrade)
 transformations where the latter is meant to eventually reversibly
 restore what the former intentionally simplified (normalized) for
 upgrade transformation's peruse.  It's optional (even the post-upgrade
 counterpart is optional alone) and depends on whether the suitable
 files are found along the upgrade transformation itself: e.g., for
 `upgrade-2.10.xsl`, such files are `upgrade-2.10-enter.xsl` and
 `upgrade-2.10-leave.xsl`.  Note that unfolding + refolding `id-ref`
 shortcuts is just a practically imposed individual case of how to
 reversibly make the configuration space tractable in the upgrade
 itself, allowing for more sophistication down the road.
 
 ### General Procedure
 
 1. Copy the most recent version of `${base}-*.rng` to `${base}-${X}.${Y}.rng` 
 1. Commit the copy, e.g. `"Low: xml: clone ${base} schema in preparation for
    changes"`. This way, the actual change will be obvious in the commit history.
 1. Modify `${base}-${X}.${Y}.rng` as required.
 1. If required, add an XSLT file, and update `xslt\_SCRIPTS` in `xml/Makefile.am`.
 1. Commit
 1. `make -C xml clean; make -C xml all` to rebuild the schemas in the local
    source directory.
 1. The CIB validity regression tests will break after the schema is updated.
    Run `cts/cts-cli -s` to make the referential outcomes reflect the transient
    changes made so far, `git diff cts/cli/regression.validity.exp` to ensure
    the these changes look sane, and `git add cts/cli/regression.validity.exp`
    to enqueue this change for a subsequent commit.
 1. Similarly, with the new major version `${X}`, it's advisable to refresh
    scheduler tests at some point, see the instructions in `cts/README.md`.
 
 ## Using a New Schema
 
 New features will not be available until the cluster administrator:
 
 1. Updates all the nodes
 1. Runs the equivalent of `cibadmin --upgrade --force`
 
 ## Random Notes
 
 From the source directory, run `make -C xml diff` to see the changes
 in the current schema (compared to the previous ones) and also the
 pending changes in `pacemaker-next`.
 Alternatively, if the intention is to grok the overall historical schema
 evolution, use `make -C xml fulldiff`.
diff --git a/xml/tags-3.3.rng b/xml/tags-3.3.rng
new file mode 100644
index 0000000000..d94d73a106
--- /dev/null
+++ b/xml/tags-3.3.rng
@@ -0,0 +1,25 @@
+
+
+  
+    
+