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 <d.k...@proxmox.com> --- .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 c35280ee..35de63f6 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 e54959fb..6da9e100 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 00000000..c8b2f2dd --- /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 00000000..59a2c364 --- /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 00000000..1e279e73 --- /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 00000000..3fd0c9ca --- /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 00000000..824afed1 --- /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 (<rules_cfgs/*cfg>) { + run_test($cfg); + } +} -- 2.47.2 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel