From 178e9a02e367ab4527129ddbc623401e245d00b2 Mon Sep 17 00:00:00 2001 From: inqrphl <32687873+inqrphl@users.noreply.github.com> Date: Tue, 19 May 2026 16:01:43 +0200 Subject: check_http and check_curl: custom timeout return state (#2266) check_curl + check_http: hdd cli argument to return custom states on timeout --------- Co-authored-by: Ahmet Oeztuerk --- plugins/check_curl.c | 35 ++++++++++++++++++++++++++++--- plugins/check_curl.d/check_curl_helpers.c | 1 + plugins/check_curl.d/config.h | 3 +++ plugins/check_http.c | 25 ++++++++++++++++++++-- plugins/t/check_curl.t | 29 +++++++++++++++++++++++-- 5 files changed, 86 insertions(+), 7 deletions(-) (limited to 'plugins') diff --git a/plugins/check_curl.c b/plugins/check_curl.c index 67d89129..3f44c86b 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c @@ -273,9 +273,17 @@ mp_subcheck check_http(const check_curl_config config, check_curl_working_state /* Curl errors, result in critical Nagios state */ if (res != CURLE_OK) { - xasprintf(&sc_curl.output, _("Error while performing connection: cURL returned %d - %s"), - res, errbuf[0] ? errbuf : curl_easy_strerror(res)); - sc_curl = mp_set_subcheck_state(sc_curl, STATE_CRITICAL); + /* Custom handling for timeouts, state might be set to non CRITICAL */ + if (res == CURLE_OPERATION_TIMEDOUT) { + xasprintf(&sc_curl.output, _("cURL returned %d - %s"), res, + errbuf[0] ? errbuf : curl_easy_strerror(res)); + sc_curl = mp_set_subcheck_state(sc_curl, config.on_timeout_result_state); + } else { + xasprintf(&sc_curl.output, + _("Error while performing connection: cURL returned %d - %s"), res, + errbuf[0] ? errbuf : curl_easy_strerror(res)); + sc_curl = mp_set_subcheck_state(sc_curl, STATE_CRITICAL); + } mp_add_subcheck_to_subcheck(&sc_result, sc_curl); return sc_result; } @@ -890,6 +898,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { STATE_REGEX, OUTPUT_FORMAT, NO_PROXY, + TIMEOUT_RESULT, }; static struct option longopts[] = { @@ -939,6 +948,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { {"cookie-jar", required_argument, 0, COOKIE_JAR}, {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL}, {"output-format", required_argument, 0, OUTPUT_FORMAT}, + {"timeout-result", required_argument, 0, TIMEOUT_RESULT}, {0, 0, 0, 0}}; check_curl_config_wrapper result = { @@ -1004,6 +1014,21 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { result.config.curl_config.socket_timeout = (int)strtol(optarg, NULL, 10); } break; + case TIMEOUT_RESULT: + if (!strcmp(optarg, "0") || !strcasecmp(optarg, "ok")) { + result.config.on_timeout_result_state = STATE_OK; + } else if (!strcmp(optarg, "1") || !strcasecmp(optarg, "warning")) { + result.config.on_timeout_result_state = STATE_WARNING; + } else if (!strcmp(optarg, "2") || !strcasecmp(optarg, "critical")) { + result.config.on_timeout_result_state = STATE_CRITICAL; + } else if (!strcmp(optarg, "3") || !strcasecmp(optarg, "unknown")) { + result.config.on_timeout_result_state = STATE_UNKNOWN; + } else { + usage2(_("Invalid timeout-result state option, give either a return code or state " + "name in lowercase"), + optarg); + } + break; case 'c': /* critical time threshold */ { mp_range_parsed critical_range = mp_parse_range_string(optarg); @@ -1701,6 +1726,10 @@ void print_help(void) { printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); + printf(" %s\n", "--timeout-result=ok|warning|critical|unknown|0|1|2|3"); + printf(" %s\n", _("Timeouts default to returning STATE_CRITICAL.")); + printf(" %s\n", _("This argument changes the return state on timeouts.")); + printf(UT_VERBOSE); printf(UT_OUTPUT_FORMAT); diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c index 80d6f4f6..5b13a138 100644 --- a/plugins/check_curl.d/check_curl_helpers.c +++ b/plugins/check_curl.d/check_curl_helpers.c @@ -755,6 +755,7 @@ check_curl_config check_curl_config_init(void) { .header_expect = "", .on_redirect_result_state = STATE_OK, .on_redirect_dependent = false, + .on_timeout_result_state = STATE_CRITICAL, .show_extended_perfdata = false, .show_body = false, diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h index bcdf3010..0a7fa01d 100644 --- a/plugins/check_curl.d/config.h +++ b/plugins/check_curl.d/config.h @@ -113,9 +113,12 @@ typedef struct { mp_state_enum on_redirect_result_state; bool on_redirect_dependent; + mp_state_enum on_timeout_result_state; + bool show_extended_perfdata; bool show_body; + bool output_format_is_set; mp_output_format output_format; } check_curl_config; diff --git a/plugins/check_http.c b/plugins/check_http.c index 71f94b91..73e4f3b6 100644 --- a/plugins/check_http.c +++ b/plugins/check_http.c @@ -205,7 +205,8 @@ bool process_arguments(int argc, char **argv) { SNI_OPTION, MAX_REDIRS_OPTION, CONTINUE_AFTER_CHECK_CERT, - STATE_REGEX + STATE_REGEX, + TIMEOUT_RESULT }; int option = 0; @@ -247,6 +248,7 @@ bool process_arguments(int argc, char **argv) { {"extended-perfdata", no_argument, 0, 'E'}, {"show-body", no_argument, 0, 'B'}, {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, + {"timeout-result", required_argument, 0, TIMEOUT_RESULT}, {0, 0, 0, 0}}; if (argc < 2) { @@ -298,6 +300,21 @@ bool process_arguments(int argc, char **argv) { socket_timeout = atoi(optarg); } break; + case TIMEOUT_RESULT: + if (!strcmp(optarg, "0") || !strcasecmp(optarg, "ok")) { + socket_timeout_state = STATE_OK; + } else if (!strcmp(optarg, "1") || !strcasecmp(optarg, "warning")) { + socket_timeout_state = STATE_WARNING; + } else if (!strcmp(optarg, "2") || !strcasecmp(optarg, "critical")) { + socket_timeout_state = STATE_CRITICAL; + } else if (!strcmp(optarg, "3") || !strcasecmp(optarg, "unknown")) { + socket_timeout_state = STATE_UNKNOWN; + } else { + usage2(_("Invalid timeout-result state option, give either a return code or state " + "name in lowercase"), + optarg); + } + break; case 'c': /* critical time threshold */ critical_thresholds = optarg; break; @@ -1032,7 +1049,7 @@ int check_http(void) { printf("SSL initialized\n"); } if (result != STATE_OK) { - die(STATE_CRITICAL, _("HTTP CRITICAL - SSL error\n")); + die(STATE_CRITICAL, _("HTTP CRITICAL - SSL error\n")); } microsec_ssl = deltime(tv_temp); elapsed_time_ssl = (double)microsec_ssl / 1.0e6; @@ -1883,6 +1900,10 @@ void print_help(void) { printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); + printf(" %s\n", "--timeout-result=ok|warning|critical|unknown|0|1|2|3"); + printf(" %s\n", _("Timeouts default to returning STATE_CRITICAL.")); + printf(" %s\n", _("This argument changes the return state on timeouts.")); + printf(UT_VERBOSE); printf("\n"); diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t index 0f4d0de7..7ec8ca06 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 ? 57 : 92; + $tests = $has_ipv6 ? 65 : 100; plan tests => $tests; } @@ -69,7 +69,32 @@ $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, "/cURL returned 28 - Connection timed out after/", "Output OK"); +like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK"); + +# timeout return results can be changed using --timeout-result option +$res = NPTest->testCmd( + "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3 --timeout-result ok" + ); +like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK"); +cmp_ok( $res->return_code, "==", 0, "Return code is correct due argument: --timeout-result ok"); + +$res = NPTest->testCmd( + "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3 --timeout-result warning" + ); +like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK"); +cmp_ok( $res->return_code, "==", 1, "Return code is correct due argument: --timeout-result warning"); + +$res = NPTest->testCmd( + "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3 --timeout-result 2" + ); +like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK"); +cmp_ok( $res->return_code, "==", 2, "Return code is correct due argument: --timeout-result 2"); + +$res = NPTest->testCmd( + "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3 --timeout-result 3" + ); +like( $res->output, "/cURL returned 28 - (Connection|Operation) timed out after/", "Output OK"); +cmp_ok( $res->return_code, "==", 3, "Return code is correct due argument: --timeout-result 3"); $res = NPTest->testCmd( "./$plugin $hostname_invalid -wt 1 -ct 2" -- cgit v1.2.3-74-g34f1