Add test cases to verify that the rule checkers correctly identify and remove ill-defined location and colocation rules from the rules:
- Set defaults when reading location and colocation rules - Dropping location rules, which specify the same service multiple times - Dropping colocation rules, which state that two or more services are to be kept together and separate at the same time - Dropping colocation rules, which cannot be fullfilled because of the constraints of the location rules of their services - Dropping colocation rules, which specify less than two services Signed-off-by: Daniel Kral <d.k...@proxmox.com> --- changes since v1: - dropped connected positive colocation rules check - rename illdefined-colocations to ineffective-colocation-rules - rename inner-inconsistent-colocations to inconsistent-colocation-rules - introduced rule set tests for default values - introduced rule set tests for duplicate service reference in location rules - introduced rule set tests for multi-priority location with colocation rules .gitignore | 1 + src/test/Makefile | 4 +- .../defaults-for-colocation-rules.cfg | 10 ++ .../defaults-for-colocation-rules.cfg.expect | 29 ++++ .../defaults-for-location-rules.cfg | 16 +++ .../defaults-for-location-rules.cfg.expect | 49 +++++++ .../duplicate-service-in-location-rules.cfg | 31 +++++ ...icate-service-in-location-rules.cfg.expect | 66 +++++++++ .../inconsistent-colocation-rules.cfg | 11 ++ .../inconsistent-colocation-rules.cfg.expect | 11 ++ ...inconsistent-location-colocation-rules.cfg | 54 ++++++++ ...stent-location-colocation-rules.cfg.expect | 130 ++++++++++++++++++ .../ineffective-colocation-rules.cfg | 7 + .../ineffective-colocation-rules.cfg.expect | 9 ++ ...ulti-priority-location-with-colocation.cfg | 19 +++ ...iority-location-with-colocation.cfg.expect | 47 +++++++ src/test/test_rules_config.pl | 102 ++++++++++++++ 17 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 src/test/rules_cfgs/defaults-for-colocation-rules.cfg create mode 100644 src/test/rules_cfgs/defaults-for-colocation-rules.cfg.expect create mode 100644 src/test/rules_cfgs/defaults-for-location-rules.cfg create mode 100644 src/test/rules_cfgs/defaults-for-location-rules.cfg.expect create mode 100644 src/test/rules_cfgs/duplicate-service-in-location-rules.cfg create mode 100644 src/test/rules_cfgs/duplicate-service-in-location-rules.cfg.expect create mode 100644 src/test/rules_cfgs/inconsistent-colocation-rules.cfg create mode 100644 src/test/rules_cfgs/inconsistent-colocation-rules.cfg.expect create mode 100644 src/test/rules_cfgs/inconsistent-location-colocation-rules.cfg create mode 100644 src/test/rules_cfgs/inconsistent-location-colocation-rules.cfg.expect create mode 100644 src/test/rules_cfgs/ineffective-colocation-rules.cfg create mode 100644 src/test/rules_cfgs/ineffective-colocation-rules.cfg.expect create mode 100644 src/test/rules_cfgs/multi-priority-location-with-colocation.cfg create mode 100644 src/test/rules_cfgs/multi-priority-location-with-colocation.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-colocation-rules.cfg b/src/test/rules_cfgs/defaults-for-colocation-rules.cfg new file mode 100644 index 0000000..8e68030 --- /dev/null +++ b/src/test/rules_cfgs/defaults-for-colocation-rules.cfg @@ -0,0 +1,10 @@ +# Case 1: Colocation rules are enabled by default, so set it so if it isn't yet. +colocation: colocation-defaults + services vm:101,vm:102 + affinity separate + +# Case 2: Colocation rule is disabled, it shouldn't be enabled afterwards. +colocation: colocation-disabled + services vm:201,vm:202 + affinity separate + state disabled diff --git a/src/test/rules_cfgs/defaults-for-colocation-rules.cfg.expect b/src/test/rules_cfgs/defaults-for-colocation-rules.cfg.expect new file mode 100644 index 0000000..faafec8 --- /dev/null +++ b/src/test/rules_cfgs/defaults-for-colocation-rules.cfg.expect @@ -0,0 +1,29 @@ +--- Log --- +--- Config --- +$VAR1 = { + 'digest' => '692081df1aaf03092f67cd415f5c66222b1d55e2', + 'ids' => { + 'colocation-defaults' => { + 'affinity' => 'separate', + 'services' => { + 'vm:101' => 1, + 'vm:102' => 1 + }, + 'state' => 'enabled', + 'type' => 'colocation' + }, + 'colocation-disabled' => { + 'affinity' => 'separate', + 'services' => { + 'vm:201' => 1, + 'vm:202' => 1 + }, + 'state' => 'disabled', + 'type' => 'colocation' + } + }, + 'order' => { + 'colocation-defaults' => 1, + 'colocation-disabled' => 2 + } + }; diff --git a/src/test/rules_cfgs/defaults-for-location-rules.cfg b/src/test/rules_cfgs/defaults-for-location-rules.cfg new file mode 100644 index 0000000..728558d --- /dev/null +++ b/src/test/rules_cfgs/defaults-for-location-rules.cfg @@ -0,0 +1,16 @@ +# Case 1: Location rules are enabled and loose by default, so set it so if it isn't yet. +location: location-defaults + services vm:101 + nodes node1 + +# Case 2: Location rule is disabled, it shouldn't be enabled afterwards. +location: location-disabled + services vm:102 + nodes node2 + state disabled + +# Case 3: Location rule is set to strict, so it shouldn't be loose afterwards. +location: location-strict + services vm:103 + nodes node3 + strict 1 diff --git a/src/test/rules_cfgs/defaults-for-location-rules.cfg.expect b/src/test/rules_cfgs/defaults-for-location-rules.cfg.expect new file mode 100644 index 0000000..d534deb --- /dev/null +++ b/src/test/rules_cfgs/defaults-for-location-rules.cfg.expect @@ -0,0 +1,49 @@ +--- Log --- +--- Config --- +$VAR1 = { + 'digest' => '27c1704d1a5497b314f8f5717b633184c1a1aacf', + 'ids' => { + 'location-defaults' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:101' => 1 + }, + 'state' => 'enabled', + 'type' => 'location' + }, + 'location-disabled' => { + 'nodes' => { + 'node2' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:102' => 1 + }, + 'state' => 'disabled', + 'type' => 'location' + }, + 'location-strict' => { + 'nodes' => { + 'node3' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:103' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + } + }, + 'order' => { + 'location-defaults' => 1, + 'location-disabled' => 2, + 'location-strict' => 3 + } + }; diff --git a/src/test/rules_cfgs/duplicate-service-in-location-rules.cfg b/src/test/rules_cfgs/duplicate-service-in-location-rules.cfg new file mode 100644 index 0000000..7409bd7 --- /dev/null +++ b/src/test/rules_cfgs/duplicate-service-in-location-rules.cfg @@ -0,0 +1,31 @@ +# Case 1: Do not remove two location rules, which do not share services. +location: no-same-service1 + services vm:101,vm:102,vm:103 + nodes node1,node2:2 + strict 0 + +location: no-same-service2 + services vm:104,vm:105 + nodes node1,node2:2 + strict 0 + +location: no-same-service3 + services vm:106 + nodes node1,node2:2 + strict 1 + +# Case 2: Remove location rules, which share the same service between them. +location: same-service1 + services vm:201 + nodes node1,node2:2 + strict 0 + +location: same-service2 + services vm:201,vm:202 + nodes node3 + strict 1 + +location: same-service3 + services vm:201,vm:203,vm:204 + nodes node1:2,node3:3 + strict 0 diff --git a/src/test/rules_cfgs/duplicate-service-in-location-rules.cfg.expect b/src/test/rules_cfgs/duplicate-service-in-location-rules.cfg.expect new file mode 100644 index 0000000..39b95bd --- /dev/null +++ b/src/test/rules_cfgs/duplicate-service-in-location-rules.cfg.expect @@ -0,0 +1,66 @@ +--- Log --- +Drop rule 'same-service1', because service 'vm:201' is already used in another location rule. +Drop rule 'same-service2', because service 'vm:201' is already used in another location rule. +Drop rule 'same-service3', because service 'vm:201' is already used in another location rule. +--- Config --- +$VAR1 = { + 'digest' => '07ee7a87159672339144fb9d1021b54905e09632', + 'ids' => { + 'no-same-service1' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + }, + 'node2' => { + 'priority' => 2 + } + }, + 'services' => { + 'vm:101' => 1, + 'vm:102' => 1, + 'vm:103' => 1 + }, + 'state' => 'enabled', + 'strict' => 0, + 'type' => 'location' + }, + 'no-same-service2' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + }, + 'node2' => { + 'priority' => 2 + } + }, + 'services' => { + 'vm:104' => 1, + 'vm:105' => 1 + }, + 'state' => 'enabled', + 'strict' => 0, + 'type' => 'location' + }, + 'no-same-service3' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + }, + 'node2' => { + 'priority' => 2 + } + }, + 'services' => { + 'vm:106' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + } + }, + 'order' => { + 'no-same-service1' => 1, + 'no-same-service2' => 2, + 'no-same-service3' => 3 + } + }; diff --git a/src/test/rules_cfgs/inconsistent-colocation-rules.cfg b/src/test/rules_cfgs/inconsistent-colocation-rules.cfg new file mode 100644 index 0000000..3199bfb --- /dev/null +++ b/src/test/rules_cfgs/inconsistent-colocation-rules.cfg @@ -0,0 +1,11 @@ +colocation: keep-apart1 + services vm:102,vm:103 + affinity separate + +colocation: keep-apart2 + services vm:102,vm:104,vm:106 + affinity separate + +colocation: stick-together1 + services vm:101,vm:102,vm:103,vm:104,vm:106 + affinity together diff --git a/src/test/rules_cfgs/inconsistent-colocation-rules.cfg.expect b/src/test/rules_cfgs/inconsistent-colocation-rules.cfg.expect new file mode 100644 index 0000000..b1989a8 --- /dev/null +++ b/src/test/rules_cfgs/inconsistent-colocation-rules.cfg.expect @@ -0,0 +1,11 @@ +--- Log --- +Drop rule 'keep-apart1', because rule shares two or more services with 'stick-together1'. +Drop rule 'keep-apart2', because rule shares two or more services with 'stick-together1'. +Drop rule 'stick-together1', because rule shares two or more services with 'keep-apart1'. +Drop rule 'stick-together1', because rule shares two or more services with 'keep-apart2'. +--- Config --- +$VAR1 = { + 'digest' => '469bc45c05ffbb123a277fc0fda48e0132fc9046', + 'ids' => {}, + 'order' => {} + }; diff --git a/src/test/rules_cfgs/inconsistent-location-colocation-rules.cfg b/src/test/rules_cfgs/inconsistent-location-colocation-rules.cfg new file mode 100644 index 0000000..ed6b82d --- /dev/null +++ b/src/test/rules_cfgs/inconsistent-location-colocation-rules.cfg @@ -0,0 +1,54 @@ +# Case 1: Remove no positive colocation rule, where there is exactly one node to keep them together. +location: vm101-vm102-must-be-on-node1 + services vm:101,vm:102 + nodes node1 + strict 1 + +colocation: vm101-vm102-must-be-kept-together + services vm:101,vm:102 + affinity together + +# Case 2: Remove no negative colocation rule, where there are exactly enough nodes available to keep them apart. +location: vm201-must-be-on-node1 + services vm:201 + nodes node1 + strict 1 + +location: vm202-must-be-on-node2 + services vm:202 + nodes node2 + strict 1 + +colocation: vm201-vm202-must-be-kept-separate + services vm:201,vm:202 + affinity separate + +# Case 1: Remove the positive colocation rules, where two services are restricted to a different node. +location: vm301-must-be-on-node1 + services vm:301 + nodes node1 + strict 1 + +location: vm301-must-be-on-node2 + services vm:302 + nodes node2 + strict 1 + +colocation: vm301-vm302-must-be-kept-together + services vm:301,vm:302 + affinity together + +# Case 2: Remove the negative colocation rule, where two services are restricted to less nodes than needed to keep them apart. +location: vm401-must-be-on-node1 + services vm:401 + nodes node1 + strict 1 + +location: vm402-must-be-on-node1 + services vm:402 + nodes node1 + strict 1 + +colocation: vm401-vm402-must-be-kept-separate + services vm:401,vm:402 + affinity separate diff --git a/src/test/rules_cfgs/inconsistent-location-colocation-rules.cfg.expect b/src/test/rules_cfgs/inconsistent-location-colocation-rules.cfg.expect new file mode 100644 index 0000000..bed4668 --- /dev/null +++ b/src/test/rules_cfgs/inconsistent-location-colocation-rules.cfg.expect @@ -0,0 +1,130 @@ +--- Log --- +Drop rule 'vm301-vm302-must-be-kept-together', because two or more services are restricted to different nodes. +Drop rule 'vm401-vm402-must-be-kept-separate', because two or more services are restricted to less nodes than available to the services. +--- Config --- +$VAR1 = { + 'digest' => '27e76e13c20a1d11c5cbcf14434bcd54655fdd40', + 'ids' => { + 'vm101-vm102-must-be-kept-together' => { + 'affinity' => 'together', + 'services' => { + 'vm:101' => 1, + 'vm:102' => 1 + }, + 'state' => 'enabled', + 'type' => 'colocation' + }, + 'vm101-vm102-must-be-on-node1' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:101' => 1, + 'vm:102' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + }, + 'vm201-must-be-on-node1' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:201' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + }, + 'vm201-vm202-must-be-kept-separate' => { + 'affinity' => 'separate', + 'services' => { + 'vm:201' => 1, + 'vm:202' => 1 + }, + 'state' => 'enabled', + 'type' => 'colocation' + }, + 'vm202-must-be-on-node2' => { + 'nodes' => { + 'node2' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:202' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + }, + 'vm301-must-be-on-node1' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:301' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + }, + 'vm301-must-be-on-node2' => { + 'nodes' => { + 'node2' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:302' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + }, + 'vm401-must-be-on-node1' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:401' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + }, + 'vm402-must-be-on-node1' => { + 'nodes' => { + 'node1' => { + 'priority' => 0 + } + }, + 'services' => { + 'vm:402' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + } + }, + '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/ineffective-colocation-rules.cfg b/src/test/rules_cfgs/ineffective-colocation-rules.cfg new file mode 100644 index 0000000..4f2338e --- /dev/null +++ b/src/test/rules_cfgs/ineffective-colocation-rules.cfg @@ -0,0 +1,7 @@ +colocation: lonely-service1 + services vm:101 + affinity together + +colocation: lonely-service2 + services vm:101 + affinity separate diff --git a/src/test/rules_cfgs/ineffective-colocation-rules.cfg.expect b/src/test/rules_cfgs/ineffective-colocation-rules.cfg.expect new file mode 100644 index 0000000..3741ba7 --- /dev/null +++ b/src/test/rules_cfgs/ineffective-colocation-rules.cfg.expect @@ -0,0 +1,9 @@ +--- Log --- +Drop rule 'lonely-service1', because rule is ineffective as there are less than two services. +Drop rule 'lonely-service2', because rule is ineffective as there are less than two services. +--- Config --- +$VAR1 = { + 'digest' => '47bdd78898e4193aa113ab05b0fd7aaaeb08109d', + 'ids' => {}, + 'order' => {} + }; diff --git a/src/test/rules_cfgs/multi-priority-location-with-colocation.cfg b/src/test/rules_cfgs/multi-priority-location-with-colocation.cfg new file mode 100644 index 0000000..889fe47 --- /dev/null +++ b/src/test/rules_cfgs/multi-priority-location-with-colocation.cfg @@ -0,0 +1,19 @@ +# Case 1: Remove colocation rules, where there is a loose location rule with multiple priority groups set for the nodes. +location: vm101-vm102-should-be-on-node1-or-node2 + services vm:101,vm:102 + nodes node1:1,node2:2 + strict 0 + +colocation: vm101-vm102-must-be-kept-separate + services vm:101,vm:102 + affinity separate + +# Case 2: Remove colocation rules, where there is a strict location rule with multiple priority groups set for the nodes. +location: vm201-vm202-must-be-on-node1-or-node2 + services vm:201,vm:202 + nodes node1:1,node2:2 + strict 1 + +colocation: vm201-vm202-must-be-kept-together + services vm:201,vm:202 + affinity together diff --git a/src/test/rules_cfgs/multi-priority-location-with-colocation.cfg.expect b/src/test/rules_cfgs/multi-priority-location-with-colocation.cfg.expect new file mode 100644 index 0000000..47c7af5 --- /dev/null +++ b/src/test/rules_cfgs/multi-priority-location-with-colocation.cfg.expect @@ -0,0 +1,47 @@ +--- Log --- +Drop rule 'vm101-vm102-must-be-kept-separate', because services are in location rules with multiple priorities. +Drop rule 'vm201-vm202-must-be-kept-together', because services are in location rules with multiple priorities. +--- Config --- +$VAR1 = { + 'digest' => '30292457018bf1ae4fcf9bea92199233c877bf28', + 'ids' => { + 'vm101-vm102-should-be-on-node1-or-node2' => { + 'nodes' => { + 'node1' => { + 'priority' => 1 + }, + 'node2' => { + 'priority' => 2 + } + }, + 'services' => { + 'vm:101' => 1, + 'vm:102' => 1 + }, + 'state' => 'enabled', + 'strict' => 0, + 'type' => 'location' + }, + 'vm201-vm202-must-be-on-node1-or-node2' => { + 'nodes' => { + 'node1' => { + 'priority' => 1 + }, + 'node2' => { + 'priority' => 2 + } + }, + 'services' => { + 'vm:201' => 1, + 'vm:202' => 1 + }, + 'state' => 'enabled', + 'strict' => 1, + 'type' => 'location' + } + }, + '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 new file mode 100755 index 0000000..6e6b7de --- /dev/null +++ b/src/test/test_rules_config.pl @@ -0,0 +1,102 @@ +#!/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::Location; +use PVE::HA::Rules::Colocation; + +PVE::HA::Rules::Location->register(); +PVE::HA::Rules::Colocation->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.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel