public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Daniel Kral <d.kral@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH ha-manager v3 12/13] test: rules: add test cases for resource affinity rules
Date: Fri,  4 Jul 2025 20:20:55 +0200	[thread overview]
Message-ID: <20250704182102.467624-13-d.kral@proxmox.com> (raw)
In-Reply-To: <20250704182102.467624-1-d.kral@proxmox.com>

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@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



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


  parent reply	other threads:[~2025-07-04 18:21 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-04 18:20 [pve-devel] [PATCH container/docs/ha-manager/manager/qemu-server v3 00/19] HA " Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 01/13] rules: introduce plugin-specific canonicalize routines Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 02/13] rules: add haenv node list to the rules' canonicalization stage Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 03/13] rules: introduce resource affinity rule plugin Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 04/13] rules: add global checks between node and resource affinity rules Daniel Kral
2025-07-29 11:44   ` Michael Köppl
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 05/13] usage: add information about a service's assigned nodes Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 06/13] manager: apply resource affinity rules when selecting service nodes Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 07/13] manager: handle resource affinity rules in manual migrations Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 08/13] sim: resources: add option to limit start and migrate tries to node Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 09/13] test: ha tester: add test cases for negative resource affinity rules Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 10/13] test: ha tester: add test cases for positive " Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 11/13] test: ha tester: add test cases for static scheduler resource affinity Daniel Kral
2025-07-04 18:20 ` Daniel Kral [this message]
2025-07-04 18:20 ` [pve-devel] [PATCH ha-manager v3 13/13] api: resources: add check for resource affinity in resource migrations Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH docs v3 1/1] ha: add documentation about ha resource affinity rules Daniel Kral
2025-07-08 16:08   ` Shannon Sterz
2025-07-09  6:19     ` Friedrich Weber
2025-07-30 10:05     ` Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH manager v3 1/3] ui: ha: rules: add " Daniel Kral
2025-07-04 18:20 ` [pve-devel] [PATCH manager v3 2/3] ui: migrate: lxc: display precondition messages for ha resource affinity Daniel Kral
2025-07-04 18:21 ` [pve-devel] [PATCH manager v3 3/3] ui: migrate: vm: " Daniel Kral
2025-07-04 18:21 ` [pve-devel] [PATCH container v3 1/1] api: introduce migration preconditions api endpoint Daniel Kral
2025-07-04 18:21 ` [pve-devel] [PATCH qemu-server v3 1/1] api: migration preconditions: add checks for ha resource affinity rules Daniel Kral

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250704182102.467624-13-d.kral@proxmox.com \
    --to=d.kral@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal