From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 544531FF141 for ; Tue, 02 Jun 2026 12:03:57 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 93506E8D3; Tue, 2 Jun 2026 12:03:26 +0200 (CEST) From: Daniel Kral To: pve-devel@lists.proxmox.com Subject: [PATCH ha-manager v2 01/12] rules: node affinity: add affinity property to node affinity rules Date: Tue, 2 Jun 2026 12:01:05 +0200 Message-ID: <20260602100226.180071-2-d.kral@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260602100226.180071-1-d.kral@proxmox.com> References: <20260602100226.180071-1-d.kral@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1780394515227 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.101 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LOTSOFHASH 0.25 Emails with lots of hash-like gibberish PROLO_LEO1 0.1 Meta Catches all Leo drug variations so far SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: MZHSFI7ZWFGRPWPRKMHHYICFGBIW74V3 X-Message-ID-Hash: MZHSFI7ZWFGRPWPRKMHHYICFGBIW74V3 X-MailFrom: d.kral@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This is in preparation of the next patch, which adds negative node affinity rules. Signed-off-by: Daniel Kral Reviewed-by: Fiona Ebner --- changes since v1: - none src/PVE/HA/Groups.pm | 1 + src/PVE/HA/Rules/NodeAffinity.pm | 9 +++++++++ src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg | 8 ++++---- .../defaults-for-node-affinity-rules.cfg.expect | 6 +++++- .../inconsistent-node-resource-affinity-rules.cfg.expect | 3 +++ ...inity-for-positive-resource-affinity-rules.cfg.expect | 4 ++++ ...node-affinity-with-resource-affinity-rules.cfg.expect | 2 ++ ...tiple-resource-refs-in-node-affinity-rules.cfg.expect | 3 +++ 8 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/PVE/HA/Groups.pm b/src/PVE/HA/Groups.pm index fef7eeb1..ecdfcbcd 100644 --- a/src/PVE/HA/Groups.pm +++ b/src/PVE/HA/Groups.pm @@ -147,6 +147,7 @@ sub migrate_groups_to_rules { type => 'node-affinity', resources => $resources, nodes => $nodes, + affinity => 'positive', strict => $groups->{ids}->{$group}->{restricted}, comment => $groups->{ids}->{$group}->{comment}, }; diff --git a/src/PVE/HA/Rules/NodeAffinity.pm b/src/PVE/HA/Rules/NodeAffinity.pm index 3fa1fdb4..1f15ae2d 100644 --- a/src/PVE/HA/Rules/NodeAffinity.pm +++ b/src/PVE/HA/Rules/NodeAffinity.pm @@ -64,6 +64,14 @@ sub properties { optional => 0, }, ), + affinity => { + description => "Describes whether the HA resources are supposed to" + . " be placed on the given nodes ('positive').", + type => 'string', + enum => ['positive'], + default => 'positive', + optional => 1, + }, strict => { description => "Describes whether the node affinity rule is strict or non-strict.", verbose_description => < { optional => 0 }, nodes => { optional => 0 }, + affinity => { optional => 1 }, strict => { optional => 1 }, disable => { optional => 1 }, comment => { optional => 1 }, diff --git a/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg b/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg index c8b2f2dd..27658562 100644 --- a/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg +++ b/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg @@ -1,21 +1,21 @@ -# Case 1: Node Affinity rules are enabled and loose by default, so set it so if it isn't yet. +# Case 1: Node Affinity rules are enabled, positive and loose by default, so set it so if it isn't yet. node-affinity: node-affinity-defaults resources vm:101 nodes node1 -# Case 2: Node Affinity rule is disabled, it shouldn't be enabled afterwards. +# Case 2: Positive Node Affinity rule is disabled, it shouldn't be enabled afterwards. node-affinity: node-affinity-disabled resources vm:102 nodes node2 disable -# Case 3: Node Affinity rule is disabled with explicit 1 set, it shouldn't be enabled afterwards. +# Case 3: Positive Node Affinity rule is disabled with explicit 1 set, it shouldn't be enabled afterwards. node-affinity: node-affinity-disabled-explicit resources vm:103 nodes node2 disable 1 -# Case 4: Node Affinity rule is set to strict, so it shouldn't be loose afterwards. +# Case 4: Positive Node Affinity rule is set to strict, so it shouldn't be loose afterwards. node-affinity: node-affinity-strict resources vm:104 nodes node3 diff --git a/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg.expect b/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg.expect index 35d061bd..0d6e5605 100644 --- a/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg.expect +++ b/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg.expect @@ -1,9 +1,10 @@ --- Log --- --- Config --- { - "digest" : "c96c9de143221a82e44efa8bb4814b8248a8ea11", + "digest" : "fcad82def12abc4422061b79cfd0399967053d93", "ids" : { "node-affinity-defaults" : { + "affinity" : "positive", "nodes" : { "node1" : { "priority" : 0 @@ -15,6 +16,7 @@ "type" : "node-affinity" }, "node-affinity-disabled" : { + "affinity" : "positive", "disable" : 1, "nodes" : { "node2" : { @@ -27,6 +29,7 @@ "type" : "node-affinity" }, "node-affinity-disabled-explicit" : { + "affinity" : "positive", "disable" : 1, "nodes" : { "node2" : { @@ -39,6 +42,7 @@ "type" : "node-affinity" }, "node-affinity-strict" : { + "affinity" : "positive", "nodes" : { "node3" : { "priority" : 0 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 index 4317292b..42dbc004 100644 --- a/src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg.expect +++ b/src/test/rules_cfgs/inconsistent-node-resource-affinity-rules.cfg.expect @@ -22,6 +22,7 @@ Drop rule 'vm503-must-be-on-node2', because at least one resource is in a positi "type" : "resource-affinity" }, "vm101-vm102-must-be-on-node1" : { + "affinity" : "positive", "nodes" : { "node1" : { "priority" : 0 @@ -35,6 +36,7 @@ Drop rule 'vm503-must-be-on-node2', because at least one resource is in a positi "type" : "node-affinity" }, "vm201-must-be-on-node1" : { + "affinity" : "positive", "nodes" : { "node1" : { "priority" : 0 @@ -55,6 +57,7 @@ Drop rule 'vm503-must-be-on-node2', because at least one resource is in a positi "type" : "resource-affinity" }, "vm202-must-be-on-node2" : { + "affinity" : "positive", "nodes" : { "node2" : { "priority" : 0 diff --git a/src/test/rules_cfgs/infer-node-affinity-for-positive-resource-affinity-rules.cfg.expect b/src/test/rules_cfgs/infer-node-affinity-for-positive-resource-affinity-rules.cfg.expect index ed339777..db505420 100644 --- a/src/test/rules_cfgs/infer-node-affinity-for-positive-resource-affinity-rules.cfg.expect +++ b/src/test/rules_cfgs/infer-node-affinity-for-positive-resource-affinity-rules.cfg.expect @@ -4,6 +4,7 @@ "digest" : "32ae135ef2f8bd84cd12c18af6910dce9d6bc9fa", "ids" : { "do-not-infer-negative1" : { + "affinity" : "positive", "nodes" : { "node1" : { "priority" : 0 @@ -19,6 +20,7 @@ "type" : "node-affinity" }, "do-not-infer-negative2" : { + "affinity" : "positive", "nodes" : { "node3" : { "priority" : 0 @@ -47,6 +49,7 @@ "type" : "resource-affinity" }, "infer-multi-resources1" : { + "affinity" : "positive", "nodes" : { "node1" : { "priority" : 0 @@ -76,6 +79,7 @@ "type" : "resource-affinity" }, "infer-single-resource1" : { + "affinity" : "positive", "nodes" : { "node3" : { "priority" : 0 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 index 68a2b75f..cc6595ac 100644 --- 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 @@ -8,6 +8,7 @@ Drop rule 'vm201-vm202-must-be-on-node1-or-node2', because resources are in a re "digest" : "722a98914555f296af0916c980a9d6c780f5f072", "ids" : { "vm301-must-be-on-node1-with-prio-1" : { + "affinity" : "positive", "nodes" : { "node1" : { "priority" : 1 @@ -28,6 +29,7 @@ Drop rule 'vm201-vm202-must-be-on-node1-or-node2', because resources are in a re "type" : "resource-affinity" }, "vm302-must-be-on-node2-with-prio-2" : { + "affinity" : "positive", "nodes" : { "node2" : { "priority" : 2 diff --git a/src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg.expect b/src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg.expect index 425de2b1..2776b56b 100644 --- a/src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg.expect +++ b/src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg.expect @@ -7,6 +7,7 @@ Drop rule 'same-resource3', because resource 'vm:201' is already used in another "digest" : "5865d23b1a342e7f8cfa68bd0e1da556ca8d28a6", "ids" : { "no-same-resource1" : { + "affinity" : "positive", "nodes" : { "node1" : { "priority" : 0 @@ -24,6 +25,7 @@ Drop rule 'same-resource3', because resource 'vm:201' is already used in another "type" : "node-affinity" }, "no-same-resource2" : { + "affinity" : "positive", "nodes" : { "node1" : { "priority" : 0 @@ -40,6 +42,7 @@ Drop rule 'same-resource3', because resource 'vm:201' is already used in another "type" : "node-affinity" }, "no-same-resource3" : { + "affinity" : "positive", "nodes" : { "node1" : { "priority" : 0 -- 2.47.3