From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 057B91FF17A for ; Fri, 4 Jul 2025 20:17:52 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 32CAE3CD67; Fri, 4 Jul 2025 20:17:29 +0200 (CEST) From: Daniel Kral To: pve-devel@lists.proxmox.com Date: Fri, 4 Jul 2025 20:16:52 +0200 Message-Id: <20250704181659.465441-14-d.kral@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250704181659.465441-1-d.kral@proxmox.com> References: <20250704181659.465441-1-d.kral@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.013 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 SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH ha-manager v3 12/15] test: add test cases for rules config X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" Add test cases to verify that the rule checkers correctly identify and remove HA rules from the rules to make the rule set feasible. For now, there only are HA Node Affinity rules, which verify: - Node Affinity rules retrieve the correct optional default values - Node Affinity rules, which specify the same HA resource more than once, are dropped from the rule set Signed-off-by: Daniel Kral --- .gitignore | 1 + src/test/Makefile | 4 +- .../defaults-for-node-affinity-rules.cfg | 22 ++++ ...efaults-for-node-affinity-rules.cfg.expect | 60 +++++++++++ ...e-resource-refs-in-node-affinity-rules.cfg | 31 ++++++ ...rce-refs-in-node-affinity-rules.cfg.expect | 63 +++++++++++ src/test/test_rules_config.pl | 100 ++++++++++++++++++ 7 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg create mode 100644 src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg.expect create mode 100644 src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg create mode 100644 src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg.expect create mode 100755 src/test/test_rules_config.pl diff --git a/.gitignore b/.gitignore index c35280e..35de63f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /src/test/test-*/status/* /src/test/fence_cfgs/*.cfg.commands /src/test/fence_cfgs/*.cfg.write +/src/test/rules_cfgs/*.cfg.output diff --git a/src/test/Makefile b/src/test/Makefile index e54959f..6da9e10 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -5,6 +5,7 @@ all: test: @echo "-- start regression tests --" ./test_failover1.pl + ./test_rules_config.pl ./ha-tester.pl ./test_fence_config.pl @echo "-- end regression tests (success) --" @@ -12,4 +13,5 @@ test: .PHONY: clean clean: rm -rf *~ test-*/log test-*/*~ test-*/status \ - fence_cfgs/*.cfg.commands fence_cfgs/*.write + fence_cfgs/*.cfg.commands fence_cfgs/*.write \ + rules_cfgs/*.cfg.output diff --git a/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg b/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg new file mode 100644 index 0000000..c8b2f2d --- /dev/null +++ b/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg @@ -0,0 +1,22 @@ +# Case 1: Node Affinity rules are enabled 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. +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. +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. +node-affinity: node-affinity-strict + resources vm:104 + nodes node3 + strict 1 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 new file mode 100644 index 0000000..59a2c36 --- /dev/null +++ b/src/test/rules_cfgs/defaults-for-node-affinity-rules.cfg.expect @@ -0,0 +1,60 @@ +--- Log --- +--- Config --- +$VAR1 = { + 'digest' => 'c96c9de143221a82e44efa8bb4814b8248a8ea11', + 'ids' => { + 'node-affinity-defaults' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + } + }, + 'resources' => { + 'vm:101' => 1 + }, + 'type' => 'node-affinity' + }, + 'node-affinity-disabled' => { + 'disable' => 1, + 'nodes' => { + 'node2' => { + 'priority' => 0 + } + }, + 'resources' => { + 'vm:102' => 1 + }, + 'type' => 'node-affinity' + }, + 'node-affinity-disabled-explicit' => { + 'disable' => 1, + 'nodes' => { + 'node2' => { + 'priority' => 0 + } + }, + 'resources' => { + 'vm:103' => 1 + }, + 'type' => 'node-affinity' + }, + 'node-affinity-strict' => { + 'nodes' => { + 'node3' => { + 'priority' => 0 + } + }, + 'resources' => { + 'vm:104' => 1 + }, + 'strict' => 1, + 'type' => 'node-affinity' + } + }, + 'order' => { + 'node-affinity-defaults' => 1, + 'node-affinity-disabled' => 2, + 'node-affinity-disabled-explicit' => 3, + 'node-affinity-strict' => 4 + } + }; diff --git a/src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg b/src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg new file mode 100644 index 0000000..1e279e7 --- /dev/null +++ b/src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg @@ -0,0 +1,31 @@ +# Case 1: Do not remove two Node Affinity rules, which do not share resources. +node-affinity: no-same-resource1 + resources vm:101,vm:102,vm:103 + nodes node1,node2:2 + strict 0 + +node-affinity: no-same-resource2 + resources vm:104,vm:105 + nodes node1,node2:2 + strict 0 + +node-affinity: no-same-resource3 + resources vm:106 + nodes node1,node2:2 + strict 1 + +# Case 2: Remove Node Affinity rules, which share the same resource between them. +node-affinity: same-resource1 + resources vm:201 + nodes node1,node2:2 + strict 0 + +node-affinity: same-resource2 + resources vm:201,vm:202 + nodes node3 + strict 1 + +node-affinity: same-resource3 + resources vm:201,vm:203,vm:204 + nodes node1:2,node3:3 + strict 0 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 new file mode 100644 index 0000000..3fd0c9c --- /dev/null +++ b/src/test/rules_cfgs/multiple-resource-refs-in-node-affinity-rules.cfg.expect @@ -0,0 +1,63 @@ +--- Log --- +Drop rule 'same-resource1', because resource 'vm:201' is already used in another node affinity rule. +Drop rule 'same-resource2', because resource 'vm:201' is already used in another node affinity rule. +Drop rule 'same-resource3', because resource 'vm:201' is already used in another node affinity rule. +--- Config --- +$VAR1 = { + 'digest' => '5865d23b1a342e7f8cfa68bd0e1da556ca8d28a6', + 'ids' => { + 'no-same-resource1' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + }, + 'node2' => { + 'priority' => 2 + } + }, + 'resources' => { + 'vm:101' => 1, + 'vm:102' => 1, + 'vm:103' => 1 + }, + 'strict' => 0, + 'type' => 'node-affinity' + }, + 'no-same-resource2' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + }, + 'node2' => { + 'priority' => 2 + } + }, + 'resources' => { + 'vm:104' => 1, + 'vm:105' => 1 + }, + 'strict' => 0, + 'type' => 'node-affinity' + }, + 'no-same-resource3' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + }, + 'node2' => { + 'priority' => 2 + } + }, + 'resources' => { + 'vm:106' => 1 + }, + 'strict' => 1, + 'type' => 'node-affinity' + } + }, + 'order' => { + 'no-same-resource1' => 1, + 'no-same-resource2' => 2, + 'no-same-resource3' => 3 + } + }; diff --git a/src/test/test_rules_config.pl b/src/test/test_rules_config.pl new file mode 100755 index 0000000..824afed --- /dev/null +++ b/src/test/test_rules_config.pl @@ -0,0 +1,100 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Getopt::Long; + +use lib qw(..); + +use Test::More; +use Test::MockModule; + +use Data::Dumper; + +use PVE::HA::Rules; +use PVE::HA::Rules::NodeAffinity; + +PVE::HA::Rules::NodeAffinity->register(); + +PVE::HA::Rules->init(property_isolation => 1); + +my $opt_nodiff; + +if (!GetOptions("nodiff" => \$opt_nodiff)) { + print "usage: $0 [test.cfg] [--nodiff]\n"; + exit -1; +} + +sub _log { + my ($fh, $source, $message) = @_; + + chomp $message; + $message = "[$source] $message" if $source; + + print "$message\n"; + + $fh->print("$message\n"); + $fh->flush(); +} + +sub check_cfg { + my ($cfg_fn, $outfile) = @_; + + my $raw = PVE::Tools::file_get_contents($cfg_fn); + + open(my $LOG, '>', "$outfile"); + select($LOG); + $| = 1; + + print "--- Log ---\n"; + my $cfg = PVE::HA::Rules->parse_config($cfg_fn, $raw); + PVE::HA::Rules->set_rule_defaults($_) for values %{ $cfg->{ids} }; + my $messages = PVE::HA::Rules->canonicalize($cfg); + print $_ for @$messages; + print "--- Config ---\n"; + { + local $Data::Dumper::Sortkeys = 1; + print Dumper($cfg); + } + + select(STDOUT); +} + +sub run_test { + my ($cfg_fn) = @_; + + print "* check: $cfg_fn\n"; + + my $outfile = "$cfg_fn.output"; + my $expect = "$cfg_fn.expect"; + + eval { check_cfg($cfg_fn, $outfile); }; + if (my $err = $@) { + die "Test '$cfg_fn' failed:\n$err\n"; + } + + return if $opt_nodiff; + + my $res; + + if (-f $expect) { + my $cmd = ['diff', '-u', $expect, $outfile]; + $res = system(@$cmd); + die "test '$cfg_fn' failed\n" if $res != 0; + } else { + $res = system('cp', $outfile, $expect); + die "test '$cfg_fn' failed\n" if $res != 0; + } + + print "* end rules test: $cfg_fn (success)\n\n"; +} + +# exec tests + +if (my $testcfg = shift) { + run_test($testcfg); +} else { + for my $cfg () { + run_test($cfg); + } +} -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel