From 5eb1a9c921460151716a4897fbcdef8f50658303 Mon Sep 17 00:00:00 2001 From: Sami Kerola Date: Fri, 14 Aug 2015 21:06:28 +0100 Subject: [PATCH] check_timex: add new plugin This plugin uses ntp_adjtime() function to read and report system time using struct timex values. Check is similar to check_ntp_time, but with a difference being completely local execution. This has some desirable effects, such as: 1) This check runs very quickly. 2) The status of clock is reported from solely systems point of view, i.e., a small network hiccup or public DNS failure will not cause spurious failures 3) The check works when clock is syncronized with something else than ntp, such as ptp. Main difference of the check_timex and check_ntp_time is units used in --warning and --critical arguments. This check is using microseconds, while the check_ntp_time is using seconds. That means one should not interchange these checks without additional configuration changes. --- .gitignore | 1 + THANKS.in | 1 + configure.ac | 5 ++ plugins/Makefile.am | 5 ++ plugins/check_timex.c | 175 ++++++++++++++++++++++++++++++++++++++++++ po/POTFILES.in | 1 + 6 files changed, 188 insertions(+) create mode 100644 plugins/check_timex.c diff --git a/.gitignore b/.gitignore index 3093c6ead..c8d71f37a 100644 --- a/.gitignore +++ b/.gitignore @@ -187,6 +187,7 @@ NP-VERSION-FILE /plugins/check_swap /plugins/check_tcp /plugins/check_time +/plugins/check_timex /plugins/check_udp /plugins/check_ups /plugins/check_users diff --git a/THANKS.in b/THANKS.in index 59c90feb2..91361258c 100644 --- a/THANKS.in +++ b/THANKS.in @@ -336,3 +336,4 @@ Nick Peelman Sebastian Herbszt Christopher Schultz Matthias Hähnel +Sami Kerola diff --git a/configure.ac b/configure.ac index 0a554af68..0376df02c 100644 --- a/configure.ac +++ b/configure.ac @@ -593,6 +593,11 @@ dnl Checks for library functions. AC_CHECK_FUNCS(memmove select socket strdup strstr strtol strtoul floor) AC_CHECK_FUNCS(poll) +AC_CHECK_FUNCS([ntp_adjtime], + [AM_CONDITIONAL([HAVE_NTP_ADJTIME], [true])], + [AM_CONDITIONAL([HAVE_NTP_ADJTIME], [false])] +) + AC_MSG_CHECKING(return type of socket size) AC_TRY_COMPILE([#include #include diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 0ddf9bd1a..1ec3d0d71 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -117,6 +117,11 @@ if !HAVE_UTMPX check_users_LDADD += popen.o endif +if HAVE_NTP_ADJTIME +libexec_PROGRAMS += check_timex +check_timex_LDADD = $(NETLIBS) +endif + ############################################################################## # secondary dependencies diff --git a/plugins/check_timex.c b/plugins/check_timex.c new file mode 100644 index 000000000..04eaf35f0 --- /dev/null +++ b/plugins/check_timex.c @@ -0,0 +1,175 @@ +/***************************************************************************** +* +* Monitoring check_timex plugin +* +* License: GPL +* Copyright (c) 2015 Monitoring Plugins Development Team +* Author: Sami Kerola +* +* Description: +* +* This file contains the check_timex plugin +* +* This plugin uses ntp_gettime() interface to monitor system clock. +* +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* +*****************************************************************************/ + +const char *progname = "check_timex"; +const char *copyright = "2015"; +const char *email = "devel@monitoring-plugins.org"; + +#include "common.h" +#include "utils.h" + +#include + +long int warning_offset; +int check_warning_offset = FALSE; +long int critical_offset; +int check_critical_offset = FALSE; + +void +print_usage (void) +{ + printf ("%s\n", _("Usage:")); + printf (_("%s [-w offset_warn] [-c offset_crit]\n"), progname); +} + +static void +print_help (void) +{ + print_revision (progname, NP_VERSION); + printf ("Copyright (c) 2015 Monitoring Plugins Development Team\n"); + printf (COPYRIGHT, copyright, email); + printf ("%s\n", _("This plugin will check if the system time is syncronized.")); + printf ("\n\n"); + print_usage (); + printf (UT_HELP_VRSN); + printf (" %s\n", "-w, --warning=THRESHOLD"); + printf (" %s\n", _("Offset to result in warning status (microseconds)")); + printf (" %s\n", "-c, --critical=THRESHOLD"); + printf (" %s\n", _("Offset to result in critical status (microseconds)")); + printf ("\n"); + printf (" %s\n", _("System clock out of sync will always result critical status.")); + printf (UT_SUPPORT); +} + +static int +process_arguments (int argc, char **argv) +{ + static const struct option longopts[] = { + {"warning", required_argument, NULL, 'w'}, + {"critical", required_argument, NULL, 'c'}, + {"version", no_argument, NULL, 'V'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + int c; + + while (1) { + c = getopt_long (argc, argv, "w:c:Vh", longopts, NULL); + if (c == -1 || c == EOF) + break; + switch (c) { + case '?': + usage5 (); + case 'h': + print_help (); + exit (STATE_OK); + case 'V': + print_revision (progname, NP_VERSION); + exit (STATE_OK); + case 'w': + if (is_intnonneg (optarg)) { + warning_offset = strtol (optarg, NULL, 10); + check_warning_offset = TRUE; + } + else { + usage4 (_("Warning threshold must be a positive integer")); + } + break; + case 'c': + if (is_intnonneg (optarg)) { + critical_offset = strtol (optarg, NULL, 10); + check_critical_offset = TRUE; + } + else { + usage4 (_("Critical threshold must be a positive integer")); + } + break; + } + } + c = optind; + return OK; +} + +static int +with_in_limits (long int threshold, long int value) +{ + if (threshold < labs (value)) + return 1; + return 0; +} + +int +main (int argc, char **argv) +{ + int result = STATE_UNKNOWN, ret; + struct timex tx = { 0 }; + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + if (process_arguments (argc, argv) == ERROR) { + usage4 (_("Could not parse arguments")); + } + if (check_critical_offset && check_warning_offset) { + if (critical_offset < warning_offset) { + die (STATE_UNKNOWN, + _("Parameter inconsistency: warning is greater than critical\n")); + } + } + ret = ntp_adjtime (&tx); + if (ret == TIME_ERROR) { + die (STATE_CRITICAL, + "TIMEX CRITICAL: The precision clock model is not properly set up\n"); + } + fputs ("TIMEX ", stdout); + if (check_critical_offset && with_in_limits (critical_offset, tx.offset)) { + result = STATE_CRITICAL; + fputs ("CRITICAL: ", stdout); + } + else if (check_warning_offset && with_in_limits (warning_offset, tx.offset)) { + result = STATE_WARNING; + fputs ("WARNING: ", stdout); + } + else { + fputs ("OK: ", stdout); + } + printf ("Estimated error %ld|", tx.offset); + printf ("offset=%ld;%ld;%ld ", tx.offset, critical_offset, warning_offset); + printf ("maxerror=%ld ", tx.maxerror); + printf ("esterror=%ld ", tx.esterror); + printf ("precision=%ld ", tx.precision); + printf ("jitter=%ld ", tx.jitter); + printf ("stabil=%ld ", tx.stabil); + printf ("jitcnt=%ld ", tx.jitcnt); + printf ("errcnt=%ld ", tx.errcnt); + printf ("stbcnt=%ld\n", tx.stbcnt); + return result; +} diff --git a/po/POTFILES.in b/po/POTFILES.in index 6e491d78f..0dfd90656 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -31,6 +31,7 @@ plugins/check_ssh.c plugins/check_swap.c plugins/check_tcp.c plugins/check_time.c +plugins/check_timex.c plugins/check_ups.c plugins/check_users.c plugins/check_ide_smart.c