From 270d643d1155afd83a5c699c2e6721a4dea2c5ae Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Wed, 12 Mar 2025 22:16:57 +0100 Subject: Adapt tests --- plugins/t/check_users.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_users.t b/plugins/t/check_users.t index 21c3e53d..446e0476 100644 --- a/plugins/t/check_users.t +++ b/plugins/t/check_users.t @@ -15,8 +15,8 @@ use NPTest; use vars qw($tests); BEGIN {$tests = 12; plan tests => $tests} -my $successOutput = '/^USERS OK - [0-9]+ users currently logged in/'; -my $failureOutput = '/^USERS CRITICAL - [0-9]+ users currently logged in/'; +my $successOutput = '/[0-9]+ users currently logged in/'; +my $failureOutput = '/[0-9]+ users currently logged in/'; my $wrongOptionOutput = '/Usage:/'; my $t; -- cgit v1.2.3-74-g34f1 From 205b97b3e2133b14fbaab98f81b5f5991cfca1e9 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Thu, 13 Mar 2025 23:48:33 +0100 Subject: check_load: Remove output formatting test and adapt others --- plugins/t/check_load.t | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_load.t b/plugins/t/check_load.t index bba8947c..3e453703 100644 --- a/plugins/t/check_load.t +++ b/plugins/t/check_load.t @@ -16,28 +16,28 @@ my $successScaledOutput = "/^LOAD OK - scaled load average: $loadValue, $loadVal my $failureOutput = "/^LOAD CRITICAL - total load average: $loadValue, $loadValue, $loadValue/"; my $failurScaledOutput = "/^LOAD CRITICAL - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/"; -plan tests => 13; +plan tests => 8; $res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100" ); cmp_ok( $res->return_code, 'eq', 0, "load not over 100"); -like( $res->output, $successOutput, "Output OK"); +# like( $res->output, $successOutput, "Output OK"); $res = NPTest->testCmd( "./check_load -w 0,0,0 -c 0,0,0" ); cmp_ok( $res->return_code, 'eq', 2, "Load over 0"); -like( $res->output, $failureOutput, "Output OK"); +# like( $res->output, $failureOutput, "Output OK"); $res = NPTest->testCmd( "./check_load -r -w 0,0,0 -c 0,0,0" ); cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division"); -like( $res->output, $failurScaledOutput, "Output OK"); +# like( $res->output, $failurScaledOutput, "Output OK"); $res = NPTest->testCmd( "./check_load -w 100 -c 100,110" ); cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments"); -like( $res->output, $successOutput, "Output OK"); -like( $res->perf_output, "/load1=$loadValue;100.000;100.000/", "Test handling of non triplet thresholds (load1)"); -like( $res->perf_output, "/load5=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load5)"); -like( $res->perf_output, "/load15=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load15)"); +# like( $res->output, $successOutput, "Output OK"); +like( $res->perf_output, "/load1=$loadValue;~:100.0+;~:100.0+/", "Test handling of non triplet thresholds (load1)"); +like( $res->perf_output, "/load5=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load5)"); +like( $res->perf_output, "/load15=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load15)"); $res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100 -r" ); cmp_ok( $res->return_code, 'eq', 0, "load not over 100"); -like( $res->output, $successScaledOutput, "Output OK"); +# like( $res->output, $successScaledOutput, "Output OK"); -- cgit v1.2.3-74-g34f1 From 76971dea753d52d3e177aa84605d9b239a3a793e Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 30 Mar 2025 22:38:12 +0200 Subject: Address check_disk changes in tests --- plugins/t/check_disk.t | 205 +++++++++++++++++++++++----------------- plugins/tests/test_check_disk.c | 67 ++++++------- 2 files changed, 154 insertions(+), 118 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t index 9eb77ce4..16daee9a 100644 --- a/plugins/t/check_disk.t +++ b/plugins/t/check_disk.t @@ -10,6 +10,7 @@ use strict; use Test::More; use NPTest; use POSIX qw(ceil floor); +use Data::Dumper; my $successOutput = '/^DISK OK/'; my $failureOutput = '/^DISK CRITICAL/'; @@ -20,117 +21,148 @@ my $result; my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/"); my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var"); +my $output_format = "--output-format mp-test-json"; + if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") { plan skip_all => "Need 2 mountpoints to test"; } else { - plan tests => 94; + plan tests => 96; } $result = NPTest->testCmd( - "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -p $mountpoint2_valid" + "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -P -p $mountpoint2_valid $output_format" ); cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)"); -my $c = 0; -$_ = $result->output; -$c++ while /\(/g; # counts number of "(" - should be two -cmp_ok( $c, '==', 2, "Got two mountpoints in output"); +like($result->{'mp_test_result'}->{'state'}, "/OK/", "Main result is OK"); +like($result->{'mp_test_result'}->{'checks'}->[0]->{'state'}, "/OK/", "First sub result is OK"); +like($result->{'mp_test_result'}->{'checks'}->[1]->{'state'}, "/OK/", "Second sub result is OK"); + +my $absolut_space_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'}; +# print("absolut space on mp1: ". $absolut_space_mp1 . "\n"); + +my $free_percent_on_mp1 = ($result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / ($absolut_space_mp1/100)); +print("free percent on mp1: ". $free_percent_on_mp1 . "\n"); + +my $absolut_space_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'}; +# print("absolut space on mp2: ". $absolut_space_mp2 . "\n"); -# Get perf data -# Should use Monitoring::Plugin -my @perf_data = sort(split(/ /, $result->perf_output)); +my $free_percent_on_mp2 = ($result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ ($absolut_space_mp2/100)); +print("free percent on mp2: ". $free_percent_on_mp2 . "\n"); +my @perfdata; +@perfdata[0] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]; +@perfdata[1] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]; # Calculate avg_free free on mountpoint1 and mountpoint2 # because if you check in the middle, you should get different errors -$_ = $result->output; -my ($free_on_mp1, $free_on_mp2) = (m/\((\d+\.\d+)%.*\((\d+\.\d+)%/); -die "Cannot parse output: $_" unless ($free_on_mp1 && $free_on_mp2); -my $avg_free = ceil(($free_on_mp1+$free_on_mp2)/2); +my $avg_free_percent = ceil(($free_percent_on_mp1+$free_percent_on_mp2)/2); +# print("avg_free: " . $avg_free_percent . "\n"); my ($more_free, $less_free); -if ($free_on_mp1 > $free_on_mp2) { +if ($free_percent_on_mp1 > $free_percent_on_mp2) { $more_free = $mountpoint_valid; $less_free = $mountpoint2_valid; -} elsif ($free_on_mp1 < $free_on_mp2) { +} elsif ($free_percent_on_mp1 < $free_percent_on_mp2) { $more_free = $mountpoint2_valid; $less_free = $mountpoint_valid; } else { die "Two mountpoints are the same - cannot do rest of test"; } -if($free_on_mp1 == $avg_free || $free_on_mp2 == $avg_free) { + +print("less free: " . $less_free . "\n"); +print("more free: " . $more_free . "\n"); + +if($free_percent_on_mp1 == $avg_free_percent || $free_percent_on_mp2 == $avg_free_percent) { die "One mountpoints has average space free - cannot do rest of test"; } +my $free_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'}; +my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'}; +my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100); -# Do same for inodes -$_ = $result->output; -my ($free_inode_on_mp1, $free_inode_on_mp2) = (m/inode=(\d+)%.*inode=(\d+)%/); -die "Cannot parse free inodes: $_" unless ($free_inode_on_mp1 && $free_inode_on_mp2); -my $avg_inode_free = ceil(($free_inode_on_mp1 + $free_inode_on_mp2)/2); +my $free_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'}; +my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'}; +my $free_inode_percentage_on_mp2 = $free_inodes_on_mp2 / ($total_inodes_on_mp2 / 100); + +my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2); my ($more_inode_free, $less_inode_free); -if ($free_inode_on_mp1 > $free_inode_on_mp2) { +if ($free_inode_percentage_on_mp1 > $free_inode_percentage_on_mp2) { $more_inode_free = $mountpoint_valid; $less_inode_free = $mountpoint2_valid; -} elsif ($free_inode_on_mp1 < $free_inode_on_mp2) { +} elsif ($free_inode_percentage_on_mp1 < $free_inode_percentage_on_mp2) { $more_inode_free = $mountpoint2_valid; $less_inode_free = $mountpoint_valid; } else { die "Two mountpoints with same inodes free - cannot do rest of test"; } -if($free_inode_on_mp1 == $avg_inode_free || $free_inode_on_mp2 == $avg_inode_free) { +if($free_inode_percentage_on_mp1 == $avg_inode_free_percentage || $free_inode_percentage_on_mp2 == $avg_inode_free_percentage) { die "One mountpoints has average inodes free - cannot do rest of test"; } # Verify performance data # First check absolute thresholds... $result = NPTest->testCmd( - "./check_disk -w 20 -c 10 -p $mountpoint_valid" + "./check_disk -w 20 -c 10 -p $mountpoint_valid $output_format" ); -$_ = $result->perf_output; -my ($warn_absth_data, $crit_absth_data, $total_absth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/); -# default unit is MiB, but perfdata is always bytes -is ($warn_absth_data, $total_absth_data - (20 * (2 ** 20)), "Wrong warning in perf data using absolute thresholds"); -is ($crit_absth_data, $total_absth_data - (10 * (2 ** 20)), "Wrong critical in perf data using absolute thresholds"); + +cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); + +my $warn_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'}; +my $crit_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'}; +my $total_absth_data= $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'}; + +# print("warn: " .$warn_absth_data . "\n"); +# print("crit: " .$crit_absth_data . "\n"); +# print("total: " .$total_absth_data . "\n"); + +is ($warn_absth_data <=> (20 * (2 ** 20)), 0, "Wrong warning in perf data using absolute thresholds"); +is ($crit_absth_data <=> (10 * (2 ** 20)), 0, "Wrong critical in perf data using absolute thresholds"); # Then check percent thresholds. $result = NPTest->testCmd( - "./check_disk -w 20% -c 10% -p $mountpoint_valid" + "./check_disk -w 20% -c 10% -p $mountpoint_valid $output_format" ); -$_ = $result->perf_output; -my ($warn_percth_data, $crit_percth_data, $total_percth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/); -is ($warn_percth_data, int((1-20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds"); -is ($crit_percth_data, int((1-10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds"); + +cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); + +my $warn_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'}; +my $crit_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'}; +my $total_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'}; + +is ($warn_percth_data <=> int((20/100)*$total_percth_data), 0, "Wrong warning in perf data using percent thresholds"); +is ($crit_percth_data <=> int((10/100)*$total_percth_data), 0, "Wrong critical in perf data using percent thresholds"); # Check when order of mount points are reversed, that perf data remains same $result = NPTest->testCmd( - "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid" + "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid $output_format" ); -@_ = sort(split(/ /, $result->perf_output)); -is_deeply( \@perf_data, \@_, "perf data for both filesystems same when reversed"); +cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); +# write comparison set for perfdata here, but in reversed order, maybe there is a smarter way +my @perfdata2; +@perfdata2[1] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]; +@perfdata2[0] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]; +is_deeply(\@perfdata, \@perfdata2, "perf data for both filesystems same when reversed"); # Basic filesystem checks for sizes -$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free" ); -cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free"); -like ( $result->output, $successOutput, "OK output" ); -like ( $result->only_output, qr/free space/, "Have free space text"); -like ( $result->only_output, qr/$more_free/, "Have disk name in text"); +$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free $output_format"); +cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); +like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free"); -$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free" ); -cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free and $less_free"); +$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free $output_format" ); +cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); +like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free and $less_free"); -$_ = $result->output; - -my ($free_mb_on_mp1, $free_mb_on_mp2) = (m/(\d+)MiB .* (\d+)MiB /g); +my $free_mb_on_mp1 =$result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / (1024 * 1024); +my $free_mb_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ (1024 * 1024); die "Cannot parse output: $_" unless ($free_mb_on_mp1 && $free_mb_on_mp2); my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2; - -$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free" ); -is( $result->only_output, "DISK OK", "No print out of disks with -e for OKs"); +$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free $output_format" ); +cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); $result = NPTest->testCmd( "./check_disk 100 100 $more_free" ); cmp_ok( $result->return_code, '==', 0, "Old syntax okay" ); @@ -139,54 +171,55 @@ $result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" ); cmp_ok( $result->return_code, "==", 0, "At least 1% free" ); $result = NPTest->testCmd( - "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free" + "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free $output_format" ); -cmp_ok( $result->return_code, "==", 2, "Get critical on less_free mountpoint $less_free" ); -like( $result->output, $failureOutput, "Right output" ); +cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); +like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Get critical on less_free mountpoint $less_free"); $result = NPTest->testCmd( - "./check_disk -w $avg_free% -c 0% -p $less_free" + "./check_disk -w $avg_free_percent% -c 0% -p $less_free $output_format" ); -cmp_ok( $result->return_code, '==', 1, "Get warning on less_free mountpoint, when checking avg_free"); +cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); +like($result->{'mp_test_result'}->{'state'}, "/WARNING/", "Get warning on less_free mountpoint, when checking avg_free"); $result = NPTest->testCmd( - "./check_disk -w $avg_free% -c $avg_free% -p $more_free" + "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $more_free" ); cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free"); $result = NPTest->testCmd( - "./check_disk -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free" + "./check_disk -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free" ); cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning"); my $all_disks = $result->output; $result = NPTest->testCmd( - "./check_disk -e -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free" + "./check_disk -e -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free" ); isnt( $result->output, $all_disks, "-e gives different output"); # Need spaces around filesystem name in case less_free and more_free are nested like( $result->output, qr/ $less_free /, "Found problem $less_free"); unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem"); -like( $result->perf_output, qr/ $more_free=/, "But $more_free is still in perf data"); +like( $result->perf_output, qr/'$more_free'=/, "But $more_free is still in perf data"); $result = NPTest->testCmd( - "./check_disk -w $avg_free% -c 0% -p $more_free" + "./check_disk -w $avg_free_percent% -c 0% -p $more_free" ); cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free"); $result = NPTest->testCmd( - "./check_disk -w $avg_free% -c $avg_free% -p $less_free" + "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free" ); cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free"); $result = NPTest->testCmd( - "./check_disk -w $avg_free% -c 0% -p $more_free -w $avg_free% -c $avg_free% -p $less_free" + "./check_disk -w $avg_free_percent% -c 0% -p $more_free -w $avg_free_percent% -c $avg_free_percent% -p $less_free" ); cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical"); $result = NPTest->testCmd( - "./check_disk -w $avg_free% -c $avg_free% -p $less_free -w $avg_free% -c 0% -p $more_free" + "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free -w $avg_free_percent% -c 0% -p $more_free" ); cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference"); @@ -203,32 +236,32 @@ is( $result->return_code, 2, "Critical requesting 100% free inodes for both moun $result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" ); is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free"); -$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free" ); +$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free" ); is( $result->return_code, 1, "Get warning on less_inode_free, when checking average"); -$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free "); +$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free "); is( $result->return_code, 0, "Get ok on more_inode_free when checking average"); -$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" ); +$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" ); is ($result->return_code, 1, "Combine above two tests, get warning"); $all_disks = $result->output; -$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" ); +$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" ); isnt( $result->output, $all_disks, "-e gives different output"); like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free"); unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem"); like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data"); -$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free" ); +$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" ); is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average"); -$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" ); +$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" ); is( $result->return_code, 2, "Get critical on less_inode_free, checking average"); -$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" ); +$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" ); is( $result->return_code, 2, "Combining above two tests, get critical"); -$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free -W $avg_inode_free% -K 0% -p $more_inode_free" ); +$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" ); cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference"); @@ -249,9 +282,9 @@ $result = NPTest->testCmd( ); cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" ); -$result = NPTest->testCmd( "./check_disk -w 100% -c 100% ".${mountpoint_valid} ); # 100% empty -cmp_ok( $result->return_code, "==", 2, "100% empty" ); -like( $result->output, $failureOutput, "Right output" ); +$result = NPTest->testCmd( "./check_disk -w 100% -c 100% $output_format ".${mountpoint_valid} ); # 100% empty +cmp_ok( $result->return_code, "==", 0, "100% empty" ); +like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "100% empty"); $result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" ); cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" ); @@ -263,7 +296,8 @@ cmp_ok( $result->return_code, "==", 2, "100 TB empty" ); # Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds $result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} ); cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used"); -like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments"); +# like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments"); +# TODO not sure what the above should test, taking it out $result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" ); cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" ); @@ -311,8 +345,9 @@ $result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p / -p /" ); unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice"); # are partitions added if -C is given without path selection -p ? -$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid" ); -like( $result->output, '/;.*;\|/', "-C selects partitions if -p is not given"); +$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid $output_format" ); +cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); +cmp_ok(scalar $result->{'mp_test_result'}->{'checks'}, '>', 1, "-C invokes matchall logic again"); # grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit $result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" ); @@ -359,39 +394,37 @@ like( $result->output, qr/$mountpoint2_valid/,"ignore: output data does have $mo # ignore-missing: exit okay, when fs is not accessible $result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob"); cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob"); -like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /bob;.*$/', 'Output OK'); +like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK'); # ignore-missing: exit okay, when regex does not match $result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob"); cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); -like( $result->output, '/^DISK OK - No disks were found for provided parameters.*$/', 'Output OK'); +like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK'); # ignore-missing: exit okay, when fs with exact match (-E) is not found $result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc"); cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs"); -like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /etc;.*$/', 'Output OK'); +like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK'); # ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex) $result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'"); cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); -like( $result->output, '/^DISK OK - free space: \/ .*$/', 'Output OK'); # ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path) $result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'"); cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); -like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK'); +# like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK'); # ignore-missing: exit okay, when checking one non-existing fs (path) and one ignored $result = NPTest->testCmd( "./check_disk -n -w 0% -c 0% -r /dummy -i /dummy2"); cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); -like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK'); +like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK'); # ignore-missing: exit okay, when regex match does not find anything $result = NPTest->testCmd( "./check_disk -n -e -l -w 10% -c 5% -W 10% -K 5% -r /dummy"); cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); -like( $result->output, '/^DISK OK\|$/', 'Output OK'); # ignore-missing: exit okay, when regex match does not find anything $result = NPTest->testCmd( "./check_disk -n -l -w 10% -c 5% -W 10% -K 5% -r /dummy"); cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); -like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK'); +like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK'); diff --git a/plugins/tests/test_check_disk.c b/plugins/tests/test_check_disk.c index 963a9413..35c57bce 100644 --- a/plugins/tests/test_check_disk.c +++ b/plugins/tests/test_check_disk.c @@ -24,7 +24,7 @@ void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc); int main(int argc, char **argv) { - plan_tests(33); + plan_tests(35); struct name_list *exclude_filesystem = NULL; ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list"); @@ -81,15 +81,16 @@ int main(int argc, char **argv) { np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2, strdup("grouped regex pathname match:")); np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2, strdup("grouped regi pathname match:")); - struct parameter_list *paths = NULL; - np_add_parameter(&paths, "/home/groups"); - np_add_parameter(&paths, "/var"); - np_add_parameter(&paths, "/tmp"); - np_add_parameter(&paths, "/home/tonvoon"); - np_add_parameter(&paths, "/dev/c2t0d0s0"); + filesystem_list test_paths = filesystem_list_init(); + mp_int_fs_list_append(&test_paths, "/home/groups"); + mp_int_fs_list_append(&test_paths, "/var"); + mp_int_fs_list_append(&test_paths, "/tmp"); + mp_int_fs_list_append(&test_paths, "/home/tonvoon"); + mp_int_fs_list_append(&test_paths, "/dev/c2t0d0s0"); + ok(test_paths.length == 5, "List counter works correctly with appends"); - np_set_best_match(paths, dummy_mount_list, false); - for (struct parameter_list *p = paths; p; p = p->name_next) { + mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, false); + for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) { struct mount_entry *temp_me; temp_me = p->best_match; if (!strcmp(p->name, "/home/groups")) { @@ -105,15 +106,19 @@ int main(int argc, char **argv) { } } - paths = NULL; /* Bad boy - should free, but this is a test suite */ - np_add_parameter(&paths, "/home/groups"); - np_add_parameter(&paths, "/var"); - np_add_parameter(&paths, "/tmp"); - np_add_parameter(&paths, "/home/tonvoon"); - np_add_parameter(&paths, "/home"); + for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) { + mp_int_fs_list_del(&test_paths, p); + } + ok(test_paths.length == 0, "List delete sets counter properly"); + + mp_int_fs_list_append(&test_paths, "/home/groups"); + mp_int_fs_list_append(&test_paths, "/var"); + mp_int_fs_list_append(&test_paths, "/tmp"); + mp_int_fs_list_append(&test_paths, "/home/tonvoon"); + mp_int_fs_list_append(&test_paths, "/home"); - np_set_best_match(paths, dummy_mount_list, true); - for (struct parameter_list *p = paths; p; p = p->name_next) { + mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, true); + for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) { if (!strcmp(p->name, "/home/groups")) { ok(!p->best_match, "/home/groups correctly not found"); } else if (!strcmp(p->name, "/var")) { @@ -129,8 +134,8 @@ int main(int argc, char **argv) { bool found = false; /* test deleting first element in paths */ - paths = np_del_parameter(paths, NULL); - for (struct parameter_list *p = paths; p; p = p->name_next) { + mp_int_fs_list_del(&test_paths, NULL); + for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) { if (!strcmp(p->name, "/home/groups")) { found = true; } @@ -138,23 +143,21 @@ int main(int argc, char **argv) { ok(!found, "first element successfully deleted"); found = false; - struct parameter_list *prev = NULL; - struct parameter_list *p = paths; - while (p) { - if (!strcmp(p->name, "/tmp")) { - p = np_del_parameter(p, prev); - } else { - prev = p; - p = p->name_next; + parameter_list_elem *prev = NULL; + parameter_list_elem *p = NULL; + for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) { + if (!strcmp(path->name, "/tmp")) { + mp_int_fs_list_del(&test_paths, path); } + p = path; } - struct parameter_list *last = NULL; - for (struct parameter_list *path = paths; path; path = path->name_next) { + parameter_list_elem *last = NULL; + for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) { if (!strcmp(path->name, "/tmp")) { found = true; } - if (path->name_next) { + if (path->next) { prev = path; } else { last = path; @@ -163,8 +166,8 @@ int main(int argc, char **argv) { ok(!found, "/tmp element successfully deleted"); int count = 0; - p = np_del_parameter(last, prev); - for (p = paths; p; p = p->name_next) { + mp_int_fs_list_del(&test_paths, p); + for (p = test_paths.first; p; p = p->next) { if (!strcmp(p->name, "/home")) { found = true; } -- cgit v1.2.3-74-g34f1 From c4fd34ed7966a197e596f3e766f58423fe9c5ddc Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 30 Mar 2025 22:46:09 +0200 Subject: Codespell fixes --- plugins/check_disk.c | 6 +++--- plugins/t/check_disk.t | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'plugins/t') diff --git a/plugins/check_disk.c b/plugins/check_disk.c index 3cab816d..ddb9ee49 100644 --- a/plugins/check_disk.c +++ b/plugins/check_disk.c @@ -288,7 +288,7 @@ int main(int argc, char **argv) { unit.name = strdup(filesystem->group); measurements = current = add_measurement_list(NULL, unit); } else { - // if this is the first element of a group, the name of the previos entry is different + // if this is the first element of a group, the name of the previous entry is different if (strcmp(filesystem->group, current->unit.name) != 0) { // so, this must be the first element of a group measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp); @@ -310,7 +310,7 @@ int main(int argc, char **argv) { mp_add_subcheck_to_check(&overall, unit_sc); } } else { - // Aparently no machting fs found + // Apparently no machting fs found mp_subcheck none_sc = mp_subcheck_init(); xasprintf(&none_sc.output, "No filesystems were found for the provided parameters"); @@ -833,7 +833,7 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { warn_freeinodes_percent, crit_freeinodes_percent); } - // If a list of paths has not been explicitely selected, find entire + // If a list of paths has not been explicitly selected, find entire // mount list and create list of paths if (!path_selected && !result.config.path_ignored) { for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) { diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t index 16daee9a..019cc9fe 100644 --- a/plugins/t/check_disk.t +++ b/plugins/t/check_disk.t @@ -39,13 +39,13 @@ like($result->{'mp_test_result'}->{'checks'}->[0]->{'state'}, "/OK/", "First sub like($result->{'mp_test_result'}->{'checks'}->[1]->{'state'}, "/OK/", "Second sub result is OK"); my $absolut_space_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'}; -# print("absolut space on mp1: ". $absolut_space_mp1 . "\n"); +# print("absolute space on mp1: ". $absolut_space_mp1 . "\n"); my $free_percent_on_mp1 = ($result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / ($absolut_space_mp1/100)); print("free percent on mp1: ". $free_percent_on_mp1 . "\n"); my $absolut_space_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'}; -# print("absolut space on mp2: ". $absolut_space_mp2 . "\n"); +# print("absolute space on mp2: ". $absolut_space_mp2 . "\n"); my $free_percent_on_mp2 = ($result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ ($absolut_space_mp2/100)); print("free percent on mp2: ". $free_percent_on_mp2 . "\n"); -- cgit v1.2.3-74-g34f1 From d1d6ba67065c0b1a8a61d59522e19a94eb647c94 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 30 Mar 2025 23:42:50 +0200 Subject: Add debugging to tests for CI --- plugins/t/check_disk.t | 3 +++ 1 file changed, 3 insertions(+) (limited to 'plugins/t') diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t index 019cc9fe..1d0b9838 100644 --- a/plugins/t/check_disk.t +++ b/plugins/t/check_disk.t @@ -129,6 +129,9 @@ my $warn_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[ my $crit_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'}; my $total_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'}; +print("warn_percth_data: " . $warn_percth_data . "\n"); +print("crit_percth_data: " . $crit_percth_data . "\n"); + is ($warn_percth_data <=> int((20/100)*$total_percth_data), 0, "Wrong warning in perf data using percent thresholds"); is ($crit_percth_data <=> int((10/100)*$total_percth_data), 0, "Wrong critical in perf data using percent thresholds"); -- cgit v1.2.3-74-g34f1 From 24a50b9421050b3c49dd07eddc942934f66685ca Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 31 Mar 2025 22:18:19 +0200 Subject: check_disk: decrease precision to avoid false negatives with small measurement changes --- plugins/t/check_disk.t | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'plugins/t') diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t index 1d0b9838..f07b2303 100644 --- a/plugins/t/check_disk.t +++ b/plugins/t/check_disk.t @@ -54,6 +54,10 @@ my @perfdata; @perfdata[0] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]; @perfdata[1] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]; +# Decrease precision of numbers since the the fs might be modified between the two runs +$perfdata[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000); +$perfdata[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000); + # Calculate avg_free free on mountpoint1 and mountpoint2 # because if you check in the middle, you should get different errors my $avg_free_percent = ceil(($free_percent_on_mp1+$free_percent_on_mp2)/2); @@ -144,8 +148,11 @@ cmp_ok( $result->return_code, "==", 0, "with JSON test format result should alwa # write comparison set for perfdata here, but in reversed order, maybe there is a smarter way my @perfdata2; -@perfdata2[1] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]; @perfdata2[0] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]; +@perfdata2[1] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]; +# Decrease precision of numbers since the the fs might be modified between the two runs +$perfdata2[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000); +$perfdata2[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000); is_deeply(\@perfdata, \@perfdata2, "perf data for both filesystems same when reversed"); # Basic filesystem checks for sizes -- cgit v1.2.3-74-g34f1 From 13c9de8c77477e78014622f5c4ff31226aeb286d Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 31 Mar 2025 22:29:49 +0200 Subject: Try fixing some tests --- plugins/t/check_disk.t | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t index f07b2303..0f62fb2b 100644 --- a/plugins/t/check_disk.t +++ b/plugins/t/check_disk.t @@ -26,7 +26,7 @@ my $output_format = "--output-format mp-test-json"; if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") { plan skip_all => "Need 2 mountpoints to test"; } else { - plan tests => 96; + plan tests => 97; } $result = NPTest->testCmd( @@ -56,7 +56,7 @@ my @perfdata; # Decrease precision of numbers since the the fs might be modified between the two runs $perfdata[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000); -$perfdata[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000); +$perfdata[1]->{'value'}->{'value'} = int($perfdata[1]->{'value'}->{'value'} / 1000000); # Calculate avg_free free on mountpoint1 and mountpoint2 # because if you check in the middle, you should get different errors @@ -136,8 +136,8 @@ my $total_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'} print("warn_percth_data: " . $warn_percth_data . "\n"); print("crit_percth_data: " . $crit_percth_data . "\n"); -is ($warn_percth_data <=> int((20/100)*$total_percth_data), 0, "Wrong warning in perf data using percent thresholds"); -is ($crit_percth_data <=> int((10/100)*$total_percth_data), 0, "Wrong critical in perf data using percent thresholds"); +is (int($warn_percth_data), int((20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds. Got " . $warn_percth_data . " with total " . $total_percth_data); +is (int($crit_percth_data), int((10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds. Got " . $crit_percth_data . " with total " . $total_percth_data); # Check when order of mount points are reversed, that perf data remains same @@ -151,8 +151,8 @@ my @perfdata2; @perfdata2[0] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]; @perfdata2[1] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]; # Decrease precision of numbers since the the fs might be modified between the two runs -$perfdata2[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000); -$perfdata2[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000); +$perfdata2[0]->{'value'}->{'value'} = int($perfdata2[0]->{'value'}->{'value'} / 1000000); +$perfdata2[1]->{'value'}->{'value'} = int($perfdata2[1]->{'value'}->{'value'} / 1000000); is_deeply(\@perfdata, \@perfdata2, "perf data for both filesystems same when reversed"); # Basic filesystem checks for sizes @@ -174,8 +174,9 @@ my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2; $result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free $output_format" ); cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK"); -$result = NPTest->testCmd( "./check_disk 100 100 $more_free" ); -cmp_ok( $result->return_code, '==', 0, "Old syntax okay" ); +$result = NPTest->testCmd( "./check_disk 101 101 $more_free" ); +like($result->output, "/OK/", "OK in Output"); +cmp_ok( $result->return_code, '==', 0, "Old syntax okay, output was: ". $result->output . "\n" ); $result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" ); cmp_ok( $result->return_code, "==", 0, "At least 1% free" ); -- cgit v1.2.3-74-g34f1 From b191a8a05543b22bf8e3255d74d358dd42ef1a89 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 6 Jul 2025 23:16:34 +0200 Subject: check_load: fix tests --- plugins/t/check_load.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_load.t b/plugins/t/check_load.t index 3e453703..fc26bb35 100644 --- a/plugins/t/check_load.t +++ b/plugins/t/check_load.t @@ -33,9 +33,9 @@ cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division"); $res = NPTest->testCmd( "./check_load -w 100 -c 100,110" ); cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments"); # like( $res->output, $successOutput, "Output OK"); -like( $res->perf_output, "/load1=$loadValue;~:100.0+;~:100.0+/", "Test handling of non triplet thresholds (load1)"); -like( $res->perf_output, "/load5=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load5)"); -like( $res->perf_output, "/load15=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load15)"); +like( $res->perf_output, "/'load1'=$loadValue;~:100.0+;~:100.0+/", "Test handling of non triplet thresholds (load1)"); +like( $res->perf_output, "/'load5'=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load5)"); +like( $res->perf_output, "/'load15'=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load15)"); $res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100 -r" ); -- cgit v1.2.3-74-g34f1 From 015e4c098693e6234de0994879a173dd2463fefd Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:42:06 +0200 Subject: check_snmp: fix/adapt tests --- plugins/t/check_snmp.t | 103 ++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 62 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_snmp.t b/plugins/t/check_snmp.t index 576cc506..99e01add 100644 --- a/plugins/t/check_snmp.t +++ b/plugins/t/check_snmp.t @@ -10,7 +10,7 @@ use NPTest; BEGIN { plan skip_all => 'check_snmp is not compiled' unless -x "./check_snmp"; - plan tests => 63; + plan tests => 42; } my $res; @@ -24,7 +24,7 @@ my $user_snmp = getTestParameter("NP_SNMP_USER", "An SNMP user", "auth_ $res = NPTest->testCmd( "./check_snmp -t 1" ); is( $res->return_code, 3, "No host name" ); -is( $res->output, "No host specified" ); +is( $res->output, "No OIDs specified" ); $res = NPTest->testCmd( "./check_snmp -H fakehostname --ignore-mib-parsing-errors" ); is( $res->return_code, 3, "No OIDs specified" ); @@ -32,145 +32,124 @@ is( $res->output, "No OIDs specified" ); $res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3 -U not_a_user --seclevel=rubbish" ); is( $res->return_code, 3, "Invalid seclevel" ); -like( $res->output, "/check_snmp: Invalid seclevel - rubbish/" ); +like( $res->output, "/invalid security level: rubbish/" ); $res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3c" ); is( $res->return_code, 3, "Invalid protocol" ); -like( $res->output, "/check_snmp: Invalid SNMP version - 3c/" ); +like( $res->output, "/invalid SNMP version/protocol: 3c/" ); SKIP: { skip "no snmp host defined", 50 if ( ! $host_snmp ); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -P 2c -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:"); cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" ); - like($res->output, '/^SNMP OK - (\d+)/', "String contains SNMP OK"); - $res->output =~ /^SNMP OK - (\d+)/; + $res->output =~ /\|.*=(\d+);/; my $value = $1; cmp_ok( $value, ">", 0, "Got a time value" ); like($res->perf_output, "/sysUpTime.*$1/", "Got perfdata with value '$1' in it"); # some more threshold tests - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1 -P 2c"); cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" ); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1: -P 2c"); cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" ); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1 -P 2c"); cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" ); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10 -P 2c"); cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" ); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10 -P 2c"); cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" ); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 10:1"); - cmp_ok( $res->return_code, '==', 0, "Threshold test -c 10:1" ); - - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1:"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1: -P 2c"); cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" ); - like($res->output, '/^SNMP OK - \d+/', "String contains SNMP OK"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -P 2c"); cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" ); unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0 -P 2c"); cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" ); - like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0 -P 2c"); cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" ); - like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1 -P 2c"); cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" ); - like($res->output, '/^SNMP OK - 1\s.*$/', "String fits SNMP OK and output format"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1:"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1: -P 2c"); cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " ); - like($res->output, '/^SNMP WARNING - \*1\*\s.*$/', "String matches SNMP WARNING and output format"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0 -P 2c"); cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" ); - like($res->output, '/^SNMP CRITICAL - \*1\*\s.*$/', "String matches SNMP CRITICAL and output format"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2 -P 2c"); cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" ); - like($res->output, "/^SNMP OK - 2 1/", "Got two values back" ); - like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); - like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" ); + like( $res->perf_output, "/ifIndex.2'?=2/", "Got 1st perf data" ); + like( $res->perf_output, "/ifIndex.1'?=1/", "Got 2nd perf data" ); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2 -P 2c"); cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" ); - like($res->output, "/^SNMP CRITICAL - 2 *1*/", "Got two values back" ); - like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); - like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" ); + like( $res->perf_output, "/ifIndex.2'?=2/", "Got 1st perf data" ); + like( $res->perf_output, "/ifIndex.1'?=1/", "Got 2nd perf data" ); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1:"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1: -P 2c"); cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses"); - like($res->output, '/^SNMP OK - \d+ \d+/', "String contains hrMemorySize and hrSystemProcesses"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0 -P 2c"); cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds"); - like($res->output, '/^SNMP OK - 1\s.*$/', "String matches SNMP OK and output format"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3"); - $res->output =~ m/^SNMP OK - (\d+\.\d{2})\s.*$/; + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoadInt.3 -P 2c"); + $res->output =~ m/^.*Value: (\d+).*$/; my $lower = $1 - 0.05; my $higher = $1 + 0.05; - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3 -w $lower -c $higher"); - cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractionnal arguments"); + # $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoadInt.3 -w $lower -c $higher -P 2c"); + # cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractional arguments"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2 -P 2c"); cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold"); - like($res->output, '/^SNMP WARNING - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s+\*1\*\s.*$/', "First OID returned as string, 2nd checked for thresholds"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c ''"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c '' -P 2c"); cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2 -P 2c"); cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check"); - like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping first two thresholds, result printed rather than parsed"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,,"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,, -P 2c"); cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds"); - like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping all thresholds, result printed rather than parsed"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec'"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec' -P 2c"); cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold"); - like($res->output, '/^SNMP CRITICAL - \*\d+\* 1\/100 sec.*$/', "Timetick used as a threshold, parsed as numeric"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -P 2c"); cmp_ok( $res->return_code, '==', 0, "Timetick used as a string"); - like($res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "Timetick used as a string, result printed rather than parsed"); - $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1"); + $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1 -P 2c"); cmp_ok( $res->return_code, '==', 0, "snmp response without datatype"); - like( $res->output, '/^SNMP OK - "(systemd|init)" \| $/', "snmp response without datatype" ); } SKIP: { skip "no SNMP user defined", 1 if ( ! $user_snmp ); $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -o HOST-RESOURCES-MIB::hrSystemUptime.0 -P 3 -U $user_snmp -L noAuthNoPriv"); - like( $res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "noAuthNoPriv security level works properly" ); } # These checks need a complete command line. An invalid community is used so # the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway SKIP: { skip "no non responsive host defined", 2 if ( ! $host_nonresponsive ); - $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); + $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1: -P 2c"); cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" ); - like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem"); + # like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem"); } SKIP: { skip "no non invalid host defined", 2 if ( ! $hostname_invalid ); - $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); + $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1: -P 2c"); cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" ); - like($res->output, '/External command error: .*(nosuchhost|Name or service not known|Unknown host).*/s', "String matches invalid host"); + like($res->output, '/.*Unknown host.*/s', "String matches invalid host"); } -- cgit v1.2.3-74-g34f1 From c43f845c22a9e879546472aa9051d7ca0803ef2a Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 9 Sep 2025 01:43:27 +0200 Subject: Adjust number of tests --- plugins/t/check_snmp.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins/t') diff --git a/plugins/t/check_snmp.t b/plugins/t/check_snmp.t index 99e01add..8d435df3 100644 --- a/plugins/t/check_snmp.t +++ b/plugins/t/check_snmp.t @@ -10,7 +10,7 @@ use NPTest; BEGIN { plan skip_all => 'check_snmp is not compiled' unless -x "./check_snmp"; - plan tests => 42; + plan tests => 62; } my $res; -- cgit v1.2.3-74-g34f1 From 6ae8ba911018571afddcf51c08e3d32f5efa3b5a Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sat, 13 Sep 2025 12:49:06 +0200 Subject: check_curl: test adaption and output adaption --- plugins/check_curl.c | 39 +++++++++++--------- plugins/t/check_curl.t | 4 +-- plugins/tests/check_curl.t | 89 +++++++++++++++++++++++----------------------- 3 files changed, 69 insertions(+), 63 deletions(-) (limited to 'plugins/t') diff --git a/plugins/check_curl.c b/plugins/check_curl.c index 17fb5564..89173808 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c @@ -238,7 +238,28 @@ mp_subcheck check_http(const check_curl_config config, check_curl_working_state return sc_result; } - xasprintf(&sc_curl.output, "cURL performed query"); + /* get status line of answer, check sanity of HTTP code */ + if (curlhelp_parse_statusline(curl_state.header_buf->buf, curl_state.status_line) < 0) { + sc_result = mp_set_subcheck_state(sc_result, STATE_CRITICAL); + /* we cannot know the major/minor version here for sure as we cannot parse the first + * line */ + xasprintf(&sc_result.output, "HTTP/x.x unknown - Unparsable status line"); + return sc_result; + } + + curl_state.status_line_initialized = true; + + size_t page_len = get_content_length(curl_state.header_buf, curl_state.body_buf); + + double total_time; + handle_curl_option_return_code( + curl_easy_getinfo(curl_state.curl, CURLINFO_TOTAL_TIME, &total_time), + "CURLINFO_TOTAL_TIME"); + + xasprintf( + &sc_curl.output, "%s %d %s - %ld bytes in %.3f second response time", + string_statuscode(curl_state.status_line->http_major, curl_state.status_line->http_minor), + curl_state.status_line->http_code, curl_state.status_line->msg, page_len, total_time); sc_curl = mp_set_subcheck_state(sc_curl, STATE_OK); mp_add_subcheck_to_subcheck(&sc_result, sc_curl); @@ -264,10 +285,6 @@ mp_subcheck check_http(const check_curl_config config, check_curl_working_state // total time the query took mp_perfdata pd_total_time = perfdata_init(); - double total_time; - handle_curl_option_return_code( - curl_easy_getinfo(curl_state.curl, CURLINFO_TOTAL_TIME, &total_time), - "CURLINFO_TOTAL_TIME"); mp_perfdata_value pd_val_total_time = mp_create_pd_value(total_time); pd_total_time.value = pd_val_total_time; pd_total_time = mp_pd_set_thresholds(pd_total_time, config.thlds); @@ -360,17 +377,6 @@ mp_subcheck check_http(const check_curl_config config, check_curl_working_state return sc_result; } - /* get status line of answer, check sanity of HTTP code */ - if (curlhelp_parse_statusline(curl_state.header_buf->buf, curl_state.status_line) < 0) { - sc_result = mp_set_subcheck_state(sc_result, STATE_CRITICAL); - /* we cannot know the major/minor version here for sure as we cannot parse the first - * line */ - xasprintf(&sc_result.output, "HTTP/x.x unknown - Unparsable status line"); - return sc_result; - } - - curl_state.status_line_initialized = true; - /* get result code from cURL */ long httpReturnCode; handle_curl_option_return_code( @@ -578,7 +584,6 @@ mp_subcheck check_http(const check_curl_config config, check_curl_working_state // size a.k.a. page length mp_perfdata pd_page_length = perfdata_init(); - size_t page_len = get_content_length(curl_state.header_buf, curl_state.body_buf); mp_perfdata_value pd_val_page_length = mp_create_pd_value(page_len); pd_page_length.value = pd_val_page_length; pd_page_length.label = "size"; diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t index 7a930a4e..7f1a2de0 100644 --- a/plugins/t/check_curl.t +++ b/plugins/t/check_curl.t @@ -18,7 +18,7 @@ BEGIN { } -my $successOutput = '/OK.*HTTP.*second/'; +my $successOutput = '/.*HTTP.*second/'; my $res; my $plugin = 'check_http'; @@ -63,7 +63,7 @@ $res = NPTest->testCmd( ); cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" ); # was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!) -like( $res->output, "/HTTP CRITICAL - Invalid HTTP response received from host on port 80: cURL returned 28 - Connection timed out after/", "Output OK"); +like( $res->output, "/Invalid HTTP response received from host on port 80: cURL returned 28 - Connection timed out after/", "Output OK"); $res = NPTest->testCmd( "./$plugin $hostname_invalid -wt 1 -ct 2" diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t index eaa9f518..e66d0ba6 100755 --- a/plugins/tests/check_curl.t +++ b/plugins/tests/check_curl.t @@ -15,6 +15,7 @@ # Email Address []:devel@monitoring-plugins.org use strict; +use warnings; use Test::More; use NPTest; use FindBin qw($Bin); @@ -245,21 +246,21 @@ SKIP: { $result = NPTest->testCmd( "$command -p $port_https -S -C 14" ); is( $result->return_code, 0, "$command -p $port_https -S -C 14" ); - is( $result->output, "OK - Certificate 'Monitoring Plugins' will expire on $expiry.", "output ok" ); + like( $result->output, "/.*Certificate \'Monitoring Plugins\' will expire on $expiry.*", "output ok" ); $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" ); is( $result->return_code, 1, "$command -p $port_https -S -C 14000" ); - like( $result->output, '/WARNING - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" ); + like( $result->output, '/.*Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\).*/', "output ok" ); # Expired cert tests $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" ); is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" ); - like( $result->output, '/CRITICAL - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" ); + like( $result->output, '/.*Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\).*/', "output ok" ); $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" ); is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" ); - is( $result->output, - 'CRITICAL - Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.', + like( $result->output, + '/.*Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.*/', "output ok" ); } @@ -274,19 +275,19 @@ SKIP: { $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$port_http\$"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); # http with virtual port (!= 80) $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$virtual_port\$"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); # http with virtual port (80) $cmd = "./$plugin -H $virtual_host:80 -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host\$"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); } # and the same for SSL @@ -296,19 +297,19 @@ SKIP: { $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$port_https\$"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); # https with virtual port (!= 443) $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$virtual_port\$"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); # https with virtual port (443) $cmd = "./$plugin -H $virtual_host:443 -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host\$"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); } @@ -321,165 +322,165 @@ sub run_common_tests { $result = NPTest->testCmd( "$command -u /file/root" ); is( $result->return_code, 0, "/file/root"); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" ); + like( $result->output, '/.*HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second.*/', "Output correct" ); $result = NPTest->testCmd( "$command -u /file/root -s Root" ); is( $result->return_code, 0, "/file/root search for string"); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" ); + like( $result->output, '/.*HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second.*/', "Output correct" ); $result = NPTest->testCmd( "$command -u /file/root -s NonRoot" ); is( $result->return_code, 2, "Missing string check"); - like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location"); + like( $result->output, qr%string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location"); $result = NPTest->testCmd( "$command -u /file/root -s NonRootWithOver30charsAndMoreFunThanAWetFish" ); is( $result->return_code, 2, "Missing string check"); - like( $result->output, qr%HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location"); + like( $result->output, qr%string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location"); $result = NPTest->testCmd( "$command -u /header_check -d foo" ); is( $result->return_code, 0, "header_check search for string"); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second/', "Output correct" ); + like( $result->output, '/.*HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second.*/', "Output correct" ); $result = NPTest->testCmd( "$command -u /header_check -d bar" ); is( $result->return_code, 2, "Missing header string check"); - like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location"); + like( $result->output, qr%header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location"); $result = NPTest->testCmd( "$command -u /header_broken_check" ); is( $result->return_code, 0, "header_check search for string"); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second/', "Output correct" ); + like( $result->output, '/.*HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second.*/', "Output correct" ); my $cmd; $cmd = "$command -u /slow"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, "$cmd"); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $result->output =~ /in ([\d\.]+) second/; cmp_ok( $1, ">", 1, "Time is > 1 second" ); $cmd = "$command -u /statuscode/200"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -u /statuscode/200 -e 200"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*Status line output matched "200".*/', "Output correct: ".$result->output ); $cmd = "$command -u /statuscode/201"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -u /statuscode/201 -e 201"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "201" - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output ); + like( $result->output, '/.*Status line output matched "201".*/', "Output correct: ".$result->output ); $cmd = "$command -u /statuscode/201 -e 200"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 2, $cmd); - like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created/', "Output correct: ".$result->output ); + like( $result->output, '/.*Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created.*/', "Output correct: ".$result->output ); $cmd = "$command -u /statuscode/200 -e 200,201,202"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*Status line output matched "200,201,202".*/', "Output correct: ".$result->output ); $cmd = "$command -u /statuscode/201 -e 200,201,202"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*Status line output matched "200,201,202".*/', "Output correct: ".$result->output ); $cmd = "$command -u /statuscode/203 -e 200,201,202"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 2, $cmd); - like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information/', "Output correct: ".$result->output ); + like( $result->output, '/.*Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information.*/', "Output correct: ".$result->output ); $cmd = "$command -j HEAD -u /method"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -j POST -u /method"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -j GET -u /method"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -u /method"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -P foo -u /method"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -j DELETE -u /method"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 1, $cmd); - like( $result->output, '/^HTTP WARNING: HTTP/1.1 405 Method Not Allowed/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 405 Method Not Allowed.*/', "Output correct: ".$result->output ); $cmd = "$command -j foo -u /method"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 2, $cmd); - like( $result->output, '/^HTTP CRITICAL: HTTP/1.1 501 Not Implemented/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 501 Not Implemented.*/', "Output correct: ".$result->output ); $cmd = "$command -P stufftoinclude -u /postdata -s POST:stufftoinclude"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -j PUT -P stufftoinclude -u /postdata -s PUT:stufftoinclude"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); # To confirm that the free doesn't segfault $cmd = "$command -P stufftoinclude -j PUT -u /postdata -s PUT:stufftoinclude"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -u /redirect"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -f follow -u /redirect"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -u /redirect -k 'follow: me'"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -f follow -u /redirect -k 'follow: me'"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -f sticky -u /redirect -k 'follow: me'"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -f stickyport -u /redirect -k 'follow: me'"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); $cmd = "$command -f follow -u /redirect_rel -s redirected"; $result = NPTest->testCmd( $cmd ); is( $result->return_code, 0, $cmd); - like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); + like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); # These tests may block # stickyport - on full urlS port is set back to 80 otherwise -- cgit v1.2.3-74-g34f1 From 404d52efb9b814013d5664019cab714253ac13ff Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 15 Sep 2025 01:58:26 +0200 Subject: Fix/adapt tests --- plugins/t/check_curl.t | 43 +++++++++++++++++++++++++++---------------- plugins/tests/check_curl.t | 4 ++-- 2 files changed, 29 insertions(+), 18 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t index 7f1a2de0..240c8f37 100644 --- a/plugins/t/check_curl.t +++ b/plugins/t/check_curl.t @@ -124,14 +124,14 @@ SKIP: { $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" ); cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'"); - like ( $res->output, "/pattern not found/", "Error message says 'pattern not found'"); + like ( $res->output, "/matched not/", "Error message says 'matched not'"); $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" ); cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'"); $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" ); cmp_ok( $res->return_code, "==", 2, "Invert results work when found"); - like ( $res->output, "/pattern found/", "Error message says 'pattern found'"); + like ( $res->output, "/matched/", "Error message says 'matched'"); $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" ); cmp_ok( $res->return_code, "==", 0, "And also when not found"); @@ -151,63 +151,74 @@ SKIP: { $res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" ); cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http"); - like ( $res->output, qr/WARNING - Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" ); + like ( $res->output, qr/Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" ); $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" ); is( $res->return_code, 0, "Old syntax for cert checking okay" ); - is( $res->output, $saved_cert_output, "Same output as new syntax" ); + # deactived since different timings will change the output + # TODO compare without perfdata + # is( $res->output, $saved_cert_output, "Same output as new syntax" ); $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" ); is( $res->return_code, 0, "Updated syntax for cert checking okay" ); - is( $res->output, $saved_cert_output, "Same output as new syntax" ); + # deactived since different timings will change the output + # TODO compare without perfdata + # is( $res->output, $saved_cert_output, "Same output as new syntax" ); $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" ); - cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added"); + # deactived since different timings will change the output + # TODO compare without perfdata + # cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added"); $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" ); - cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works"); + # deactived since different timings will change the output + # TODO compare without perfdata + # cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works"); # run some certificate checks with faketime SKIP: { skip "No faketime binary found", 12 if !$faketime; $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http"); - like($res->output, qr/OK - Certificate '$host_tls_cert' will expire on/, "Catch cert output"); + like($res->output, qr/Certificate '$host_tls_cert' will expire on/, "Catch cert output"); is( $res->return_code, 0, "Catch cert output exit code" ); + my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/); if(!defined $year) { die("parsing date failed from: ".$res->output); } + my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11}; my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900); my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts)); + $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http"); - like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' just expired/, "Output on expire date"); + like($res->output, qr/Certificate '$host_tls_cert' just expired/, "Output on expire date"); is( $res->return_code, 2, "Output on expire date" ); $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http"); - like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output"); + like($res->output, qr/Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output"); is( $res->return_code, 2, "cert expires in 1 second exit code" ); $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http"); - like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output"); + like($res->output, qr/Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output"); is( $res->return_code, 2, "cert expires in 2 minutes exit code" ); $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http"); - like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output"); + like($res->output, qr/Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output"); is( $res->return_code, 2, "cert expires in 2 hours exit code" ); $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http"); - like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expired on/, "Certificate expired output"); + like($res->output, qr/Certificate '$host_tls_cert' expired on/, "Certificate expired output"); is( $res->return_code, 2, "Certificate expired exit code" ); }; $res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" ); - like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' ); - like ( $res->output, '/time_ssl=[\d\.]+/', 'Extended Performance Data SSL Output OK' ); + like ( $res->output, '/\'time_connect\'=[\d\.]+/', 'Extended Performance Data Output OK' ); + like ( $res->output, '/\'time_tls\'=[\d\.]+/', 'Extended Performance Data SSL Output OK' ); $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org -u /download.html -f follow" ); is( $res->return_code, 0, "Redirection based on location is okay"); $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org --extended-perfdata" ); - like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' ); + like ( $res->output, '/\'time_connect\'=[\d\.]+/', 'Extended Performance Data Output OK' ); } diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t index e66d0ba6..52c5ad1c 100755 --- a/plugins/tests/check_curl.t +++ b/plugins/tests/check_curl.t @@ -246,7 +246,7 @@ SKIP: { $result = NPTest->testCmd( "$command -p $port_https -S -C 14" ); is( $result->return_code, 0, "$command -p $port_https -S -C 14" ); - like( $result->output, "/.*Certificate \'Monitoring Plugins\' will expire on $expiry.*", "output ok" ); + like( $result->output, '/.*Certificate \'Monitoring Plugins\' will expire on ' . quotemeta($expiry) . '.*/', "output ok" ); $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" ); is( $result->return_code, 1, "$command -p $port_https -S -C 14000" ); @@ -260,7 +260,7 @@ SKIP: { $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" ); is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" ); like( $result->output, - '/.*Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.*/', + '/.*Certificate \'Monitoring Plugins\' expired on Wed Jan\s+2 12:00:00 2008 \+0000.*/', "output ok" ); } -- cgit v1.2.3-74-g34f1 From c892db9ae16183fdda9c96b3d4b93c58355b34ac Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 15 Sep 2025 02:02:04 +0200 Subject: Fix typos --- plugins/t/check_curl.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t index 240c8f37..5d1f1811 100644 --- a/plugins/t/check_curl.t +++ b/plugins/t/check_curl.t @@ -155,23 +155,23 @@ SKIP: { $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" ); is( $res->return_code, 0, "Old syntax for cert checking okay" ); - # deactived since different timings will change the output + # deactivated since different timings will change the output # TODO compare without perfdata # is( $res->output, $saved_cert_output, "Same output as new syntax" ); $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" ); is( $res->return_code, 0, "Updated syntax for cert checking okay" ); - # deactived since different timings will change the output + # deactivated since different timings will change the output # TODO compare without perfdata # is( $res->output, $saved_cert_output, "Same output as new syntax" ); $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" ); - # deactived since different timings will change the output + # deactivated since different timings will change the output # TODO compare without perfdata # cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added"); $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" ); - # deactived since different timings will change the output + # deactivated since different timings will change the output # TODO compare without perfdata # cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works"); -- cgit v1.2.3-74-g34f1 From c07dd02beefe225e077048166bc0fb6eb516bdf9 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 15 Sep 2025 02:09:04 +0200 Subject: Adapt test to new error message --- plugins/t/check_curl.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins/t') diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t index 5d1f1811..2b2d81a8 100644 --- a/plugins/t/check_curl.t +++ b/plugins/t/check_curl.t @@ -63,7 +63,7 @@ $res = NPTest->testCmd( ); cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" ); # was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!) -like( $res->output, "/Invalid HTTP response received from host on port 80: cURL returned 28 - Connection timed out after/", "Output OK"); +like( $res->output, "/cURL returned 28 - Connection timed out after/", "Output OK"); $res = NPTest->testCmd( "./$plugin $hostname_invalid -wt 1 -ct 2" -- cgit v1.2.3-74-g34f1 From eca9eaf9f5771e417366bd3dac0cd463f405eb70 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 15 Sep 2025 02:17:44 +0200 Subject: fix number of tests --- plugins/t/check_curl.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins/t') diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t index 2b2d81a8..2c2fafde 100644 --- a/plugins/t/check_curl.t +++ b/plugins/t/check_curl.t @@ -13,7 +13,7 @@ use vars qw($tests $has_ipv6); BEGIN { use NPTest; $has_ipv6 = NPTest::has_ipv6(); - $tests = $has_ipv6 ? 59 : 57; + $tests = $has_ipv6 ? 55 : 53; plan tests => $tests; } -- cgit v1.2.3-74-g34f1 From c4716ad8d8dfdcc0b1ab4b1614b626360b7cca07 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:39:30 +0200 Subject: Fix check_apt tests --- plugins/t/check_apt.t | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_apt.t b/plugins/t/check_apt.t index 430eb53e..736bc2f2 100644 --- a/plugins/t/check_apt.t +++ b/plugins/t/check_apt.t @@ -5,6 +5,7 @@ # use strict; +use warnings; use Test::More; use NPTest; @@ -12,18 +13,18 @@ sub make_result_regexp { my ($warning, $critical) = @_; my $status; if ($warning == 0 && $critical == 0) { - $status = "OK"; + $status = "OK"; } elsif ($critical == 0) { - $status = "WARNING"; + $status = "WARNING"; } else { - $status = "CRITICAL"; + $status = "CRITICAL"; } - return sprintf('/^APT %s: %d packages available for upgrade \(%d critical updates\)\. |available_upgrades=%d;;;0 critical_updates=%d;;;0$/', + return sprintf('/.*[%s].*Updates available: %d.*Security updates available: %d.*\'available_upgrades\'=%d;;; \'critical_updates\'=%d;;; /s', $status, $warning, $critical, $warning, $critical); } if (-x "./check_apt") { - plan tests => 36; + plan tests => 35; } else { plan skip_all => "No check_apt compiled"; } @@ -42,7 +43,8 @@ like( $result->output, make_result_regexp(13, 0), "Output correct" ); $result = NPTest->testCmd( sprintf($testfile_command, "-o", "debian2") ); is( $result->return_code, 0, "Debian apt output, no critical" ); -like( $result->output, make_result_regexp(13, 0), "Output correct" ); +# this test does not work, since -o was given +# like( $result->output, make_result_regexp(13, 0), "Output correct" ); $result = NPTest->testCmd( sprintf($testfile_command, "", "debian3") ); is( $result->return_code, 2, "Debian apt output, some critical" ); -- cgit v1.2.3-74-g34f1 From ec5fd11c1d1f6117e1bccf4955fa99ba5706c6b4 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:05:55 +0100 Subject: check_dbi: new output functionality --- plugins/check_dbi.c | 430 ++++++++++++++++++++++++++++++++++---------------- plugins/t/check_dbi.t | 10 +- 2 files changed, 295 insertions(+), 145 deletions(-) (limited to 'plugins/t') diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c index 786fc1b6..84e3cb5b 100644 --- a/plugins/check_dbi.c +++ b/plugins/check_dbi.c @@ -29,12 +29,14 @@ * *****************************************************************************/ -#include "states.h" const char *progname = "check_dbi"; const char *copyright = "2011-2024"; const char *email = "devel@monitoring-plugins.org"; #include "../lib/monitoringplug.h" +#include "perfdata.h" +#include "output.h" +#include "states.h" #include "check_dbi.d/config.h" #include "common.h" #include "utils.h" @@ -72,9 +74,15 @@ static double timediff(struct timeval /*start*/, struct timeval /*end*/); static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...); -static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/, - double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/, - mp_dbi_type /*type*/, char * /*np_dbi_query*/); +typedef struct { + char *result_string; + double result_number; + double query_duration; + int error_code; + const char *error_string; + mp_state_enum query_processing_status; +} do_query_result; +static do_query_result do_query(dbi_conn conn, mp_dbi_metric metric, mp_dbi_type type, char *query); int main(int argc, char **argv) { setlocale(LC_ALL, ""); @@ -104,16 +112,17 @@ int main(int argc, char **argv) { dbi_inst instance_p = NULL; if (dbi_initialize_r(NULL, &instance_p) < 0) { - printf( - "UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n"); - return STATE_UNKNOWN; + printf("failed to initialize DBI; possibly you don't have any drivers installed.\n"); + exit(STATE_UNKNOWN); } + // Try to prevent libdbi from printing stuff on stderr + // Who thought that would be a good idea anyway? dbi_set_verbosity_r(0, instance_p); if (instance_p == NULL) { - printf("UNKNOWN - failed to initialize DBI.\n"); - return STATE_UNKNOWN; + printf("failed to initialize DBI.\n"); + exit(STATE_UNKNOWN); } if (verbose) { @@ -122,15 +131,14 @@ int main(int argc, char **argv) { dbi_driver driver = dbi_driver_open_r(config.dbi_driver, instance_p); if (!driver) { - printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", - config.dbi_driver); + printf("failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver); printf("Known drivers:\n"); for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) { printf(" - %s\n", dbi_driver_get_name(driver)); } - return STATE_UNKNOWN; + exit(STATE_UNKNOWN); } /* make a connection to the database */ @@ -141,7 +149,7 @@ int main(int argc, char **argv) { if (!conn) { printf("UNKNOWN - failed top open connection object.\n"); dbi_conn_close(conn); - return STATE_UNKNOWN; + exit(STATE_UNKNOWN); } for (size_t i = 0; i < config.dbi_options_num; ++i) { @@ -155,10 +163,10 @@ int main(int argc, char **argv) { if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) { continue; } - /* else: status != 0 */ - np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", - config.dbi_options[i].key, config.dbi_options[i].value); + // Failing to set option + np_dbi_print_error(conn, "failed to set option '%s' to '%s'", config.dbi_options[i].key, + config.dbi_options[i].value); printf("Known driver options:\n"); for (opt = dbi_conn_get_option_list(conn, NULL); opt; @@ -166,7 +174,7 @@ int main(int argc, char **argv) { printf(" - %s\n", opt); } dbi_conn_close(conn); - return STATE_UNKNOWN; + exit(STATE_UNKNOWN); } if (config.host) { @@ -194,31 +202,60 @@ int main(int argc, char **argv) { } if (dbi_conn_connect(conn) < 0) { - np_dbi_print_error(conn, "UNKNOWN - failed to connect to database"); - return STATE_UNKNOWN; + np_dbi_print_error(conn, "failed to connect to database"); + exit(STATE_UNKNOWN); } struct timeval end_timeval; gettimeofday(&end_timeval, NULL); double conn_time = timediff(start_timeval, end_timeval); + if (verbose) { + printf("Time elapsed: %f\n", conn_time); + } + + mp_check overall = mp_check_init(); + + mp_subcheck sc_connection_time = mp_subcheck_init(); + sc_connection_time = mp_set_subcheck_default_state(sc_connection_time, STATE_OK); + xasprintf(&sc_connection_time.output, "Connection time: %f", conn_time); + + mp_perfdata pd_conn_duration = perfdata_init(); + pd_conn_duration.label = "conntime"; + pd_conn_duration = mp_set_pd_value(pd_conn_duration, conn_time); + + if (config.metric == METRIC_CONN_TIME) { + // TODO set pd thresholds + mp_state_enum status = get_status(conn_time, config.dbi_thresholds); + sc_connection_time = mp_set_subcheck_state(sc_connection_time, status); + if (status != STATE_OK) { + xasprintf(&sc_connection_time.output, "%s violates thresholds", + sc_connection_time.output); + } + } + + mp_add_perfdata_to_subcheck(&sc_connection_time, pd_conn_duration); + mp_add_subcheck_to_check(&overall, sc_connection_time); unsigned int server_version = dbi_conn_get_engine_version(conn); if (verbose) { printf("Connected to server version %u\n", server_version); } - int status = STATE_UNKNOWN; + mp_subcheck sc_server_version = mp_subcheck_init(); + sc_server_version = mp_set_subcheck_default_state(sc_server_version, STATE_OK); + xasprintf(&sc_server_version.output, "Connected to server version %u", server_version); + if (config.metric == METRIC_SERVER_VERSION) { - status = get_status(server_version, config.dbi_thresholds); - } + mp_state_enum status = get_status(server_version, config.dbi_thresholds); - if (verbose) { - printf("Time elapsed: %f\n", conn_time); - } + sc_server_version = mp_set_subcheck_state(sc_server_version, status); - if (config.metric == METRIC_CONN_TIME) { - status = get_status(conn_time, config.dbi_thresholds); - } + if (status != STATE_OK) { + xasprintf(&sc_server_version.output, "%s violates thresholds", + sc_server_version.output); + } + }; + mp_add_subcheck_to_check(&overall, sc_server_version); /* select a database */ if (config.dbi_database) { @@ -226,58 +263,152 @@ int main(int argc, char **argv) { printf("Selecting database '%s'\n", config.dbi_database); } + mp_subcheck sc_select_db = mp_subcheck_init(); + sc_select_db = mp_set_subcheck_default_state(sc_select_db, STATE_OK); + if (dbi_conn_select_db(conn, config.dbi_database)) { np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.dbi_database); - return STATE_UNKNOWN; + exit(STATE_UNKNOWN); + } else { + mp_add_subcheck_to_check(&overall, sc_select_db); } } - const char *query_val_str = NULL; - double query_val = 0.0; - double query_time = 0.0; + // Do a query (if configured) if (config.dbi_query) { + mp_subcheck sc_query = mp_subcheck_init(); + sc_query = mp_set_subcheck_default_state(sc_query, STATE_UNKNOWN); + /* execute query */ - status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type, - config.dbi_query); - if (status != STATE_OK) { - /* do_query prints an error message in this case */ - return status; - } + do_query_result query_res = do_query(conn, config.metric, config.type, config.dbi_query); + + if (query_res.error_code != 0) { + xasprintf(&sc_query.output, "Query failed: %s", query_res.error_string); + sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); + } else if (query_res.query_processing_status != STATE_OK) { + if (query_res.error_string) { + xasprintf(&sc_query.output, "Failed to process query: %s", query_res.error_string); + } else { + xasprintf(&sc_query.output, "Failed to process query"); + } + sc_query = mp_set_subcheck_state(sc_query, query_res.query_processing_status); + } else { + // query succeeded in general + xasprintf(&sc_query.output, "Query '%s' succeeded", config.dbi_query); + + // that's a OK by default now + sc_query = mp_set_subcheck_default_state(sc_query, STATE_OK); + + // query duration first + mp_perfdata pd_query_duration = perfdata_init(); + pd_query_duration = mp_set_pd_value(pd_query_duration, query_res.query_duration); + pd_query_duration.label = "querytime"; + if (config.metric == METRIC_QUERY_TIME) { + // TODO set thresholds + } + + mp_add_perfdata_to_subcheck(&sc_query, pd_query_duration); - if (config.metric == METRIC_QUERY_RESULT) { - if (config.expect) { - if ((!query_val_str) || strcmp(query_val_str, config.expect)) { - status = STATE_CRITICAL; + if (config.metric == METRIC_QUERY_RESULT) { + if (config.expect) { + if ((!query_res.result_string) || + strcmp(query_res.result_string, config.expect)) { + xasprintf(&sc_query.output, "Found string '%s' in query result", + config.expect); + sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); + } else { + xasprintf(&sc_query.output, "Did not find string '%s' in query result", + config.expect); + sc_query = mp_set_subcheck_state(sc_query, STATE_OK); + } + } else if (config.expect_re_str) { + int comp_err; + regex_t expect_re = {}; + comp_err = regcomp(&expect_re, config.expect_re_str, config.expect_re_cflags); + if (comp_err != 0) { + // TODO error, failed to compile regex + // TODO move this to config sanitatisation + printf("Failed to compile regex from string '%s'", config.expect_re_str); + exit(STATE_UNKNOWN); + } + + int err = + regexec(&expect_re, query_res.result_string, 0, NULL, /* flags = */ 0); + if (!err) { + sc_query = mp_set_subcheck_state(sc_query, STATE_OK); + xasprintf(&sc_query.output, "Found regular expression '%s' in query result", + config.expect_re_str); + } else if (err == REG_NOMATCH) { + sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); + xasprintf(&sc_query.output, + "Did not find regular expression '%s' in query result", + config.expect_re_str); + } else { + char errmsg[1024]; + regerror(err, &expect_re, errmsg, sizeof(errmsg)); + xasprintf(&sc_query.output, + "ERROR - failed to execute regular expression: %s\n", errmsg); + sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); + } } else { - status = STATE_OK; - } - } else if (config.expect_re_str) { - int comp_err; - regex_t expect_re = {}; - comp_err = regcomp(&expect_re, config.expect_re_str, config.expect_re_cflags); - if (comp_err != 0) { - // TODO error, failed to compile regex - return STATE_UNKNOWN; + // no string matching + if (isnan(query_res.result_number)) { + // The query result is not a number, but no string checking was configured + // so we expected a number + // this is a CRITICAL + xasprintf(&sc_query.output, "Query '%s' result is not numeric", + config.dbi_query, query_res.result_string); + sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); + + } else { + mp_state_enum query_numerical_result = + get_status(query_res.result_number, config.dbi_thresholds); + sc_query = mp_set_subcheck_state(sc_query, query_numerical_result); + + mp_perfdata pd_query_val = perfdata_init(); + pd_query_val = mp_set_pd_value(pd_query_val, query_res.result_number); + pd_query_val.label = "query"; + mp_add_perfdata_to_subcheck(&sc_query, pd_query_val); + + // TODO set pd thresholds + // if (config.dbi_thresholds->warning) { + // pd_query_val.warn= config.dbi_thresholds->warning + // } else { + // } + + if (query_numerical_result == STATE_OK) { + xasprintf(&sc_query.output, + "Query result '%f' is within given thresholds", + query_res.result_number); + } else { + xasprintf(&sc_query.output, + "Query result '%f' violates the given thresholds", + query_res.result_number); + } + } } - - int err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0); - if (!err) { - status = STATE_OK; - } else if (err == REG_NOMATCH) { - status = STATE_CRITICAL; + } else if (config.metric == METRIC_QUERY_TIME) { + mp_state_enum query_time_status = + get_status(query_res.query_duration, config.dbi_thresholds); + mp_set_subcheck_state(sc_query, query_time_status); + + if (query_time_status == STATE_OK) { + xasprintf(&sc_query.output, "Query duration '%f' is withing given thresholds", + query_res.query_duration); } else { - char errmsg[1024]; - regerror(err, &expect_re, errmsg, sizeof(errmsg)); - printf("ERROR - failed to execute regular expression: %s\n", errmsg); - status = STATE_CRITICAL; + xasprintf(&sc_query.output, "Query duration '%f' violates the given thresholds", + query_res.query_duration); } } else { - status = get_status(query_val, config.dbi_thresholds); + /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error + * which should have been reported and handled (abort) before + * ... unless we expected a string to be returned */ + assert((!isnan(query_res.result_number)) || (config.type == TYPE_STRING)); } - } else if (config.metric == METRIC_QUERY_TIME) { - status = get_status(query_time, config.dbi_thresholds); } + + mp_add_subcheck_to_check(&overall, sc_query); } if (verbose) { @@ -285,63 +416,7 @@ int main(int argc, char **argv) { } dbi_conn_close(conn); - /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error - * which should have been reported and handled (abort) before - * ... unless we expected a string to be returned */ - assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || - (config.type == TYPE_STRING)); - - assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str)); - - printf("%s - connection time: %fs", state_text(status), conn_time); - if (config.dbi_query) { - if (config.type == TYPE_STRING) { - assert(config.expect || config.expect_re_str); - printf(", '%s' returned '%s' in %fs", config.dbi_query, - query_val_str ? query_val_str : "", query_time); - if (status != STATE_OK) { - if (config.expect) { - printf(" (expected '%s')", config.expect); - } else if (config.expect_re_str) { - printf(" (expected regex /%s/%s)", config.expect_re_str, - ((config.expect_re_cflags & REG_ICASE) ? "i" : "")); - } - } - } else if (isnan(query_val)) { - printf(", '%s' query execution time: %fs", config.dbi_query, query_time); - } else { - printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time); - } - } - - printf( - " | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, - ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "", - ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", - server_version, - ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range - : "", - ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range - : ""); - if (config.dbi_query) { - if (!isnan(query_val)) { /* this is also true when -e is used */ - printf(" query=%f;%s;%s;;", query_val, - ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) - ? config.warning_range - : "", - ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) - ? config.critical_range - : ""); - } - printf(" querytime=%fs;%s;%s;0;", query_time, - ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range - : "", - ((config.metric == METRIC_QUERY_TIME) && config.critical_range) - ? config.critical_range - : ""); - } - printf("\n"); - return status; + mp_exit(overall); } /* process command-line arguments */ @@ -349,7 +424,6 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) { int option = 0; static struct option longopts[] = {STD_LONG_OPTS, - {"expect", required_argument, 0, 'e'}, {"regex", required_argument, 0, 'r'}, {"regexi", required_argument, 0, 'R'}, @@ -533,6 +607,10 @@ check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrap usage("Options -r/-R require metric QUERY_RESULT"); } + if (config_wrapper.config.type == TYPE_STRING) { + assert(config_wrapper.config.expect || config_wrapper.config.expect_re_str); + } + config_wrapper.errorcode = OK; return config_wrapper; } @@ -783,38 +861,110 @@ mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_v return STATE_OK; } -mp_state_enum do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time, - mp_dbi_metric metric, mp_dbi_type type, char *np_dbi_query) { - dbi_result res; - - struct timeval timeval_start; - struct timeval timeval_end; - mp_state_enum status = STATE_OK; - - assert(np_dbi_query); +static do_query_result do_query(dbi_conn conn, mp_dbi_metric metric, mp_dbi_type type, + char *query) { + assert(query); if (verbose) { - printf("Executing query '%s'\n", np_dbi_query); + printf("Executing query '%s'\n", query); } + do_query_result result = { + .query_duration = 0, + .result_string = NULL, + .result_number = 0, + .error_code = 0, + .query_processing_status = STATE_UNKNOWN, + }; + + struct timeval timeval_start; gettimeofday(&timeval_start, NULL); - res = dbi_conn_query(conn, np_dbi_query); + dbi_result res = dbi_conn_query(conn, query); if (!res) { - np_dbi_print_error(conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); - return STATE_CRITICAL; + dbi_conn_error(conn, &result.error_string); + result.error_code = 1; + return result; } - status = get_query_result(conn, res, res_val_str, res_val, metric, type); - + struct timeval timeval_end; gettimeofday(&timeval_end, NULL); - *res_time = timediff(timeval_start, timeval_end); + result.query_duration = timediff(timeval_start, timeval_end); if (verbose) { - printf("Time elapsed: %f\n", *res_time); + printf("Query duration: %f\n", result.query_duration); + } + + // Default state is OK, all error will be set explicitely + mp_state_enum query_processing_state = STATE_OK; + { + + if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) { + if (metric != METRIC_QUERY_RESULT) { + query_processing_state = STATE_OK; + } else { + dbi_conn_error(conn, &result.error_string); + query_processing_state = STATE_CRITICAL; + } + } else if (dbi_result_get_numrows(res) < 1) { + if (metric != METRIC_QUERY_RESULT) { + query_processing_state = STATE_OK; + } else { + result.error_string = "no rows returned"; + // printf("WARNING - no rows returned\n"); + query_processing_state = STATE_WARNING; + } + } else if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) { + if (metric != METRIC_QUERY_RESULT) { + query_processing_state = STATE_OK; + } else { + dbi_conn_error(conn, &result.error_string); + // np_dbi_print_error(conn, "CRITICAL - failed to fetch fields"); + query_processing_state = STATE_CRITICAL; + } + } else if (dbi_result_get_numfields(res) < 1) { + if (metric != METRIC_QUERY_RESULT) { + query_processing_state = STATE_OK; + } else { + result.error_string = "no fields returned"; + // printf("WARNING - no fields returned\n"); + query_processing_state = STATE_WARNING; + } + } else if (dbi_result_first_row(res) != 1) { + if (metric != METRIC_QUERY_RESULT) { + query_processing_state = STATE_OK; + } else { + dbi_conn_error(conn, &result.error_string); + // np_dbi_print_error(conn, "CRITICAL - failed to fetch first row"); + query_processing_state = STATE_CRITICAL; + } + } else { + unsigned short field_type = dbi_result_get_field_type_idx(res, 1); + if (field_type != DBI_TYPE_ERROR) { + if (type == TYPE_STRING) { + result.result_string = + strdup(get_field_str(conn, res, field_type, metric, type)); + } else { + result.result_number = get_field(conn, res, &field_type, metric, type); + } + } else { + // Error when retrieving the field, that is OK if the Query result is not of + // interest + if (metric != METRIC_QUERY_RESULT) { + query_processing_state = STATE_OK; + } else { + dbi_conn_error(conn, &result.error_string); + // np_dbi_print_error(conn, "CRITICAL - failed to fetch data"); + query_processing_state = STATE_CRITICAL; + } + } + } } + dbi_result_free(res); + + result.query_processing_status = query_processing_state; - return status; + return result; } double timediff(struct timeval start, struct timeval end) { diff --git a/plugins/t/check_dbi.t b/plugins/t/check_dbi.t index c24b5a8c..75444de4 100644 --- a/plugins/t/check_dbi.t +++ b/plugins/t/check_dbi.t @@ -21,12 +21,12 @@ plan tests => $tests; my $missing_driver_output = "failed to open DBI driver 'sqlite3'"; my $bad_driver_output = "/failed to open DBI driver 'nodriver'/"; -my $conn_time_output = "/OK - connection time: [0-9\.]+s \|/"; +my $conn_time_output = "/connection time: [0-9\.]+s \|/"; my $missing_query_output = "/Must specify a query to execute/"; -my $no_rows_output = "/WARNING - no rows returned/"; -my $not_numeric_output = "/CRITICAL - result value is not a numeric:/"; -my $query_time_output = "/OK - connection time: [0-9\.]+s, 'SELECT 1' returned 1.000000 in [0-9\.]+s \|/"; -my $syntax_error_output = "/CRITICAL - failed to execute query 'GET ALL FROM test': 1: near \"GET\": syntax error/"; +my $no_rows_output = "/no rows returned/"; +my $not_numeric_output = "/result value is not a numeric:/"; +my $query_time_output = "/connection time: [0-9\.]+s, 'SELECT 1' returned 1.000000 in [0-9\.]+s \|/"; +my $syntax_error_output = "/1: near \"GET\": syntax error/"; my $result; -- cgit v1.2.3-74-g34f1 From 0fb65a3a90e778f942a1f61f210a2dd969dd9597 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:31:27 +0100 Subject: check_mysql: implement modern output --- plugins/check_mysql.c | 270 ++++++++++++++++++++++++++--------------- plugins/check_mysql.d/config.h | 8 +- plugins/t/check_mysql.t | 7 +- 3 files changed, 175 insertions(+), 110 deletions(-) (limited to 'plugins/t') diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c index 7f2da5ac..9d8094c0 100644 --- a/plugins/check_mysql.c +++ b/plugins/check_mysql.c @@ -30,13 +30,11 @@ * *****************************************************************************/ -const char *progname = "check_mysql"; -const char *copyright = "1999-2024"; -const char *email = "devel@monitoring-plugins.org"; - -#define REPLICA_RESULTSIZE 96 - #include "common.h" +#include "output.h" +#include "perfdata.h" +#include "states.h" +#include "thresholds.h" #include "utils.h" #include "utils_base.h" #include "netutils.h" @@ -46,8 +44,14 @@ const char *email = "devel@monitoring-plugins.org"; #include #include +const char *progname = "check_mysql"; +const char *copyright = "1999-2024"; +const char *email = "devel@monitoring-plugins.org"; + static int verbose = 0; +#define REPLICA_RESULTSIZE 96 + #define LENGTH_METRIC_UNIT 6 static const char *metric_unit[LENGTH_METRIC_UNIT] = { "Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache", @@ -110,7 +114,11 @@ int main(int argc, char **argv) { mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, config.ciphers); } - /* establish a connection to the server and error checking */ + + mp_check overall = mp_check_init(); + + mp_subcheck sc_connection = mp_subcheck_init(); + /* establish a connection to the server and check for errors */ if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) { /* Depending on internally-selected auth plugin MySQL might return */ @@ -118,78 +126,115 @@ int main(int argc, char **argv) { /* Semantically these errors are the same. */ if (config.ignore_auth && (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) { - printf("MySQL OK - Version: %s (protocol %d)\n", mysql_get_server_info(&mysql), - mysql_get_proto_info(&mysql)); - mysql_close(&mysql); - return STATE_OK; - } + xasprintf(&sc_connection.output, "Version: %s (protocol %d)", + mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql)); + sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK); - if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { - die(STATE_WARNING, "%s\n", mysql_error(&mysql)); - } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) { - die(STATE_WARNING, "%s\n", mysql_error(&mysql)); - } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) { - die(STATE_WARNING, "%s\n", mysql_error(&mysql)); - } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) { - die(STATE_WARNING, "%s\n", mysql_error(&mysql)); - } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) { - die(STATE_WARNING, "%s\n", mysql_error(&mysql)); + mysql_close(&mysql); } else { - die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); + if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { + sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); + xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); + } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) { + sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); + xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); + } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) { + sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); + xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); + } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) { + sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); + xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); + } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) { + sc_connection = mp_set_subcheck_state(sc_connection, STATE_WARNING); + xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); + } else { + sc_connection = mp_set_subcheck_state(sc_connection, STATE_CRITICAL); + xasprintf(&sc_connection.output, "%s", mysql_error(&mysql)); + } } + + mp_add_subcheck_to_check(&overall, sc_connection); + mp_exit(overall); + } else { + // successful connection + sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK); + xasprintf(&sc_connection.output, "Version: %s (protocol %d)", mysql_get_server_info(&mysql), + mysql_get_proto_info(&mysql)); + mp_add_subcheck_to_check(&overall, sc_connection); } /* get the server stats */ - char *result = strdup(mysql_stat(&mysql)); + char *mysql_stats = strdup(mysql_stat(&mysql)); + + mp_subcheck sc_stats = mp_subcheck_init(); + sc_stats = mp_set_subcheck_default_state(sc_stats, STATE_OK); /* error checking once more */ - if (mysql_error(&mysql)) { - if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) { - die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); - } else if (mysql_errno(&mysql) == CR_SERVER_LOST) { - die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); - } else if (mysql_errno(&mysql) == CR_UNKNOWN_ERROR) { - die(STATE_CRITICAL, "%s\n", mysql_error(&mysql)); + if (mysql_errno(&mysql) != 0) { + if ((mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) || + (mysql_errno(&mysql) == CR_SERVER_LOST) || (mysql_errno(&mysql) == CR_UNKNOWN_ERROR)) { + sc_stats = mp_set_subcheck_state(sc_stats, STATE_CRITICAL); + xasprintf(&sc_stats.output, "Retrieving stats failed: %s", mysql_error(&mysql)); + } else { + // not sure which error modes occur here, but mysql_error indicates an error + sc_stats = mp_set_subcheck_state(sc_stats, STATE_WARNING); + xasprintf(&sc_stats.output, "retrieving stats caused an error: %s", + mysql_error(&mysql)); } + + mp_add_subcheck_to_check(&overall, sc_stats); + mp_exit(overall); + } else { + xasprintf(&sc_stats.output, "retrieved stats: %s", mysql_stats); + sc_stats = mp_set_subcheck_state(sc_stats, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_stats); } - char *perf = strdup(""); - char *error = NULL; MYSQL_RES *res; MYSQL_ROW row; + mp_subcheck sc_query = mp_subcheck_init(); /* try to fetch some perf data */ if (mysql_query(&mysql, "show global status") == 0) { if ((res = mysql_store_result(&mysql)) == NULL) { - error = strdup(mysql_error(&mysql)); + xasprintf(&sc_connection.output, "query failed - status store_result error: %s", + mysql_error(&mysql)); mysql_close(&mysql); - die(STATE_CRITICAL, _("status store_result error: %s\n"), error); + + sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_query); + mp_exit(overall); } while ((row = mysql_fetch_row(res)) != NULL) { for (int i = 0; i < LENGTH_METRIC_UNIT; i++) { if (strcmp(row[0], metric_unit[i]) == 0) { - xasprintf(&perf, "%s%s ", perf, - perfdata(metric_unit[i], atol(row[1]), "", false, 0, false, 0, false, - 0, false, 0)); + mp_perfdata pd_mysql_stat = perfdata_init(); + pd_mysql_stat.label = (char *)metric_unit[i]; + pd_mysql_stat.value = mp_create_pd_value(atol(row[1])); + mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat); continue; } } + for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) { if (strcmp(row[0], metric_counter[i]) == 0) { - xasprintf(&perf, "%s%s ", perf, - perfdata(metric_counter[i], atol(row[1]), "c", false, 0, false, 0, - false, 0, false, 0)); + mp_perfdata pd_mysql_stat = perfdata_init(); + pd_mysql_stat.label = (char *)metric_counter[i]; + pd_mysql_stat.value = mp_create_pd_value(atol(row[1])); + pd_mysql_stat.uom = "c"; + mp_add_perfdata_to_subcheck(&sc_stats, pd_mysql_stat); continue; } } } - /* remove trailing space */ - if (strlen(perf) > 0) { - perf[strlen(perf) - 1] = '\0'; - } + } else { + // Query failed! + xasprintf(&sc_connection.output, "query failed"); + sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_query); + mp_exit(overall); } - char replica_result[REPLICA_RESULTSIZE] = {0}; if (config.check_replica) { // Detect which version we are, on older version // "show slave status" should work, on newer ones @@ -203,8 +248,10 @@ int main(int argc, char **argv) { unsigned long major_version = server_verion_int / 10000; unsigned long minor_version = (server_verion_int % 10000) / 100; unsigned long patch_version = (server_verion_int % 100); + if (verbose) { - printf("Found MariaDB: %s, main version: %lu, minor version: %lu, patch version: %lu\n", + printf("Found MariaDB/MySQL: %s, main version: %lu, minor version: %lu, patch version: " + "%lu\n", server_version, major_version, minor_version, patch_version); } @@ -235,43 +282,60 @@ int main(int argc, char **argv) { replica_query = "show replica status"; } + mp_subcheck sc_replica = mp_subcheck_init(); + /* check the replica status */ if (mysql_query(&mysql, replica_query) != 0) { - error = strdup(mysql_error(&mysql)); + xasprintf(&sc_replica.output, "replica query error: %s", mysql_error(&mysql)); mysql_close(&mysql); - die(STATE_CRITICAL, _("replica query error: %s\n"), error); + + sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_replica); + mp_exit(overall); } /* store the result */ if ((res = mysql_store_result(&mysql)) == NULL) { - error = strdup(mysql_error(&mysql)); + xasprintf(&sc_replica.output, "replica store_result error: %s", mysql_error(&mysql)); mysql_close(&mysql); - die(STATE_CRITICAL, _("replica store_result error: %s\n"), error); + + sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_replica); + mp_exit(overall); } /* Check there is some data */ if (mysql_num_rows(res) == 0) { mysql_close(&mysql); - die(STATE_WARNING, "%s\n", _("No replicas defined")); + + xasprintf(&sc_replica.output, "no replicas defined"); + sc_replica = mp_set_subcheck_state(sc_replica, STATE_WARNING); + mp_add_subcheck_to_check(&overall, sc_replica); + mp_exit(overall); } /* fetch the first row */ if ((row = mysql_fetch_row(res)) == NULL) { - error = strdup(mysql_error(&mysql)); + xasprintf(&sc_replica.output, "replica fetch row error: %s", mysql_error(&mysql)); mysql_free_result(res); mysql_close(&mysql); - die(STATE_CRITICAL, _("replica fetch row error: %s\n"), error); + + sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_replica); + mp_exit(overall); } if (mysql_field_count(&mysql) == 12) { /* mysql 3.23.x */ - snprintf(replica_result, REPLICA_RESULTSIZE, _("Replica running: %s"), row[6]); + xasprintf(&sc_replica.output, "Replica running: %s", row[6]); if (strcmp(row[6], "Yes") != 0) { mysql_free_result(res); mysql_close(&mysql); - die(STATE_CRITICAL, "%s\n", replica_result); - } + sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_replica); + mp_exit(overall); + } } else { /* mysql 4.x.x and mysql 5.x.x */ int replica_io_field = -1; @@ -315,14 +379,18 @@ int main(int argc, char **argv) { if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) { mysql_free_result(res); mysql_close(&mysql); - die(STATE_CRITICAL, "Replica status unavailable\n"); + + xasprintf(&sc_replica.output, "Replica status unavailable"); + sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_replica); + mp_exit(overall); } /* Save replica status in replica_result */ - snprintf(replica_result, REPLICA_RESULTSIZE, - "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s", - row[replica_io_field], row[replica_sql_field], - seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown"); + xasprintf(&sc_replica.output, + "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s", + row[replica_io_field], row[replica_sql_field], + seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown"); /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no * mysqldump threads running */ @@ -345,10 +413,14 @@ int main(int argc, char **argv) { } mysql_close(&mysql); } + if (mysqldump_threads == 0) { - die(STATE_CRITICAL, "%s\n", replica_result); + sc_replica = mp_set_subcheck_state(sc_replica, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_replica); + mp_exit(overall); } else { - strncat(replica_result, " Mysqldump: in progress", REPLICA_RESULTSIZE - 1); + xasprintf(&sc_replica.output, "%s %s", sc_replica.output, + " Mysqldump: in progress"); } } @@ -364,22 +436,22 @@ int main(int argc, char **argv) { /* Check Seconds Behind against threshold */ if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp(row[seconds_behind_field], "NULL") != 0)) { - double value = atof(row[seconds_behind_field]); - int status; - - status = get_status(value, config.my_threshold); - - xasprintf(&perf, "%s %s", perf, - fperfdata("seconds behind master", value, "s", true, - (double)config.warning_time, true, (double)config.critical_time, - false, 0, false, 0)); - - if (status == STATE_WARNING) { - printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf); - exit(STATE_WARNING); - } else if (status == STATE_CRITICAL) { - printf("SLOW_REPLICA %s: %s|%s\n", _("CRITICAL"), replica_result, perf); - exit(STATE_CRITICAL); + mp_perfdata pd_seconds_behind = perfdata_init(); + pd_seconds_behind.label = "seconds behind master"; + pd_seconds_behind.value = mp_create_pd_value(atof(row[seconds_behind_field])); + pd_seconds_behind = + mp_pd_set_thresholds(pd_seconds_behind, config.replica_thresholds); + pd_seconds_behind.uom = "s"; + mp_add_perfdata_to_subcheck(&sc_replica, pd_seconds_behind); + + mp_state_enum status = mp_get_pd_status(pd_seconds_behind); + + sc_replica = mp_set_subcheck_state(sc_replica, status); + + if (status != STATE_OK) { + xasprintf(&sc_replica.output, "slow replica - %s", sc_replica.output); + mp_add_subcheck_to_check(&overall, sc_replica); + mp_exit(overall); } } } @@ -391,14 +463,7 @@ int main(int argc, char **argv) { /* close the connection */ mysql_close(&mysql); - /* print out the result of stats */ - if (config.check_replica) { - printf("%s %s|%s\n", result, replica_result, perf); - } else { - printf("%s|%s\n", result, perf); - } - - return STATE_OK; + mp_exit(overall); } /* process command-line arguments */ @@ -442,9 +507,6 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) { return result; } - char *warning = NULL; - char *critical = NULL; - int option = 0; while (true) { int option_index = @@ -516,14 +578,22 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) { case 'n': result.config.ignore_auth = true; /* ignore-auth */ break; - case 'w': - warning = optarg; - result.config.warning_time = strtod(warning, NULL); - break; - case 'c': - critical = optarg; - result.config.critical_time = strtod(critical, NULL); - break; + case 'w': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse warning time threshold"); + } + result.config.replica_thresholds = + mp_thresholds_set_warn(result.config.replica_thresholds, tmp.range); + } break; + case 'c': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse critical time threshold"); + } + result.config.replica_thresholds = + mp_thresholds_set_crit(result.config.replica_thresholds, tmp.range); + } break; case 'V': /* version */ print_revision(progname, NP_VERSION); exit(STATE_UNKNOWN); @@ -540,8 +610,6 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) { int index = optind; - set_thresholds(&result.config.my_threshold, warning, critical); - while (argc > index) { if (result.config.db_host == NULL) { if (is_host(argv[index])) { diff --git a/plugins/check_mysql.d/config.h b/plugins/check_mysql.d/config.h index 71ddbe8d..ef086cfc 100644 --- a/plugins/check_mysql.d/config.h +++ b/plugins/check_mysql.d/config.h @@ -24,9 +24,7 @@ typedef struct { bool check_replica; bool ignore_auth; - double warning_time; - double critical_time; - thresholds *my_threshold; + mp_thresholds replica_thresholds; } check_mysql_config; @@ -50,9 +48,7 @@ check_mysql_config check_mysql_config_init() { .check_replica = false, .ignore_auth = false, - .warning_time = 0, - .critical_time = 0, - .my_threshold = NULL, + .replica_thresholds = mp_thresholds_init(), }; return tmp; } diff --git a/plugins/t/check_mysql.t b/plugins/t/check_mysql.t index a383bc99..9114cccc 100644 --- a/plugins/t/check_mysql.t +++ b/plugins/t/check_mysql.t @@ -11,6 +11,7 @@ # mysql -u$user -p$password -h$host $db use strict; +use warnings; use Test::More; use NPTest; @@ -40,7 +41,7 @@ SKIP: { $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details"); cmp_ok( $result->return_code, "==", 1, "No replicas defined" ); - like( $result->output, "/No replicas defined/", "Correct error message"); + like( $result->output, "/no replicas defined/", "Correct error message"); } SKIP: { @@ -54,7 +55,7 @@ SKIP: { $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details"); cmp_ok( $result->return_code, "==", 1, "No replicas defined" ); - like( $result->output, "/No replicas defined/", "Correct error message"); + like( $result->output, "/no replicas defined/", "Correct error message"); } SKIP: { @@ -70,5 +71,5 @@ SKIP: { $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60:"); cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind'); - like( $result->output, "/^SLOW_REPLICA WARNING:/", "Output okay"); + like( $result->output, "/^slow_replica/", "Output okay"); } -- cgit v1.2.3-74-g34f1 From 9d827acbe1aac0edaa91a8765a87412a189cadf1 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:01:36 +0100 Subject: check_mysql_query: implement modern output --- plugins/check_mysql_query.c | 105 +++++++++++++++++++++-------------- plugins/check_mysql_query.d/config.h | 4 +- plugins/t/check_mysql_query.t | 2 +- 3 files changed, 65 insertions(+), 46 deletions(-) (limited to 'plugins/t') diff --git a/plugins/check_mysql_query.c b/plugins/check_mysql_query.c index c7e84deb..cb79b4b4 100644 --- a/plugins/check_mysql_query.c +++ b/plugins/check_mysql_query.c @@ -29,11 +29,11 @@ * *****************************************************************************/ -const char *progname = "check_mysql_query"; -const char *copyright = "1999-2024"; -const char *email = "devel@monitoring-plugins.org"; - #include "common.h" +#include "output.h" +#include "perfdata.h" +#include "states.h" +#include "thresholds.h" #include "utils.h" #include "utils_base.h" #include "netutils.h" @@ -42,6 +42,10 @@ const char *email = "devel@monitoring-plugins.org"; #include #include +const char *progname = "check_mysql_query"; +const char *copyright = "1999-2024"; +const char *email = "devel@monitoring-plugins.org"; + typedef struct { int errorcode; check_mysql_query_config config; @@ -83,27 +87,38 @@ int main(int argc, char **argv) { mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client"); } + mp_check overall = mp_check_init(); + mp_subcheck sc_connect = mp_subcheck_init(); + /* establish a connection to the server and error checking */ if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) { + xasprintf(&sc_connect.output, "query failed: %s", mysql_error(&mysql)); + if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) { - die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); + sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) { - die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); + sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) { - die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); + sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) { - die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); + sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) { - die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); + sc_connect = mp_set_subcheck_state(sc_connect, STATE_WARNING); } else { - die(STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error(&mysql)); + sc_connect = mp_set_subcheck_state(sc_connect, STATE_CRITICAL); } + + mp_add_subcheck_to_check(&overall, sc_connect); + mp_exit(overall); } - char *error = NULL; + sc_connect = mp_set_subcheck_state(sc_connect, STATE_OK); + xasprintf(&sc_connect.output, "query succeeded"); + mp_add_subcheck_to_check(&overall, sc_connect); + if (mysql_query(&mysql, config.sql_query) != 0) { - error = strdup(mysql_error(&mysql)); + char *error = strdup(mysql_error(&mysql)); mysql_close(&mysql); die(STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error); } @@ -111,7 +126,7 @@ int main(int argc, char **argv) { MYSQL_RES *res; /* store the result */ if ((res = mysql_store_result(&mysql)) == NULL) { - error = strdup(mysql_error(&mysql)); + char *error = strdup(mysql_error(&mysql)); mysql_close(&mysql); die(STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error); } @@ -122,17 +137,24 @@ int main(int argc, char **argv) { die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned")); } + mp_subcheck sc_value = mp_subcheck_init(); MYSQL_ROW row; /* fetch the first row */ if ((row = mysql_fetch_row(res)) == NULL) { - error = strdup(mysql_error(&mysql)); + xasprintf(&sc_value.output, "fetch row error - %s", mysql_error(&mysql)); mysql_free_result(res); mysql_close(&mysql); - die(STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error); + + sc_value = mp_set_subcheck_state(sc_value, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_value); + mp_exit(overall); } if (!is_numeric(row[0])) { - die(STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]); + xasprintf(&sc_value.output, "query result is not numeric"); + sc_value = mp_set_subcheck_state(sc_value, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_value); + mp_exit(overall); } double value = strtod(row[0], NULL); @@ -147,24 +169,18 @@ int main(int argc, char **argv) { printf("mysql result: %f\n", value); } - int status = get_status(value, config.my_thresholds); + mp_perfdata pd_query_result = perfdata_init(); + pd_query_result = mp_set_pd_value(pd_query_result, value); + pd_query_result = mp_pd_set_thresholds(pd_query_result, config.thresholds); + pd_query_result.label = "result"; + mp_add_perfdata_to_subcheck(&sc_value, pd_query_result); - if (status == STATE_OK) { - printf("QUERY %s: ", _("OK")); - } else if (status == STATE_WARNING) { - printf("QUERY %s: ", _("WARNING")); - } else if (status == STATE_CRITICAL) { - printf("QUERY %s: ", _("CRITICAL")); - } - printf(_("'%s' returned %f | %s"), config.sql_query, value, - fperfdata("result", value, "", config.my_thresholds->warning, - config.my_thresholds->warning ? config.my_thresholds->warning->end : 0, - config.my_thresholds->critical, - config.my_thresholds->critical ? config.my_thresholds->critical->end : 0, - false, 0, false, 0)); - printf("\n"); + sc_value = mp_set_subcheck_state(sc_value, mp_get_pd_status(pd_query_result)); + xasprintf(&sc_value.output, "'%s' returned '%f'", config.sql_query, value); + + mp_add_subcheck_to_check(&overall, sc_value); - return status; + mp_exit(overall); } /* process command-line arguments */ @@ -195,9 +211,6 @@ check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { return result; } - char *warning = NULL; - char *critical = NULL; - while (true) { int option = 0; int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option); @@ -253,19 +266,25 @@ check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { case 'q': xasprintf(&result.config.sql_query, "%s", optarg); break; - case 'w': - warning = optarg; - break; - case 'c': - critical = optarg; - break; + case 'w': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse warnign threshold"); + } + result.config.thresholds = mp_thresholds_set_warn(result.config.thresholds, tmp.range); + } break; + case 'c': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse critical threshold"); + } + result.config.thresholds = mp_thresholds_set_crit(result.config.thresholds, tmp.range); + } break; case '?': /* help */ usage5(); } } - set_thresholds(&result.config.my_thresholds, warning, critical); - return validate_arguments(result); } diff --git a/plugins/check_mysql_query.d/config.h b/plugins/check_mysql_query.d/config.h index be019160..1c9952e5 100644 --- a/plugins/check_mysql_query.d/config.h +++ b/plugins/check_mysql_query.d/config.h @@ -15,7 +15,7 @@ typedef struct { unsigned int db_port; char *sql_query; - thresholds *my_thresholds; + mp_thresholds thresholds; } check_mysql_query_config; check_mysql_query_config check_mysql_query_config_init() { @@ -30,7 +30,7 @@ check_mysql_query_config check_mysql_query_config_init() { .db_port = MYSQL_PORT, .sql_query = NULL, - .my_thresholds = NULL, + .thresholds = mp_thresholds_init(), }; return tmp; } diff --git a/plugins/t/check_mysql_query.t b/plugins/t/check_mysql_query.t index c30245b2..6de48bf6 100644 --- a/plugins/t/check_mysql_query.t +++ b/plugins/t/check_mysql_query.t @@ -54,5 +54,5 @@ like( $result->output, "/No rows returned/", "No rows error message"); $result = NPTest->testCmd("./check_mysql_query -q 'SHOW VARIABLES' -H $mysqlserver $mysql_login_details"); cmp_ok( $result->return_code, '==', 2, "Data not numeric"); -like( $result->output, "/Is not a numeric/", "Data not numeric error message"); +like( $result->output, "/is not numeric/", "Data not numeric error message"); -- cgit v1.2.3-74-g34f1 From e0b127312797cd4619886dc6df57411a77fe2d33 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sat, 8 Nov 2025 00:46:37 +0100 Subject: check_smtp: adapt tests --- plugins/t/check_smtp.t | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t index 73b4a1fd..6c8601d3 100644 --- a/plugins/t/check_smtp.t +++ b/plugins/t/check_smtp.t @@ -5,6 +5,7 @@ # use strict; +use warnings; use Test::More; use NPTest; @@ -42,12 +43,11 @@ SKIP: { TODO: { local $TODO = "Output is over two lines"; - like ( $res->output, qr/^SMTP WARNING/, "Correct error message" ); } $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" ); is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" ); - like ($res->output, qr/^CRITICAL - Cannot make SSL connection\./, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port"); + like ($res->output, qr/^cannot create TLS context\./, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port"); } SKIP: { @@ -68,7 +68,6 @@ SKIP: { skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls; $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls --ssl" ); is ($res->return_code, 0, "Check rc of connecting to $host_tcp_smtp_tls with TLS" ); - like ($res->output, qr/^SMTP OK - /, "Check output of connecting to $host_tcp_smtp_tls with TLS" ); my $unused_port = 4465; $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" ); -- cgit v1.2.3-74-g34f1 From 4442ea917b9b3a7bc4fe4b980bbfc70b533a6010 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sat, 8 Nov 2025 01:15:54 +0100 Subject: small test correction --- plugins/t/check_smtp.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t index 6c8601d3..c2f53c3d 100644 --- a/plugins/t/check_smtp.t +++ b/plugins/t/check_smtp.t @@ -25,7 +25,7 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost" ); my $res; -plan tests => 15; +plan tests => 13; SKIP: { skip "No SMTP server defined", 4 unless $host_tcp_smtp; @@ -47,7 +47,7 @@ SKIP: { $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" ); is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" ); - like ($res->output, qr/^cannot create TLS context\./, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port"); + like ($res->output, qr/cannot create TLS context/, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port"); } SKIP: { -- cgit v1.2.3-74-g34f1 From 584272e97d5c72ad6a7fb9b91844592252040ed9 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 16 Nov 2025 15:28:19 +0100 Subject: check_by_ssh: fix some tests --- plugins/t/check_by_ssh.t | 50 ++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'plugins/t') diff --git a/plugins/t/check_by_ssh.t b/plugins/t/check_by_ssh.t index b6479f1f..0ee310cd 100644 --- a/plugins/t/check_by_ssh.t +++ b/plugins/t/check_by_ssh.t @@ -16,7 +16,7 @@ my $ssh_conf = getTestParameter( "NP_SSH_CONFIGFILE", "A config file with ssh plan skip_all => "SSH_HOST and SSH_IDENTITY must be defined" unless ($ssh_service && $ssh_key); -plan tests => 42; +plan tests => 33; # Some random check strings/response my @response = ('OK: Everything is fine', @@ -47,70 +47,70 @@ for (my $i=0; $i<4; $i++) { "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[$i]; exit $i'" ); cmp_ok($result->return_code, '==', $i, "Exit with return code $i"); - is($result->output, $response[$i], "Status text is correct for check $i"); + like($result->output, "/$response[$i]/", "Status text is correct for check $i"); } $result = NPTest->testCmd( "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 0'" ); cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); -is($result->output, 'OK - check_by_ssh: Remote command \'exit 0\' returned status 0', "Status text if command returned none (OK)"); +like($result->output, '/command \'exit 0\' returned status 0/', "Status text if command returned none (OK)"); $result = NPTest->testCmd( "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 1'" ); cmp_ok($result->return_code, '==', 1, "Exit with return code 1 (WARNING)"); -is($result->output, 'WARNING - check_by_ssh: Remote command \'exit 1\' returned status 1', "Status text if command returned none (WARNING)"); +like($result->output, '/command \'exit 1\' returned status 1/', "Status text if command returned none (WARNING)"); $result = NPTest->testCmd( "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 2'" ); cmp_ok($result->return_code, '==', 2, "Exit with return code 2 (CRITICAL)"); -is($result->output, 'CRITICAL - check_by_ssh: Remote command \'exit 2\' returned status 2', "Status text if command returned none (CRITICAL)"); +like($result->output, '/command \'exit 2\' returned status 2/', "Status text if command returned none (CRITICAL)"); $result = NPTest->testCmd( "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 3'" ); cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)"); -is($result->output, 'UNKNOWN - check_by_ssh: Remote command \'exit 3\' returned status 3', "Status text if command returned none (UNKNOWN)"); +like($result->output, '/command \'exit 3\' returned status 3/', "Status text if command returned none (UNKNOWN)"); $result = NPTest->testCmd( "./check_by_ssh -i $ssh_key -H $ssh_service -C 'exit 7'" ); -cmp_ok($result->return_code, '==', 7, "Exit with return code 7 (out of bounds)"); -is($result->output, 'UNKNOWN - check_by_ssh: Remote command \'exit 7\' returned status 7', "Status text if command returned none (out of bounds)"); +cmp_ok($result->return_code, '==', 3, "Exit with return code 3"); +like($result->output, '/command \'exit 7\' returned status 7/', "Status text if command returned none (out of bounds)"); $result = NPTest->testCmd( "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[4]; exit 8'" ); -cmp_ok($result->return_code, '==', 8, "Exit with return code 8 (out of bounds)"); -is($result->output, $response[4], "Return proper status text even with unknown status codes"); +cmp_ok($result->return_code, '==', 3, "Exit with return code 3"); +like($result->output, "/$response[4]/", "Return proper status text even with unknown status codes"); $result = NPTest->testCmd( "./check_by_ssh -i $ssh_key -H $ssh_service -F $ssh_conf -C 'exit 0'" ); cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); -is($result->output, 'OK - check_by_ssh: Remote command \'exit 0\' returned status 0', "Status text if command returned none (OK)"); +like($result->output, '/command \'exit 0\' returned status 0/', "Status text if command returned none (OK)"); # Multiple active checks $result = NPTest->testCmd( "./check_by_ssh -i $ssh_key -H $ssh_service -C '$check[1]; sh -c exit\\ 1' -C '$check[0]; sh -c exit\\ 0' -C '$check[3]; sh -c exit\\ 3' -C '$check[2]; sh -c exit\\ 2'" ); cmp_ok($result->return_code, '==', 0, "Multiple checks always return OK"); -my @lines = split(/\n/, $result->output); -cmp_ok(scalar(@lines), '==', 8, "Correct number of output lines for multiple checks"); -my %linemap = ( - '0' => '1', - '2' => '0', - '4' => '3', - '6' => '2', -); -foreach my $line (0, 2, 4, 6) { - my $code = $linemap{$line}; - my $statline = $line+1; - is($lines[$line], "$response[$code]", "multiple checks status text is correct for line $line"); - is($lines[$statline], "STATUS CODE: $code", "multiple check status code is correct for line $line"); -} +# my @lines = split(/\n/, $result->output); +# cmp_ok(scalar(@lines), '==', 8, "Correct number of output lines for multiple checks"); +# my %linemap = ( +# '0' => '1', +# '2' => '0', +# '4' => '3', +# '6' => '2', +# ); +# foreach my $line (0, 2, 4, 6) { + # my $code = $linemap{$line}; + # my $statline = $line+1; + # is($lines[$line], "$response[$code]", "multiple checks status text is correct for line $line"); + # is($lines[$statline], "STATUS CODE: $code", "multiple check status code is correct for line $line"); +# } # Passive checks unlink("/tmp/check_by_ssh.$$"); -- cgit v1.2.3-74-g34f1 From 07d3eb9e2c729b6ab5effc0f664b6d5d9958fa72 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 25 Nov 2025 12:31:00 +0100 Subject: check_ldap: modern output implementation --- plugins/check_ldap.c | 310 ++++++++++++++++++++++++++---------------- plugins/check_ldap.d/config.h | 18 +-- plugins/t/check_ldap.t | 14 +- 3 files changed, 207 insertions(+), 135 deletions(-) (limited to 'plugins/t') diff --git a/plugins/check_ldap.c b/plugins/check_ldap.c index 77a33304..f1380be4 100644 --- a/plugins/check_ldap.c +++ b/plugins/check_ldap.c @@ -27,12 +27,11 @@ *****************************************************************************/ /* progname may be check_ldaps */ -char *progname = "check_ldap"; -const char *copyright = "2000-2024"; -const char *email = "devel@monitoring-plugins.org"; - +#include "output.h" #include "common.h" #include "netutils.h" +#include "perfdata.h" +#include "thresholds.h" #include "utils.h" #include "check_ldap.d/config.h" @@ -41,6 +40,10 @@ const char *email = "devel@monitoring-plugins.org"; #define LDAP_DEPRECATED 1 #include +char *progname = "check_ldap"; +const char *copyright = "2000-2024"; +const char *email = "devel@monitoring-plugins.org"; + enum { DEFAULT_PORT = 389 }; @@ -89,101 +92,172 @@ int main(int argc, char *argv[]) { struct timeval start_time; gettimeofday(&start_time, NULL); + mp_check overall = mp_check_init(); + LDAP *ldap_connection; /* initialize ldap */ + { #ifdef HAVE_LDAP_INIT - if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) { - printf("Could not connect to the server at port %i\n", config.ld_port); - return STATE_CRITICAL; - } + mp_subcheck sc_ldap_init = mp_subcheck_init(); + if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) { + xasprintf(&sc_ldap_init.output, "could not connect to the server at port %i", + config.ld_port); + sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_ldap_init); + mp_exit(overall); + } else { + xasprintf(&sc_ldap_init.output, "connected to the server at port %i", config.ld_port); + sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_ldap_init); + } #else - if (!(ld = ldap_open(config.ld_host, config.ld_port))) { - if (verbose) { - ldap_perror(ldap_connection, "ldap_open"); + mp_subcheck sc_ldap_init = mp_subcheck_init(); + if (!(ld = ldap_open(config.ld_host, config.ld_port))) { + if (verbose) { + ldap_perror(ldap_connection, "ldap_open"); + } + xasprintf(&sc_ldap_init.output, "Could not connect to the server at port %i"), config.ld_port); + sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_ldap_init); + mp_exit(overall); + } else { + xasprintf(&sc_ldap_init.output, "connected to the server at port %i", config.ld_port); + sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_ldap_init); } - printf(_("Could not connect to the server at port %i\n"), config.ld_port); - return STATE_CRITICAL; - } #endif /* HAVE_LDAP_INIT */ + } #ifdef HAVE_LDAP_SET_OPTION /* set ldap options */ + mp_subcheck sc_ldap_set_opts = mp_subcheck_init(); if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) != LDAP_OPT_SUCCESS) { - printf(_("Could not set protocol version %d\n"), config.ld_protocol); - return STATE_CRITICAL; + xasprintf(&sc_ldap_set_opts.output, "Could not set protocol version %d", + config.ld_protocol); + sc_ldap_set_opts = mp_set_subcheck_state(sc_ldap_set_opts, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_ldap_set_opts); + mp_exit(overall); + } else { + xasprintf(&sc_ldap_set_opts.output, "set protocol version %d", config.ld_protocol); + sc_ldap_set_opts = mp_set_subcheck_state(sc_ldap_set_opts, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_ldap_set_opts); } #endif int version = 3; int tls; - if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) { + { + if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) { #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) - /* ldaps: set option tls */ - tls = LDAP_OPT_X_TLS_HARD; + /* ldaps: set option tls */ + tls = LDAP_OPT_X_TLS_HARD; - if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) { - if (verbose) { - ldap_perror(ldap_connection, "ldaps_option"); + mp_subcheck sc_ldap_tls_init = mp_subcheck_init(); + if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) { + if (verbose) { + ldap_perror(ldap_connection, "ldaps_option"); + } + xasprintf(&sc_ldap_tls_init.output, "could not init TLS at port %i!", + config.ld_port); + sc_ldap_tls_init = mp_set_subcheck_state(sc_ldap_tls_init, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_ldap_tls_init); + mp_exit(overall); + } else { + xasprintf(&sc_ldap_tls_init.output, "initiated TLS at port %i!", config.ld_port); + sc_ldap_tls_init = mp_set_subcheck_state(sc_ldap_tls_init, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_ldap_tls_init); } - printf(_("Could not init TLS at port %i!\n"), config.ld_port); - return STATE_CRITICAL; - } #else - printf(_("TLS not supported by the libraries!\n")); - return STATE_CRITICAL; + printf(_("TLS not supported by the libraries!\n")); + exit(STATE_CRITICAL); #endif /* LDAP_OPT_X_TLS */ - } else if (config.starttls) { + } else if (config.starttls) { #if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S) - /* ldap with startTLS: set option version */ - if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == - LDAP_OPT_SUCCESS) { - if (version < LDAP_VERSION3) { - version = LDAP_VERSION3; - ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version); + /* ldap with startTLS: set option version */ + if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == + LDAP_OPT_SUCCESS) { + if (version < LDAP_VERSION3) { + version = LDAP_VERSION3; + ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version); + } } - } - /* call start_tls */ - if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) { - if (verbose) { - ldap_perror(ldap_connection, "ldap_start_tls"); + /* call start_tls */ + mp_subcheck sc_ldap_starttls = mp_subcheck_init(); + if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) { + if (verbose) { + ldap_perror(ldap_connection, "ldap_start_tls"); + } + xasprintf(&sc_ldap_starttls.output, "could not init STARTTLS at port %i!", + config.ld_port); + sc_ldap_starttls = mp_set_subcheck_state(sc_ldap_starttls, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_ldap_starttls); + mp_exit(overall); + } else { + xasprintf(&sc_ldap_starttls.output, "initiated STARTTLS at port %i!", + config.ld_port); + sc_ldap_starttls = mp_set_subcheck_state(sc_ldap_starttls, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_ldap_starttls); } - printf(_("Could not init startTLS at port %i!\n"), config.ld_port); - return STATE_CRITICAL; - } #else - printf(_("startTLS not supported by the library, needs LDAPv3!\n")); - return STATE_CRITICAL; + printf(_("startTLS not supported by the library, needs LDAPv3!\n")); + exit(STATE_CRITICAL); #endif /* HAVE_LDAP_START_TLS_S */ + } } /* bind to the ldap server */ - if (ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE) != - LDAP_SUCCESS) { - if (verbose) { - ldap_perror(ldap_connection, "ldap_bind"); + { + mp_subcheck sc_ldap_bind = mp_subcheck_init(); + int ldap_error = + ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE); + if (ldap_error != LDAP_SUCCESS) { + if (verbose) { + ldap_perror(ldap_connection, "ldap_bind"); + } + + xasprintf(&sc_ldap_bind.output, "could not bind to the LDAP server: %s", + ldap_err2string(ldap_error)); + sc_ldap_bind = mp_set_subcheck_state(sc_ldap_bind, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_ldap_bind); + mp_exit(overall); + } else { + xasprintf(&sc_ldap_bind.output, "execute bind to the LDAP server"); + sc_ldap_bind = mp_set_subcheck_state(sc_ldap_bind, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_ldap_bind); } - printf(_("Could not bind to the LDAP server\n")); - return STATE_CRITICAL; } LDAPMessage *result; - int num_entries = 0; /* do a search of all objectclasses in the base dn */ - if (ldap_search_s(ldap_connection, config.ld_base, - (config.crit_entries != NULL || config.warn_entries != NULL) - ? LDAP_SCOPE_SUBTREE - : LDAP_SCOPE_BASE, - config.ld_attr, NULL, 0, &result) != LDAP_SUCCESS) { - if (verbose) { - ldap_perror(ldap_connection, "ldap_search"); + { + mp_subcheck sc_ldap_search = mp_subcheck_init(); + int ldap_error = ldap_search_s( + ldap_connection, config.ld_base, + (config.entries_thresholds.warning_is_set || config.entries_thresholds.critical_is_set) + ? LDAP_SCOPE_SUBTREE + : LDAP_SCOPE_BASE, + config.ld_attr, NULL, 0, &result); + + if (ldap_error != LDAP_SUCCESS) { + if (verbose) { + ldap_perror(ldap_connection, "ldap_search"); + } + xasprintf(&sc_ldap_search.output, "could not search/find objectclasses in %s: %s", + config.ld_base, ldap_err2string(ldap_error)); + sc_ldap_search = mp_set_subcheck_state(sc_ldap_search, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_ldap_search); + mp_exit(overall); + } else { + xasprintf(&sc_ldap_search.output, "search/find objectclasses in %s", config.ld_base); + sc_ldap_search = mp_set_subcheck_state(sc_ldap_search, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_ldap_search); } - printf(_("Could not search/find objectclasses in %s\n"), config.ld_base); - return STATE_CRITICAL; } - if (config.crit_entries != NULL || config.warn_entries != NULL) { - num_entries = ldap_count_entries(ldap_connection, result); + int num_entries = ldap_count_entries(ldap_connection, result); + if (verbose) { + printf("entries found: %d\n", num_entries); } /* unbind from the ldap server */ @@ -193,46 +267,41 @@ int main(int argc, char *argv[]) { alarm(0); /* calculate the elapsed time and compare to thresholds */ - long microsec = deltime(start_time); double elapsed_time = (double)microsec / 1.0e6; - mp_state_enum status = STATE_UNKNOWN; - if (config.crit_time_set && elapsed_time > config.crit_time) { - status = STATE_CRITICAL; - } else if (config.warn_time_set && elapsed_time > config.warn_time) { - status = STATE_WARNING; - } else { - status = STATE_OK; - } + mp_perfdata pd_connection_time = perfdata_init(); + pd_connection_time.label = "time"; + pd_connection_time.value = mp_create_pd_value(elapsed_time); + pd_connection_time = mp_pd_set_thresholds(pd_connection_time, config.connection_time_threshold); - if (config.entries_thresholds != NULL) { - if (verbose) { - printf("entries found: %d\n", num_entries); - print_thresholds("entry thresholds", config.entries_thresholds); - } - mp_state_enum status_entries = get_status(num_entries, config.entries_thresholds); - if (status_entries == STATE_CRITICAL) { - status = STATE_CRITICAL; - } else if (status != STATE_CRITICAL) { - status = status_entries; - } - } + mp_subcheck sc_connection_time = mp_subcheck_init(); + mp_add_perfdata_to_subcheck(&sc_connection_time, pd_connection_time); + + mp_state_enum connection_time_state = mp_get_pd_status(pd_connection_time); + sc_connection_time = mp_set_subcheck_state(sc_connection_time, connection_time_state); - /* print out the result */ - if (config.crit_entries != NULL || config.warn_entries != NULL) { - printf(_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), state_text(status), - num_entries, elapsed_time, - fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, - config.crit_time_set, config.crit_time, true, 0, false, 0), - sperfdata("entries", (double)num_entries, "", config.warn_entries, - config.crit_entries, true, 0.0, false, 0.0)); + if (connection_time_state == STATE_OK) { + xasprintf(&sc_connection_time.output, "connection time %.3fs is withing thresholds", + elapsed_time); } else { - printf(_("LDAP %s - %.3f seconds response time|%s\n"), state_text(status), elapsed_time, - fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, - config.crit_time_set, config.crit_time, true, 0, false, 0)); + xasprintf(&sc_connection_time.output, "connection time %.3fs is violating thresholds", + elapsed_time); } - exit(status); + mp_add_subcheck_to_check(&overall, sc_connection_time); + + mp_perfdata pd_num_entries = perfdata_init(); + pd_num_entries.label = "entries"; + pd_num_entries.value = mp_create_pd_value(num_entries); + pd_num_entries = mp_pd_set_thresholds(pd_num_entries, config.entries_thresholds); + + mp_subcheck sc_num_entries = mp_subcheck_init(); + xasprintf(&sc_num_entries.output, "found %d entries", num_entries); + sc_num_entries = mp_set_subcheck_state(sc_num_entries, mp_get_pd_status(pd_num_entries)); + + mp_add_subcheck_to_check(&overall, sc_num_entries); + + mp_exit(overall); } /* process command-line arguments */ @@ -319,20 +388,38 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) { case 'P': result.config.ld_passwd = optarg; break; - case 'w': - result.config.warn_time_set = true; - result.config.warn_time = strtod(optarg, NULL); - break; - case 'c': - result.config.crit_time_set = true; - result.config.crit_time = strtod(optarg, NULL); - break; - case 'W': - result.config.warn_entries = optarg; - break; - case 'C': - result.config.crit_entries = optarg; - break; + case 'w': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse warning connection time threshold"); + } + result.config.connection_time_threshold = + mp_thresholds_set_warn(result.config.connection_time_threshold, tmp.range); + } break; + case 'c': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse critical connection time threshold"); + } + result.config.connection_time_threshold = + mp_thresholds_set_crit(result.config.connection_time_threshold, tmp.range); + } break; + case 'W': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse number of entries warning threshold"); + } + result.config.connection_time_threshold = + mp_thresholds_set_warn(result.config.entries_thresholds, tmp.range); + } break; + case 'C': { + mp_range_parsed tmp = mp_parse_range_string(optarg); + if (tmp.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse number of entries critical threshold"); + } + result.config.connection_time_threshold = + mp_thresholds_set_crit(result.config.entries_thresholds, tmp.range); + } break; #ifdef HAVE_LDAP_SET_OPTION case '2': result.config.ld_protocol = 2; @@ -406,11 +493,6 @@ check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper config_wr usage4(_("Please specify the LDAP base\n")); } - if (config_wrapper.config.crit_entries != NULL || config_wrapper.config.warn_entries != NULL) { - set_thresholds(&config_wrapper.config.entries_thresholds, - config_wrapper.config.warn_entries, config_wrapper.config.crit_entries); - } - if (config_wrapper.config.ld_passwd == NULL) { config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD"); } diff --git a/plugins/check_ldap.d/config.h b/plugins/check_ldap.d/config.h index c8a40610..9e6bb845 100644 --- a/plugins/check_ldap.d/config.h +++ b/plugins/check_ldap.d/config.h @@ -25,13 +25,8 @@ typedef struct { int ld_protocol; #endif - char *warn_entries; - char *crit_entries; - thresholds *entries_thresholds; - bool warn_time_set; - double warn_time; - bool crit_time_set; - double crit_time; + mp_thresholds entries_thresholds; + mp_thresholds connection_time_threshold; } check_ldap_config; check_ldap_config check_ldap_config_init() { @@ -48,13 +43,8 @@ check_ldap_config check_ldap_config_init() { .ld_protocol = DEFAULT_PROTOCOL, #endif - .warn_entries = NULL, - .crit_entries = NULL, - .entries_thresholds = NULL, - .warn_time_set = false, - .warn_time = 0, - .crit_time_set = false, - .crit_time = 0, + .entries_thresholds = mp_thresholds_init(), + .connection_time_threshold = mp_thresholds_init(), }; return tmp; } diff --git a/plugins/t/check_ldap.t b/plugins/t/check_ldap.t index fcba0393..f3162ebb 100644 --- a/plugins/t/check_ldap.t +++ b/plugins/t/check_ldap.t @@ -32,7 +32,7 @@ SKIP: { $result = NPTest->testCmd("$command -H $hostname_invalid -b ou=blah -t 5"); is( $result->return_code, 2, "$command -H $hostname_invalid -b ou=blah -t 5" ); - is( $result->output, 'Could not bind to the LDAP server', "output ok" ); + like( $result->output, '/could not bind to the LDAP server/', "output ok" ); }; SKIP: { @@ -42,30 +42,30 @@ SKIP: { $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3"; $result = NPTest->testCmd($cmd); is( $result->return_code, 0, $cmd ); - like( $result->output, '/^LDAP OK - \d+.\d+ seconds response time\|time=\d+\.\d+s;2\.0+;3\.0+;0\.0+$/', "output ok" ); + like( $result->output, '/connection time \d+.\d+s/', "output ok" ); $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000 -C 10000001"; $result = NPTest->testCmd($cmd); is( $result->return_code, 0, $cmd ); - like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000;10000001;0\.0+$/', "output ok" ); + like( $result->output, '/found \d+ entries/', "output ok" ); $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001:"; $result = NPTest->testCmd($cmd); is( $result->return_code, 2, $cmd ); - like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001:;0\.0+$/', "output ok" ); + like( $result->output, '/found \d+ entries/', "output ok" ); $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 0 -C 0"; $result = NPTest->testCmd($cmd); is( $result->return_code, 2, $cmd ); - like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;0;0;0\.0+$/', "output ok" ); + like( $result->output, '/found \d+ entries/', "output ok" ); $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001"; $result = NPTest->testCmd($cmd); is( $result->return_code, 1, $cmd ); - like( $result->output, '/^LDAP WARNING - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001;0\.0+$/', "output ok" ); + like( $result->output, '/found \d+ entries/', "output ok" ); $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -C 10000001"; $result = NPTest->testCmd($cmd); is( $result->return_code, 0, $cmd ); - like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;;10000001;0\.0+$/', "output ok" ); + like( $result->output, '/found \d+ entries/', "output ok" ); }; -- cgit v1.2.3-74-g34f1 From 2f96b82c9b67ca1aad6cd584a9c458d060bdd4bb Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Fri, 28 Nov 2025 10:52:39 +0100 Subject: check_ntp_time/check_ntp_peer: unix socket handling (#2187) * check_ntp_time/check_ntp_peer: unix socket handling * No tests for check_ntp since it is deprecated --- plugins/check_ntp_peer.c | 2 +- plugins/check_ntp_time.c | 81 +++++++++++++++++++++++++++++++++++------------- plugins/t/check_ntp.t | 2 +- 3 files changed, 61 insertions(+), 24 deletions(-) (limited to 'plugins/t') diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c index f7cad630..26f74286 100644 --- a/plugins/check_ntp_peer.c +++ b/plugins/check_ntp_peer.c @@ -625,7 +625,7 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) { mp_thresholds_set_crit(result.config.truechimer_thresholds, tmp.range); } break; case 'H': - if (!is_host(optarg)) { + if (!is_host(optarg) && (optarg[0] != '/')) { usage2(_("Invalid hostname/address"), optarg); } result.config.server_address = strdup(optarg); diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c index 602b6010..1300faea 100644 --- a/plugins/check_ntp_time.c +++ b/plugins/check_ntp_time.c @@ -42,6 +42,8 @@ #include "states.h" #include "thresholds.h" #include "check_ntp_time.d/config.h" +#include +#include static int verbose = 0; @@ -336,17 +338,26 @@ static offset_request_wrapper offset_request(const char *host, const char *port, hints.ai_protocol = IPPROTO_UDP; hints.ai_socktype = SOCK_DGRAM; - /* fill in ai with the list of hosts resolved by the host name */ + bool is_socket; struct addrinfo *addresses = NULL; - int ga_result = getaddrinfo(host, port, &hints, &addresses); - if (ga_result != 0) { - die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result)); - } - - /* count the number of returned hosts, and allocate stuff accordingly */ size_t num_hosts = 0; - for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { - num_hosts++; + if (host[0] == '/') { + num_hosts = 1; + is_socket = true; + } else { + is_socket = false; + + /* fill in ai with the list of hosts resolved by the host name */ + struct addrinfo *addresses = NULL; + int ga_result = getaddrinfo(host, port, &hints, &addresses); + if (ga_result != 0) { + die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result)); + } + + /* count the number of returned hosts, and allocate stuff accordingly */ + for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { + num_hosts++; + } } ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts); @@ -374,25 +385,51 @@ static offset_request_wrapper offset_request(const char *host, const char *port, DBG(printf("Found %zu peers to check\n", num_hosts)); /* setup each socket for writing, and the corresponding struct pollfd */ - struct addrinfo *ai_tmp = addresses; - for (int i = 0; ai_tmp; i++) { - socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); - if (socklist[i] == -1) { - perror(NULL); - die(STATE_UNKNOWN, "can not create new socket"); + if (is_socket) { + socklist[0] = socket(AF_UNIX, SOCK_STREAM, 0); + if (socklist[0] == -1) { + DBG(printf("can't create socket: %s\n", strerror(errno))); + die(STATE_UNKNOWN, "can not create new socket\n"); } - if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) { + + struct sockaddr_un unix_socket = { + .sun_family = AF_UNIX, + }; + + strncpy(unix_socket.sun_path, host, strlen(host)); + + if (connect(socklist[0], &unix_socket, sizeof(unix_socket))) { /* don't die here, because it is enough if there is one server answering in time. This also would break for dual ipv4/6 stacked ntp servers when the client only supports on of them. */ - DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); + DBG(printf("can't create socket connection on peer %i: %s\n", 0, strerror(errno))); } else { - ufds[i].fd = socklist[i]; - ufds[i].events = POLLIN; - ufds[i].revents = 0; + ufds[0].fd = socklist[0]; + ufds[0].events = POLLIN; + ufds[0].revents = 0; + } + } else { + struct addrinfo *ai_tmp = addresses; + for (int i = 0; ai_tmp; i++) { + socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); + if (socklist[i] == -1) { + perror(NULL); + die(STATE_UNKNOWN, "can not create new socket"); + } + if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) { + /* don't die here, because it is enough if there is one server + answering in time. This also would break for dual ipv4/6 stacked + ntp servers when the client only supports on of them. + */ + DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); + } else { + ufds[i].fd = socklist[i]; + ufds[i].events = POLLIN; + ufds[i].revents = 0; + } + ai_tmp = ai_tmp->ai_next; } - ai_tmp = ai_tmp->ai_next; } /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds @@ -586,7 +623,7 @@ static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range); } break; case 'H': - if (!is_host(optarg)) { + if (!is_host(optarg) && (optarg[0] != '/')) { usage2(_("Invalid hostname/address"), optarg); } result.config.server_address = strdup(optarg); diff --git a/plugins/t/check_ntp.t b/plugins/t/check_ntp.t index a8ac7bb8..7703bc3b 100644 --- a/plugins/t/check_ntp.t +++ b/plugins/t/check_ntp.t @@ -8,7 +8,7 @@ use strict; use Test::More; use NPTest; -my @PLUGINS1 = ('check_ntp', 'check_ntp_peer', 'check_ntp_time'); +my @PLUGINS1 = ('check_ntp_peer', 'check_ntp_time'); my @PLUGINS2 = ('check_ntp_peer'); plan tests => (12 * scalar(@PLUGINS1)) + (6 * scalar(@PLUGINS2)); -- cgit v1.2.3-74-g34f1