[pve-devel] [PATCH ha-manager v3 12/13] test: rules: add test cases for resource affinity rules

Daniel Kral d.kral at proxmox.com
Fri Jul 4 20:20:55 CEST 2025


Add test cases to verify that the rule checkers correctly identify and
remove HA Resource Affinity rules from the rules to make the rule set
feasible. The added test cases verify:

- Resource Affinity rules retrieve the correct optional default values
- Resource Affinity rules, which state that two or more resources are to
  be kept together and separate at the same time, are dropped from the
  rule set
- Resource Affinity rules, which cannot be fullfilled because of the
  constraints imposed by the Node Affinity rules of their resources, are
  dropped from the rule set
- Resource Affinity rules, which specify less than two nodes, are
  dropped from the rule set
- Negative resource affinity rules, which specify more nodes than
  available, are dropped from the rule set
- Positive resource affinity rule resources, which overlap with other
  positive resource affinity rules' resources, are merged into a single
  positive resource affinity rule to make them disjoint from each other
- Positive resource affinity rule resources, which are also in negative
  resource affinity rules, implicitly create negative resource affinity
  rules for the other resources as well

Signed-off-by: Daniel Kral <d.kral at proxmox.com>
---
 .../defaults-for-resource-affinity-rules.cfg  |  16 +++
 ...lts-for-resource-affinity-rules.cfg.expect |  38 +++++
 ...onsistent-node-resource-affinity-rules.cfg |  54 ++++++++
 ...nt-node-resource-affinity-rules.cfg.expect | 121 ++++++++++++++++
 .../inconsistent-resource-affinity-rules.cfg  |  11 ++
 ...sistent-resource-affinity-rules.cfg.expect |  11 ++
 ...ctive-negative-resource-affinity-rules.cfg |  17 +++
 ...egative-resource-affinity-rules.cfg.expect |  30 ++++
 .../ineffective-resource-affinity-rules.cfg   |   8 ++
 ...fective-resource-affinity-rules.cfg.expect |   9 ++
 ...licit-negative-resource-affinity-rules.cfg |  40 ++++++
 ...egative-resource-affinity-rules.cfg.expect | 131 ++++++++++++++++++
 ...licit-negative-resource-affinity-rules.cfg |  16 +++
 ...egative-resource-affinity-rules.cfg.expect |  73 ++++++++++
 ...ected-positive-resource-affinity-rules.cfg |  42 ++++++
 ...ositive-resource-affinity-rules.cfg.expect |  70 ++++++++++
 ...-affinity-with-resource-affinity-rules.cfg |  19 +++
 ...ty-with-resource-affinity-rules.cfg.expect |  45 ++++++
 src/test/test_rules_config.pl                 |   2 +
 19 files changed, 753 insertions(+)
 create mode 100644 src/test/rules_cfgs/defaults-for-resource-affinity-rules.cfg
 create mode 100644 src/test/rules_cfgs/defaults-for-resource-affinity-rules.cfg.expect
 create mode 100644 src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg
 create mode 100644 src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg.expect
 create mode 100644 src/test/rules_cfgs/inconsistent-resource-affinity-rules.cfg
 create mode 100644 src/test/rules_cfgs/inconsistent-resource-affinity-rules.cfg.expect
 create mode 100644 src/test/rules_cfgs/ineffective-negative-resource-affinity-rules.cfg
 create mode 100644 src/test/rules_cfgs/ineffective-negative-resource-affinity-rules.cfg.expect
 create mode 100644 src/test/rules_cfgs/ineffective-resource-affinity-rules.cfg
 create mode 100644 src/test/rules_cfgs/ineffective-resource-affinity-rules.cfg.expect
 create mode 100644 src/test/rules_cfgs/infer-implicit-negative-resource-affinity-rules.cfg
 create mode 100644 src/test/rules_cfgs/infer-implicit-negative-resource-affinity-rules.cfg.expect
 create mode 100644 src/test/rules_cfgs/merge-and-infer-implicit-negative-resource-affinity-rules.cfg
 create mode 100644 src/test/rules_cfgs/merge-and-infer-implicit-negative-resource-affinity-rules.cfg.expect
 create mode 100644 src/test/rules_cfgs/merge-connected-positive-resource-affinity-rules.cfg
 create mode 100644 src/test/rules_cfgs/merge-connected-positive-resource-affinity-rules.cfg.expect
 create mode 100644 src/test/rules_cfgs/multi-priority-node-affinity-with-resource-affinity-rules.cfg
 create mode 100644 src/test/rules_cfgs/multi-priority-node-affinity-with-resource-affinity-rules.cfg.expect

diff --git a/src/test/rules_cfgs/defaults-for-resource-affinity-rules.cfg b/src/test/rules_cfgs/defaults-for-resource-affinity-rules.cfg
new file mode 100644
index 0000000..a0fb4e0
--- /dev/null
+++ b/src/test/rules_cfgs/defaults-for-resource-affinity-rules.cfg
@@ -0,0 +1,16 @@
+# Case 1: Resource Affinity rules are enabled by default, so set it so if it isn't yet.
+resource-affinity: resource-affinity-defaults
+	resources vm:101,vm:102
+	affinity negative
+
+# Case 2: Resource Affinity rule is disabled, it shouldn't be enabled afterwards.
+resource-affinity: resource-affinity-disabled
+	resources vm:201,vm:202
+	affinity negative
+	disable
+
+# Case 3: Resource Affinity rule is disabled with explicit 1 set, it shouldn't be enabled afterwards.
+resource-affinity: resource-affinity-disabled-explicit
+	resources vm:301,vm:302
+	affinity negative
+	disable 1
diff --git a/src/test/rules_cfgs/defaults-for-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/defaults-for-resource-affinity-rules.cfg.expect
new file mode 100644
index 0000000..7384b0b
--- /dev/null
+++ b/src/test/rules_cfgs/defaults-for-resource-affinity-rules.cfg.expect
@@ -0,0 +1,38 @@
+--- Log ---
+--- Config ---
+$VAR1 = {
+          'digest' => '9ac7cc517f02c41e3403085ec02f6a9259f2ac94',
+          'ids' => {
+                     'resource-affinity-defaults' => {
+                                                       'affinity' => 'negative',
+                                                       'resources' => {
+                                                                        'vm:101' => 1,
+                                                                        'vm:102' => 1
+                                                                      },
+                                                       'type' => 'resource-affinity'
+                                                     },
+                     'resource-affinity-disabled' => {
+                                                       'affinity' => 'negative',
+                                                       'disable' => 1,
+                                                       'resources' => {
+                                                                        'vm:201' => 1,
+                                                                        'vm:202' => 1
+                                                                      },
+                                                       'type' => 'resource-affinity'
+                                                     },
+                     'resource-affinity-disabled-explicit' => {
+                                                                'affinity' => 'negative',
+                                                                'disable' => 1,
+                                                                'resources' => {
+                                                                                 'vm:301' => 1,
+                                                                                 'vm:302' => 1
+                                                                               },
+                                                                'type' => 'resource-affinity'
+                                                              }
+                   },
+          'order' => {
+                       'resource-affinity-defaults' => 1,
+                       'resource-affinity-disabled' => 2,
+                       'resource-affinity-disabled-explicit' => 3
+                     }
+        };
diff --git a/src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg b/src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg
new file mode 100644
index 0000000..9c93193
--- /dev/null
+++ b/src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg
@@ -0,0 +1,54 @@
+# Case 1: Remove no positive resource affinity rule, where there is exactly one node to keep them together.
+node-affinity: vm101-vm102-must-be-on-node1
+	resources vm:101,vm:102
+	nodes node1
+	strict 1
+
+resource-affinity: vm101-vm102-must-be-kept-together
+	resources vm:101,vm:102
+	affinity positive
+
+# Case 2: Remove no negative resource affinity rule, where there are exactly enough nodes available to keep them apart.
+node-affinity: vm201-must-be-on-node1
+	resources vm:201
+	nodes node1
+	strict 1
+
+node-affinity: vm202-must-be-on-node2
+	resources vm:202
+	nodes node2
+	strict 1
+
+resource-affinity: vm201-vm202-must-be-kept-separate
+	resources vm:201,vm:202
+	affinity negative
+
+# Case 1: Remove the positive resource affinity rules, where two resources are restricted to a different node.
+node-affinity: vm301-must-be-on-node1
+	resources vm:301
+	nodes node1
+	strict 1
+
+node-affinity: vm301-must-be-on-node2
+	resources vm:302
+	nodes node2
+	strict 1
+
+resource-affinity: vm301-vm302-must-be-kept-together
+	resources vm:301,vm:302
+	affinity positive
+
+# Case 2: Remove the negative resource affinity rule, where two resources are restricted to less nodes than needed to keep them apart.
+node-affinity: vm401-must-be-on-node1
+	resources vm:401
+	nodes node1
+	strict 1
+
+node-affinity: vm402-must-be-on-node1
+	resources vm:402
+	nodes node1
+	strict 1
+
+resource-affinity: vm401-vm402-must-be-kept-separate
+	resources vm:401,vm:402
+	affinity negative
diff --git a/src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg.expect
new file mode 100644
index 0000000..a2b898d
--- /dev/null
+++ b/src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg.expect
@@ -0,0 +1,121 @@
+--- Log ---
+Drop rule 'vm301-vm302-must-be-kept-together', because two or more resources are restricted to different nodes.
+Drop rule 'vm401-vm402-must-be-kept-separate', because two or more resources are restricted to less nodes than available to the resources.
+--- Config ---
+$VAR1 = {
+          'digest' => '2125f6ec9743b24d6eb9ac8273ea90525cdd0d5a',
+          'ids' => {
+                     'vm101-vm102-must-be-kept-together' => {
+                                                              'affinity' => 'positive',
+                                                              'resources' => {
+                                                                               'vm:101' => 1,
+                                                                               'vm:102' => 1
+                                                                             },
+                                                              'type' => 'resource-affinity'
+                                                            },
+                     'vm101-vm102-must-be-on-node1' => {
+                                                         'nodes' => {
+                                                                      'node1' => {
+                                                                                   'priority' => 0
+                                                                                 }
+                                                                    },
+                                                         'resources' => {
+                                                                          'vm:101' => 1,
+                                                                          'vm:102' => 1
+                                                                        },
+                                                         'strict' => 1,
+                                                         'type' => 'node-affinity'
+                                                       },
+                     'vm201-must-be-on-node1' => {
+                                                   'nodes' => {
+                                                                'node1' => {
+                                                                             'priority' => 0
+                                                                           }
+                                                              },
+                                                   'resources' => {
+                                                                    'vm:201' => 1
+                                                                  },
+                                                   'strict' => 1,
+                                                   'type' => 'node-affinity'
+                                                 },
+                     'vm201-vm202-must-be-kept-separate' => {
+                                                              'affinity' => 'negative',
+                                                              'resources' => {
+                                                                               'vm:201' => 1,
+                                                                               'vm:202' => 1
+                                                                             },
+                                                              'type' => 'resource-affinity'
+                                                            },
+                     'vm202-must-be-on-node2' => {
+                                                   'nodes' => {
+                                                                'node2' => {
+                                                                             'priority' => 0
+                                                                           }
+                                                              },
+                                                   'resources' => {
+                                                                    'vm:202' => 1
+                                                                  },
+                                                   'strict' => 1,
+                                                   'type' => 'node-affinity'
+                                                 },
+                     'vm301-must-be-on-node1' => {
+                                                   'nodes' => {
+                                                                'node1' => {
+                                                                             'priority' => 0
+                                                                           }
+                                                              },
+                                                   'resources' => {
+                                                                    'vm:301' => 1
+                                                                  },
+                                                   'strict' => 1,
+                                                   'type' => 'node-affinity'
+                                                 },
+                     'vm301-must-be-on-node2' => {
+                                                   'nodes' => {
+                                                                'node2' => {
+                                                                             'priority' => 0
+                                                                           }
+                                                              },
+                                                   'resources' => {
+                                                                    'vm:302' => 1
+                                                                  },
+                                                   'strict' => 1,
+                                                   'type' => 'node-affinity'
+                                                 },
+                     'vm401-must-be-on-node1' => {
+                                                   'nodes' => {
+                                                                'node1' => {
+                                                                             'priority' => 0
+                                                                           }
+                                                              },
+                                                   'resources' => {
+                                                                    'vm:401' => 1
+                                                                  },
+                                                   'strict' => 1,
+                                                   'type' => 'node-affinity'
+                                                 },
+                     'vm402-must-be-on-node1' => {
+                                                   'nodes' => {
+                                                                'node1' => {
+                                                                             'priority' => 0
+                                                                           }
+                                                              },
+                                                   'resources' => {
+                                                                    'vm:402' => 1
+                                                                  },
+                                                   'strict' => 1,
+                                                   'type' => 'node-affinity'
+                                                 }
+                   },
+          'order' => {
+                       'vm101-vm102-must-be-kept-together' => 2,
+                       'vm101-vm102-must-be-on-node1' => 1,
+                       'vm201-must-be-on-node1' => 3,
+                       'vm201-vm202-must-be-kept-separate' => 5,
+                       'vm202-must-be-on-node2' => 4,
+                       'vm301-must-be-on-node1' => 6,
+                       'vm301-must-be-on-node2' => 7,
+                       'vm401-must-be-on-node1' => 9,
+                       'vm402-must-be-on-node1' => 10
+                     }
+        };
diff --git a/src/test/rules_cfgs/inconsistent-resource-affinity-rules.cfg b/src/test/rules_cfgs/inconsistent-resource-affinity-rules.cfg
new file mode 100644
index 0000000..a620e29
--- /dev/null
+++ b/src/test/rules_cfgs/inconsistent-resource-affinity-rules.cfg
@@ -0,0 +1,11 @@
+resource-affinity: keep-apart1
+	resources vm:102,vm:103
+	affinity negative
+
+resource-affinity: keep-apart2
+	resources vm:102,vm:104,vm:106
+	affinity negative
+
+resource-affinity: stick-together1
+	resources vm:101,vm:102,vm:103,vm:104,vm:106
+	affinity positive
diff --git a/src/test/rules_cfgs/inconsistent-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/inconsistent-resource-affinity-rules.cfg.expect
new file mode 100644
index 0000000..b0cde0f
--- /dev/null
+++ b/src/test/rules_cfgs/inconsistent-resource-affinity-rules.cfg.expect
@@ -0,0 +1,11 @@
+--- Log ---
+Drop rule 'keep-apart1', because rule shares two or more resources with 'stick-together1'.
+Drop rule 'keep-apart2', because rule shares two or more resources with 'stick-together1'.
+Drop rule 'stick-together1', because rule shares two or more resources with 'keep-apart1'.
+Drop rule 'stick-together1', because rule shares two or more resources with 'keep-apart2'.
+--- Config ---
+$VAR1 = {
+          'digest' => '50875b320034d8ac7dded185e590f5f87c4e2bb6',
+          'ids' => {},
+          'order' => {}
+        };
diff --git a/src/test/rules_cfgs/ineffective-negative-resource-affinity-rules.cfg b/src/test/rules_cfgs/ineffective-negative-resource-affinity-rules.cfg
new file mode 100644
index 0000000..c0f18d2
--- /dev/null
+++ b/src/test/rules_cfgs/ineffective-negative-resource-affinity-rules.cfg
@@ -0,0 +1,17 @@
+# Case 1: Do not remove negative resource affinity rules, which do define less resources than available nodes (3).
+resource-affinity: do-not-remove-me1
+	resources vm:101,vm:102
+	affinity negative
+
+resource-affinity: do-not-remove-me2
+	resources vm:101,vm:102,vm:103
+	affinity negative
+
+# Case 1: Remove negative resource affinity rules, which do define more resources than available nodes (3).
+resource-affinity: remove-me1
+	resources vm:101,vm:102,vm:103,vm:104
+	affinity negative
+
+resource-affinity: remove-me2
+	resources vm:101,vm:102,vm:103,vm:104,vm:105
+	affinity negative
diff --git a/src/test/rules_cfgs/ineffective-negative-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/ineffective-negative-resource-affinity-rules.cfg.expect
new file mode 100644
index 0000000..8a2b879
--- /dev/null
+++ b/src/test/rules_cfgs/ineffective-negative-resource-affinity-rules.cfg.expect
@@ -0,0 +1,30 @@
+--- Log ---
+Drop rule 'remove-me1', because rule defines more resources than available nodes.
+Drop rule 'remove-me2', because rule defines more resources than available nodes.
+--- Config ---
+$VAR1 = {
+          'digest' => '68633cedeeb355ef78fe28221ef3f16537b3e788',
+          'ids' => {
+                     'do-not-remove-me1' => {
+                                              'affinity' => 'negative',
+                                              'resources' => {
+                                                               'vm:101' => 1,
+                                                               'vm:102' => 1
+                                                             },
+                                              'type' => 'resource-affinity'
+                                            },
+                     'do-not-remove-me2' => {
+                                              'affinity' => 'negative',
+                                              'resources' => {
+                                                               'vm:101' => 1,
+                                                               'vm:102' => 1,
+                                                               'vm:103' => 1
+                                                             },
+                                              'type' => 'resource-affinity'
+                                            }
+                   },
+          'order' => {
+                       'do-not-remove-me1' => 1,
+                       'do-not-remove-me2' => 2
+                     }
+        };
diff --git a/src/test/rules_cfgs/ineffective-resource-affinity-rules.cfg b/src/test/rules_cfgs/ineffective-resource-affinity-rules.cfg
new file mode 100644
index 0000000..32f977b
--- /dev/null
+++ b/src/test/rules_cfgs/ineffective-resource-affinity-rules.cfg
@@ -0,0 +1,8 @@
+# Case 1: Remove resource affinity rules, which do not have enough resources to be effective.
+resource-affinity: lonely-resource1
+	resources vm:101
+	affinity positive
+
+resource-affinity: lonely-resource2
+	resources vm:101
+	affinity negative
diff --git a/src/test/rules_cfgs/ineffective-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/ineffective-resource-affinity-rules.cfg.expect
new file mode 100644
index 0000000..b2d468b
--- /dev/null
+++ b/src/test/rules_cfgs/ineffective-resource-affinity-rules.cfg.expect
@@ -0,0 +1,9 @@
+--- Log ---
+Drop rule 'lonely-resource1', because rule is ineffective as there are less than two resources.
+Drop rule 'lonely-resource2', because rule is ineffective as there are less than two resources.
+--- Config ---
+$VAR1 = {
+          'digest' => 'fe89f8c8f5acc29f807eaa0cec5974b6e957a596',
+          'ids' => {},
+          'order' => {}
+        };
diff --git a/src/test/rules_cfgs/infer-implicit-negative-resource-affinity-rules.cfg b/src/test/rules_cfgs/infer-implicit-negative-resource-affinity-rules.cfg
new file mode 100644
index 0000000..db26286
--- /dev/null
+++ b/src/test/rules_cfgs/infer-implicit-negative-resource-affinity-rules.cfg
@@ -0,0 +1,40 @@
+# Case 1: Do not infer any negative resource affinity rules, if there are no resources of a positive
+#         resource affinity rule in any negative resource affinity rules.
+resource-affinity: do-not-infer-positive1
+	resources vm:101,vm:102,vm:103
+	affinity positive
+
+# Case 2: Infer negative resource affinity rules with one resource in a negative resource affinity rule.
+resource-affinity: infer-simple-positive1
+	resources vm:201,vm:202,vm:203
+	affinity positive
+
+resource-affinity: infer-simple-negative1
+	resources vm:201,vm:204
+	affinity negative
+
+# Case 3: Infer negative resource affinity rules with two resources in different negative resource affinity rules.
+resource-affinity: infer-two-positive1
+	resources vm:301,vm:302,vm:303
+	affinity positive
+
+resource-affinity: infer-two-negative1
+	resources vm:303,vm:304
+	affinity negative
+
+resource-affinity: infer-two-negative2
+	resources vm:302,vm:305
+	affinity negative
+
+# Case 4: Do not infer negative resource affinity rules from inconsistent resource affinity rules.
+resource-affinity: do-not-infer-inconsistent-positive1
+	resources vm:401,vm:402,vm:403
+	affinity positive
+
+resource-affinity: do-not-infer-inconsistent-negative1
+	resources vm:401,vm:404
+	affinity negative
+
+resource-affinity: do-not-infer-inconsistent-negative2
+	resources vm:402,vm:403,vm:405
+	affinity negative
diff --git a/src/test/rules_cfgs/infer-implicit-negative-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/infer-implicit-negative-resource-affinity-rules.cfg.expect
new file mode 100644
index 0000000..bcd368a
--- /dev/null
+++ b/src/test/rules_cfgs/infer-implicit-negative-resource-affinity-rules.cfg.expect
@@ -0,0 +1,131 @@
+--- Log ---
+Drop rule 'do-not-infer-inconsistent-negative2', because rule shares two or more resources with 'do-not-infer-inconsistent-positive1'.
+Drop rule 'do-not-infer-inconsistent-positive1', because rule shares two or more resources with 'do-not-infer-inconsistent-negative2'.
+--- Config ---
+$VAR1 = {
+          'digest' => 'd8724dfe2130bb642b98e021da973aa0ec0695f0',
+          'ids' => {
+                     '_implicit-negative-infer-simple-positive1-vm:202-vm:204' => {
+                                                                                    'affinity' => 'negative',
+                                                                                    'resources' => {
+                                                                                                     'vm:202' => 1,
+                                                                                                     'vm:204' => 1
+                                                                                                   },
+                                                                                    'type' => 'resource-affinity'
+                                                                                  },
+                     '_implicit-negative-infer-simple-positive1-vm:203-vm:204' => {
+                                                                                    'affinity' => 'negative',
+                                                                                    'resources' => {
+                                                                                                     'vm:203' => 1,
+                                                                                                     'vm:204' => 1
+                                                                                                   },
+                                                                                    'type' => 'resource-affinity'
+                                                                                  },
+                     '_implicit-negative-infer-two-positive1-vm:301-vm:304' => {
+                                                                                 'affinity' => 'negative',
+                                                                                 'resources' => {
+                                                                                                  'vm:301' => 1,
+                                                                                                  'vm:304' => 1
+                                                                                                },
+                                                                                 'type' => 'resource-affinity'
+                                                                               },
+                     '_implicit-negative-infer-two-positive1-vm:301-vm:305' => {
+                                                                                 'affinity' => 'negative',
+                                                                                 'resources' => {
+                                                                                                  'vm:301' => 1,
+                                                                                                  'vm:305' => 1
+                                                                                                },
+                                                                                 'type' => 'resource-affinity'
+                                                                               },
+                     '_implicit-negative-infer-two-positive1-vm:302-vm:304' => {
+                                                                                 'affinity' => 'negative',
+                                                                                 'resources' => {
+                                                                                                  'vm:302' => 1,
+                                                                                                  'vm:304' => 1
+                                                                                                },
+                                                                                 'type' => 'resource-affinity'
+                                                                               },
+                     '_implicit-negative-infer-two-positive1-vm:303-vm:305' => {
+                                                                                 'affinity' => 'negative',
+                                                                                 'resources' => {
+                                                                                                  'vm:303' => 1,
+                                                                                                  'vm:305' => 1
+                                                                                                },
+                                                                                 'type' => 'resource-affinity'
+                                                                               },
+                     'do-not-infer-inconsistent-negative1' => {
+                                                                'affinity' => 'negative',
+                                                                'resources' => {
+                                                                                 'vm:401' => 1,
+                                                                                 'vm:404' => 1
+                                                                               },
+                                                                'type' => 'resource-affinity'
+                                                              },
+                     'do-not-infer-positive1' => {
+                                                   'affinity' => 'positive',
+                                                   'resources' => {
+                                                                    'vm:101' => 1,
+                                                                    'vm:102' => 1,
+                                                                    'vm:103' => 1
+                                                                  },
+                                                   'type' => 'resource-affinity'
+                                                 },
+                     'infer-simple-negative1' => {
+                                                   'affinity' => 'negative',
+                                                   'resources' => {
+                                                                    'vm:201' => 1,
+                                                                    'vm:204' => 1
+                                                                  },
+                                                   'type' => 'resource-affinity'
+                                                 },
+                     'infer-simple-positive1' => {
+                                                   'affinity' => 'positive',
+                                                   'resources' => {
+                                                                    'vm:201' => 1,
+                                                                    'vm:202' => 1,
+                                                                    'vm:203' => 1
+                                                                  },
+                                                   'type' => 'resource-affinity'
+                                                 },
+                     'infer-two-negative1' => {
+                                                'affinity' => 'negative',
+                                                'resources' => {
+                                                                 'vm:303' => 1,
+                                                                 'vm:304' => 1
+                                                               },
+                                                'type' => 'resource-affinity'
+                                              },
+                     'infer-two-negative2' => {
+                                                'affinity' => 'negative',
+                                                'resources' => {
+                                                                 'vm:302' => 1,
+                                                                 'vm:305' => 1
+                                                               },
+                                                'type' => 'resource-affinity'
+                                              },
+                     'infer-two-positive1' => {
+                                                'affinity' => 'positive',
+                                                'resources' => {
+                                                                 'vm:301' => 1,
+                                                                 'vm:302' => 1,
+                                                                 'vm:303' => 1
+                                                               },
+                                                'type' => 'resource-affinity'
+                                              }
+                   },
+          'order' => {
+                       '_implicit-negative-infer-simple-positive1-vm:202-vm:204' => 2,
+                       '_implicit-negative-infer-simple-positive1-vm:203-vm:204' => 2,
+                       '_implicit-negative-infer-two-positive1-vm:301-vm:304' => 2,
+                       '_implicit-negative-infer-two-positive1-vm:301-vm:305' => 2,
+                       '_implicit-negative-infer-two-positive1-vm:302-vm:304' => 2,
+                       '_implicit-negative-infer-two-positive1-vm:303-vm:305' => 2,
+                       'do-not-infer-inconsistent-negative1' => 8,
+                       'do-not-infer-positive1' => 1,
+                       'infer-simple-negative1' => 3,
+                       'infer-simple-positive1' => 2,
+                       'infer-two-negative1' => 5,
+                       'infer-two-negative2' => 6,
+                       'infer-two-positive1' => 4
+                     }
+        };
diff --git a/src/test/rules_cfgs/merge-and-infer-implicit-negative-resource-affinity-rules.cfg b/src/test/rules_cfgs/merge-and-infer-implicit-negative-resource-affinity-rules.cfg
new file mode 100644
index 0000000..5694bde
--- /dev/null
+++ b/src/test/rules_cfgs/merge-and-infer-implicit-negative-resource-affinity-rules.cfg
@@ -0,0 +1,16 @@
+# Case 1: Infer negative resource affinity rules from connected positive resource affinity rules.
+resource-affinity: infer-connected-positive1
+	resources vm:101,vm:102
+	affinity positive
+
+resource-affinity: infer-connected-positive2
+	resources vm:102,vm:103
+	affinity positive
+
+resource-affinity: infer-connected-negative1
+	resources vm:101,vm:104
+	affinity negative
+
+resource-affinity: infer-connected-negative2
+	resources vm:102,vm:105
+	affinity negative
diff --git a/src/test/rules_cfgs/merge-and-infer-implicit-negative-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/merge-and-infer-implicit-negative-resource-affinity-rules.cfg.expect
new file mode 100644
index 0000000..876c203
--- /dev/null
+++ b/src/test/rules_cfgs/merge-and-infer-implicit-negative-resource-affinity-rules.cfg.expect
@@ -0,0 +1,73 @@
+--- Log ---
+--- Config ---
+$VAR1 = {
+          'digest' => '5695bd62a65966a275a62a01d2d8fbc370d91668',
+          'ids' => {
+                     '_implicit-negative-_merged-infer-connected-positive1-infer-connected-positive2-vm:101-vm:105' => {
+                                                                                                                         'affinity' => 'negative',
+                                                                                                                         'resources' => {
+                                                                                                                                          'vm:101' => 1,
+                                                                                                                                          'vm:105' => 1
+                                                                                                                                        },
+                                                                                                                         'type' => 'resource-affinity'
+                                                                                                                       },
+                     '_implicit-negative-_merged-infer-connected-positive1-infer-connected-positive2-vm:102-vm:104' => {
+                                                                                                                         'affinity' => 'negative',
+                                                                                                                         'resources' => {
+                                                                                                                                          'vm:102' => 1,
+                                                                                                                                          'vm:104' => 1
+                                                                                                                                        },
+                                                                                                                         'type' => 'resource-affinity'
+                                                                                                                       },
+                     '_implicit-negative-_merged-infer-connected-positive1-infer-connected-positive2-vm:103-vm:104' => {
+                                                                                                                         'affinity' => 'negative',
+                                                                                                                         'resources' => {
+                                                                                                                                          'vm:103' => 1,
+                                                                                                                                          'vm:104' => 1
+                                                                                                                                        },
+                                                                                                                         'type' => 'resource-affinity'
+                                                                                                                       },
+                     '_implicit-negative-_merged-infer-connected-positive1-infer-connected-positive2-vm:103-vm:105' => {
+                                                                                                                         'affinity' => 'negative',
+                                                                                                                         'resources' => {
+                                                                                                                                          'vm:103' => 1,
+                                                                                                                                          'vm:105' => 1
+                                                                                                                                        },
+                                                                                                                         'type' => 'resource-affinity'
+                                                                                                                       },
+                     '_merged-infer-connected-positive1-infer-connected-positive2' => {
+                                                                                        'affinity' => 'positive',
+                                                                                        'resources' => {
+                                                                                                         'vm:101' => 1,
+                                                                                                         'vm:102' => 1,
+                                                                                                         'vm:103' => 1
+                                                                                                       },
+                                                                                        'type' => 'resource-affinity'
+                                                                                      },
+                     'infer-connected-negative1' => {
+                                                      'affinity' => 'negative',
+                                                      'resources' => {
+                                                                       'vm:101' => 1,
+                                                                       'vm:104' => 1
+                                                                     },
+                                                      'type' => 'resource-affinity'
+                                                    },
+                     'infer-connected-negative2' => {
+                                                      'affinity' => 'negative',
+                                                      'resources' => {
+                                                                       'vm:102' => 1,
+                                                                       'vm:105' => 1
+                                                                     },
+                                                      'type' => 'resource-affinity'
+                                                    }
+                   },
+          'order' => {
+                       '_implicit-negative-_merged-infer-connected-positive1-infer-connected-positive2-vm:101-vm:105' => 2,
+                       '_implicit-negative-_merged-infer-connected-positive1-infer-connected-positive2-vm:102-vm:104' => 2,
+                       '_implicit-negative-_merged-infer-connected-positive1-infer-connected-positive2-vm:103-vm:104' => 2,
+                       '_implicit-negative-_merged-infer-connected-positive1-infer-connected-positive2-vm:103-vm:105' => 2,
+                       '_merged-infer-connected-positive1-infer-connected-positive2' => 1,
+                       'infer-connected-negative1' => 3,
+                       'infer-connected-negative2' => 4
+                     }
+        };
diff --git a/src/test/rules_cfgs/merge-connected-positive-resource-affinity-rules.cfg b/src/test/rules_cfgs/merge-connected-positive-resource-affinity-rules.cfg
new file mode 100644
index 0000000..8954a27
--- /dev/null
+++ b/src/test/rules_cfgs/merge-connected-positive-resource-affinity-rules.cfg
@@ -0,0 +1,42 @@
+# Case 1: Do not merge any negative resource affinity rules.
+resource-affinity: do-not-merge-negative1
+	resources vm:101,vm:102
+	affinity negative
+
+resource-affinity: do-not-merge-negative2
+	resources vm:102,vm:103
+	affinity negative
+
+resource-affinity: do-not-merge-negative3
+	resources vm:104,vm:105
+	affinity negative
+
+# Case 2: Do not merge unconnected positive resource affinity rules.
+resource-affinity: do-not-merge-positive1
+	resources vm:201,vm:202
+	affinity positive
+
+resource-affinity: do-not-merge-positive2
+	resources vm:203,vm:204
+	affinity positive
+
+# Case 3: Merge connected positive resource affinity rules.
+resource-affinity: merge-positive1
+	resources vm:301,vm:302
+	affinity positive
+
+resource-affinity: merge-positive2
+	resources vm:303,vm:305,vm:307
+	affinity positive
+
+resource-affinity: merge-positive3
+	resources vm:302,vm:303
+	affinity positive
+
+resource-affinity: merge-positive4
+	resources vm:302,vm:304,vm:306
+	affinity positive
+
+resource-affinity: merge-positive5
+	resources vm:307,vm:308,vm:309
+	affinity positive
diff --git a/src/test/rules_cfgs/merge-connected-positive-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/merge-connected-positive-resource-affinity-rules.cfg.expect
new file mode 100644
index 0000000..e57a792
--- /dev/null
+++ b/src/test/rules_cfgs/merge-connected-positive-resource-affinity-rules.cfg.expect
@@ -0,0 +1,70 @@
+--- Log ---
+--- Config ---
+$VAR1 = {
+          'digest' => '920d9caac206fc0dd893753bfb2cab3e6d6a9b9b',
+          'ids' => {
+                     '_merged-merge-positive1-merge-positive3-merge-positive4-merge-positive2-merge-positive5' => {
+                                                                                                                    'affinity' => 'positive',
+                                                                                                                    'resources' => {
+                                                                                                                                     'vm:301' => 1,
+                                                                                                                                     'vm:302' => 1,
+                                                                                                                                     'vm:303' => 1,
+                                                                                                                                     'vm:304' => 1,
+                                                                                                                                     'vm:305' => 1,
+                                                                                                                                     'vm:306' => 1,
+                                                                                                                                     'vm:307' => 1,
+                                                                                                                                     'vm:308' => 1,
+                                                                                                                                     'vm:309' => 1
+                                                                                                                                   },
+                                                                                                                    'type' => 'resource-affinity'
+                                                                                                                  },
+                     'do-not-merge-negative1' => {
+                                                   'affinity' => 'negative',
+                                                   'resources' => {
+                                                                    'vm:101' => 1,
+                                                                    'vm:102' => 1
+                                                                  },
+                                                   'type' => 'resource-affinity'
+                                                 },
+                     'do-not-merge-negative2' => {
+                                                   'affinity' => 'negative',
+                                                   'resources' => {
+                                                                    'vm:102' => 1,
+                                                                    'vm:103' => 1
+                                                                  },
+                                                   'type' => 'resource-affinity'
+                                                 },
+                     'do-not-merge-negative3' => {
+                                                   'affinity' => 'negative',
+                                                   'resources' => {
+                                                                    'vm:104' => 1,
+                                                                    'vm:105' => 1
+                                                                  },
+                                                   'type' => 'resource-affinity'
+                                                 },
+                     'do-not-merge-positive1' => {
+                                                   'affinity' => 'positive',
+                                                   'resources' => {
+                                                                    'vm:201' => 1,
+                                                                    'vm:202' => 1
+                                                                  },
+                                                   'type' => 'resource-affinity'
+                                                 },
+                     'do-not-merge-positive2' => {
+                                                   'affinity' => 'positive',
+                                                   'resources' => {
+                                                                    'vm:203' => 1,
+                                                                    'vm:204' => 1
+                                                                  },
+                                                   'type' => 'resource-affinity'
+                                                 }
+                   },
+          'order' => {
+                       '_merged-merge-positive1-merge-positive3-merge-positive4-merge-positive2-merge-positive5' => 6,
+                       'do-not-merge-negative1' => 1,
+                       'do-not-merge-negative2' => 2,
+                       'do-not-merge-negative3' => 3,
+                       'do-not-merge-positive1' => 4,
+                       'do-not-merge-positive2' => 5
+                     }
+        };
diff --git a/src/test/rules_cfgs/multi-priority-node-affinity-with-resource-affinity-rules.cfg b/src/test/rules_cfgs/multi-priority-node-affinity-with-resource-affinity-rules.cfg
new file mode 100644
index 0000000..28504e3
--- /dev/null
+++ b/src/test/rules_cfgs/multi-priority-node-affinity-with-resource-affinity-rules.cfg
@@ -0,0 +1,19 @@
+# Case 1: Remove resource affinity rules, where there is a loose Node Affinity rule with multiple priority groups set for the nodes.
+node-affinity: vm101-vm102-should-be-on-node1-or-node2
+	resources vm:101,vm:102
+	nodes node1:1,node2:2
+	strict 0
+
+resource-affinity: vm101-vm102-must-be-kept-separate
+	resources vm:101,vm:102
+	affinity negative
+
+# Case 2: Remove resource affinity rules, where there is a strict Node Affinity rule with multiple priority groups set for the nodes.
+node-affinity: vm201-vm202-must-be-on-node1-or-node2
+	resources vm:201,vm:202
+	nodes node1:1,node2:2
+	strict 1
+
+resource-affinity: vm201-vm202-must-be-kept-together
+	resources vm:201,vm:202
+	affinity positive
diff --git a/src/test/rules_cfgs/multi-priority-node-affinity-with-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/multi-priority-node-affinity-with-resource-affinity-rules.cfg.expect
new file mode 100644
index 0000000..41517f5
--- /dev/null
+++ b/src/test/rules_cfgs/multi-priority-node-affinity-with-resource-affinity-rules.cfg.expect
@@ -0,0 +1,45 @@
+--- Log ---
+Drop rule 'vm101-vm102-must-be-kept-separate', because resources are in node affinity rules with multiple priorities.
+Drop rule 'vm201-vm202-must-be-kept-together', because resources are in node affinity rules with multiple priorities.
+--- Config ---
+$VAR1 = {
+          'digest' => 'b9dab8eba68f60c1a6e75138b5c129de8ad284ee',
+          'ids' => {
+                     'vm101-vm102-should-be-on-node1-or-node2' => {
+                                                                    'nodes' => {
+                                                                                 'node1' => {
+                                                                                              'priority' => 1
+                                                                                            },
+                                                                                 'node2' => {
+                                                                                              'priority' => 2
+                                                                                            }
+                                                                               },
+                                                                    'resources' => {
+                                                                                     'vm:101' => 1,
+                                                                                     'vm:102' => 1
+                                                                                   },
+                                                                    'strict' => 0,
+                                                                    'type' => 'node-affinity'
+                                                                  },
+                     'vm201-vm202-must-be-on-node1-or-node2' => {
+                                                                  'nodes' => {
+                                                                               'node1' => {
+                                                                                            'priority' => 1
+                                                                                          },
+                                                                               'node2' => {
+                                                                                            'priority' => 2
+                                                                                          }
+                                                                             },
+                                                                  'resources' => {
+                                                                                   'vm:201' => 1,
+                                                                                   'vm:202' => 1
+                                                                                 },
+                                                                  'strict' => 1,
+                                                                  'type' => 'node-affinity'
+                                                                }
+                   },
+          'order' => {
+                       'vm101-vm102-should-be-on-node1-or-node2' => 1,
+                       'vm201-vm202-must-be-on-node1-or-node2' => 3
+                     }
+        };
diff --git a/src/test/test_rules_config.pl b/src/test/test_rules_config.pl
index d49d14f..c2a7af4 100755
--- a/src/test/test_rules_config.pl
+++ b/src/test/test_rules_config.pl
@@ -13,8 +13,10 @@ use Data::Dumper;
 
 use PVE::HA::Rules;
 use PVE::HA::Rules::NodeAffinity;
+use PVE::HA::Rules::ResourceAffinity;
 
 PVE::HA::Rules::NodeAffinity->register();
+PVE::HA::Rules::ResourceAffinity->register();
 
 PVE::HA::Rules->init(property_isolation => 1);
 
-- 
2.39.5





More information about the pve-devel mailing list