diff options
Diffstat (limited to 'plugins/check_dbi.c')
-rw-r--r-- | plugins/check_dbi.c | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c new file mode 100644 index 00000000..b52602c4 --- /dev/null +++ b/plugins/check_dbi.c @@ -0,0 +1,516 @@ +/***************************************************************************** +* +* Nagios check_dbi plugin +* +* License: GPL +* Copyright (c) 2011 Nagios Plugins Development Team +* Author: Sebastian 'tokkee' Harl <sh@teamix.net> +* +* Description: +* +* This file contains the check_dbi plugin +* +* Runs an arbitrary SQL command and checks the result. +* +* +* 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 <http://www.gnu.org/licenses/>. +* +* +*****************************************************************************/ + +const char *progname = "check_dbi"; +const char *copyright = "2011"; +const char *email = "nagiosplug-devel@lists.sourceforge.net"; + +#include "common.h" +#include "utils.h" + +#include "netutils.h" + +#include <dbi/dbi.h> + +#include <stdarg.h> + +typedef struct { + char *key; + char *value; +} driver_option_t; + +char *host = NULL; +int verbose = 0; + +char *warning_range = NULL; +char *critical_range = NULL; +thresholds *query_thresholds = NULL; + +char *np_dbi_driver = NULL; +driver_option_t *np_dbi_options = NULL; +int np_dbi_options_num = 0; +char *np_dbi_database = NULL; +char *np_dbi_query = NULL; + +int process_arguments (int, char **); +int validate_arguments (void); +void print_usage (void); +void print_help (void); + +void np_dbi_print_error (dbi_conn, char *, ...); + +int do_query (dbi_conn, double *); + +int +main (int argc, char **argv) +{ + int status = STATE_UNKNOWN; + + dbi_driver driver; + dbi_conn conn; + + struct timeval start_timeval, end_timeval; + double elapsed_time; + + double query_val = 0.0; + + int i; + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + /* Parse extra opts if any */ + argv = np_extra_opts (&argc, argv, progname); + + if (process_arguments (argc, argv) == ERROR) + usage4 (_("Could not parse arguments")); + + /* Set signal handling and alarm */ + if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { + usage4 (_("Cannot catch SIGALRM")); + } + alarm (timeout_interval); + + if (verbose > 2) + printf ("Initializing DBI\n"); + + if (dbi_initialize (NULL) < 0) { + printf ("UNKNOWN - failed to initialize DBI.\n"); + return STATE_UNKNOWN; + } + + if (verbose) + printf ("Opening DBI driver '%s'\n", np_dbi_driver); + + driver = dbi_driver_open (np_dbi_driver); + if (! driver) { + printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", + np_dbi_driver); + + printf ("Known drivers:\n"); + for (driver = dbi_driver_list (NULL); driver; driver = dbi_driver_list (driver)) { + printf (" - %s\n", dbi_driver_get_name (driver)); + } + return STATE_UNKNOWN; + } + + /* make a connection to the database */ + gettimeofday (&start_timeval, NULL); + + conn = dbi_conn_open (driver); + if (! conn) { + printf ("UNKNOWN - failed top open connection object.\n"); + dbi_conn_close (conn); + return STATE_UNKNOWN; + } + + for (i = 0; i < np_dbi_options_num; ++i) { + const char *opt; + + if (verbose > 1) + printf ("Setting DBI driver option '%s' to '%s'\n", + np_dbi_options[i].key, np_dbi_options[i].value); + + if (! dbi_conn_set_option (conn, np_dbi_options[i].key, np_dbi_options[i].value)) + continue; + /* else: status != 0 */ + + np_dbi_print_error (conn, "UNKNOWN - failed to set option '%s' to '%s'", + np_dbi_options[i].key, np_dbi_options[i].value); + printf ("Known driver options:\n"); + + for (opt = dbi_conn_get_option_list (conn, NULL); opt; + opt = dbi_conn_get_option_list (conn, opt)) { + printf (" - %s\n", opt); + } + dbi_conn_close (conn); + return STATE_UNKNOWN; + } + + if (host) { + if (verbose > 1) + printf ("Setting DBI driver option 'host' to '%s'\n", host); + dbi_conn_set_option (conn, "host", host); + } + + if (verbose) { + const char *dbname, *host; + + dbname = dbi_conn_get_option (conn, "dbname"); + host = dbi_conn_get_option (conn, "host"); + + if (! dbname) + dbname = "<unspecified>"; + if (! host) + host = "<unspecified>"; + + printf ("Connecting to database '%s' at host '%s'\n", + dbname, host); + } + + if (dbi_conn_connect (conn) < 0) { + np_dbi_print_error (conn, "UNKOWN - failed to connect to database"); + return STATE_UNKNOWN; + } + + gettimeofday (&end_timeval, NULL); + while (start_timeval.tv_usec > end_timeval.tv_usec) { + --end_timeval.tv_sec; + end_timeval.tv_usec += 1000000; + } + elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec) + + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0; + + if (verbose) + printf("Time elapsed: %f\n", elapsed_time); + + /* select a database */ + if (np_dbi_database) { + if (verbose > 1) + printf ("Selecting database '%s'\n", np_dbi_database); + + if (dbi_conn_select_db (conn, np_dbi_database)) { + np_dbi_print_error (conn, "UNKOWN - failed to select database '%s'", + np_dbi_database); + return STATE_UNKNOWN; + } + } + + /* execute query */ + status = do_query (conn, &query_val); + if (status != STATE_OK) + /* do_query prints an error message in this case */ + return status; + + status = get_status (query_val, query_thresholds); + + if (verbose) + printf("Closing connection\n"); + dbi_conn_close (conn); + + printf ("%s - connection time: %fs, '%s' returned %f", + state_text (status), elapsed_time, np_dbi_query, query_val); + printf (" | conntime=%fs;;;0 query=%f;%s;%s;0\n", elapsed_time, query_val, + warning_range ? warning_range : "", critical_range ? critical_range : ""); + return status; +} + +/* process command-line arguments */ +int +process_arguments (int argc, char **argv) +{ + int c; + + int option = 0; + static struct option longopts[] = { + STD_LONG_OPTS, + + {"driver", required_argument, 0, 'd'}, + {"option", required_argument, 0, 'o'}, + {"query", required_argument, 0, 'q'}, + {"database", required_argument, 0, 'D'}, + {0, 0, 0, 0} + }; + + while (1) { + c = getopt_long (argc, argv, "Vvht:c:w:H:d:o:q:D:", + longopts, &option); + + if (c == EOF) + break; + + switch (c) { + case '?': /* usage */ + usage5 (); + case 'h': /* help */ + print_help (); + exit (STATE_OK); + case 'V': /* version */ + print_revision (progname, NP_VERSION); + exit (STATE_OK); + + case 'c': /* critical range */ + critical_range = optarg; + break; + case 'w': /* warning range */ + warning_range = optarg; + break; + case 't': /* timeout */ + if (!is_intnonneg (optarg)) + usage2 (_("Timeout interval must be a positive integer"), optarg); + else + timeout_interval = atoi (optarg); + + case 'H': /* host */ + if (!is_host (optarg)) + usage2 (_("Invalid hostname/address"), optarg); + else + host = optarg; + break; + case 'v': + verbose++; + break; + + case 'd': + np_dbi_driver = optarg; + break; + case 'o': + { + driver_option_t *new; + + char *k, *v; + + k = optarg; + v = strchr (k, (int)'='); + + if (! v) + usage2 (_("Option must be '<key>=<value>'"), optarg); + + *v = '\0'; + ++v; + + new = realloc (np_dbi_options, + (np_dbi_options_num + 1) * sizeof (*new)); + if (! new) { + printf ("UNKOWN - failed to reallocate memory\n"); + exit (STATE_UNKNOWN); + } + + np_dbi_options = new; + new = np_dbi_options + np_dbi_options_num; + ++np_dbi_options_num; + + new->key = k; + new->value = v; + } + break; + case 'q': + np_dbi_query = optarg; + break; + case 'D': + np_dbi_database = optarg; + break; + } + } + + set_thresholds (&query_thresholds, warning_range, critical_range); + + return validate_arguments (); +} + +int +validate_arguments () +{ + if (! np_dbi_driver) + usage ("Must specify a DBI driver"); + + if (! np_dbi_query) + usage ("Must specify an SQL query to execute"); + + return OK; +} + +void +print_help (void) +{ + print_revision (progname, NP_VERSION); + + printf (COPYRIGHT, copyright, email); + + printf (_("This program checks a query result against threshold levels")); + + printf ("\n\n"); + + print_usage (); + + printf (UT_HELP_VRSN); + printf ("\n"); + + printf (" %s\n", "-d, --driver=STRING"); + printf (" %s\n", _("DBI driver to use")); + printf (" %s\n", "-o, --option=STRING"); + printf (" %s\n", _("DBI driver options")); + printf (" %s\n", "-q, --query=STRING"); + printf (" %s\n", _("SQL query to execute")); + printf ("\n"); + + printf (UT_WARN_CRIT_RANGE); + + printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); + + printf (UT_VERBOSE); + + printf ("\n"); + printf (" %s\n", _("A DBI driver (-d option) and a query (-q option) are required.")); + printf (" %s\n", _("This plugin connects to an SQL database using libdbi and executes the")); + printf (" %s\n", _("specified SQL query. The first column of the first row of the result")); + printf (" %s\n", _("will be used as the check result and, if specified, compared with the")); + printf (" %s\n", _("warning and critical ranges. The result from the query has to be numeric")); + printf (" %s\n\n", _("(strings representing numbers are fine).")); + + printf (" %s\n", _("The number and type of required DBI driver options depends on the actual")); + printf (" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/")); + printf (" %s\n", _("for details.")); + + printf (UT_SUPPORT); +} + +void +print_usage (void) +{ + printf ("%s\n", _("Usage:")); + printf ("%s -d <DBI driver> [-o <DBI driver option> [...]] -q <SQL query>\n", progname); + printf (" [-H <host>] [-c <critical value>] [-w <warning value>]\n"); +} + +double +get_field (dbi_conn conn, dbi_result res, unsigned short *field_type) +{ + double val = 0.0; + + if (*field_type == DBI_TYPE_INTEGER) { + val = (double)dbi_result_get_longlong_idx (res, 1); + } + else if (*field_type == DBI_TYPE_DECIMAL) { + val = dbi_result_get_double_idx (res, 1); + } + else if (*field_type == DBI_TYPE_STRING) { + const char *val_str; + char *endptr = NULL; + + val_str = dbi_result_get_string_idx (res, 1); + if ((! val_str) || (strcmp (val_str, "ERROR") == 0)) { + np_dbi_print_error (conn, "CRITICAL - failed to fetch string value"); + *field_type = DBI_TYPE_ERROR; + return 0.0; + } + + if (verbose > 2) + printf ("Query returned string '%s'\n", val_str); + + val = strtod (val_str, &endptr); + if (endptr == val_str) { + printf ("CRITICAL - result value is not a numeric: %s\n", val_str); + *field_type = DBI_TYPE_ERROR; + return 0.0; + } + else if ((endptr != NULL) && (*endptr != '\0')) { + if (verbose) + printf ("Garbage after value: %s\n", endptr); + } + } + else { + printf ("CRITICAL - cannot parse value of type %s (%i)\n", + (*field_type == DBI_TYPE_BINARY) + ? "BINARY" + : (*field_type == DBI_TYPE_DATETIME) + ? "DATETIME" + : "<unknown>", + *field_type); + *field_type = DBI_TYPE_ERROR; + return 0.0; + } + return val; +} + +int +do_query (dbi_conn conn, double *res_val) +{ + dbi_result res; + + unsigned short field_type; + double val = 0.0; + + if (verbose) + printf ("Executing query '%s'\n", np_dbi_query); + + res = dbi_conn_query (conn, np_dbi_query); + if (! res) { + np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); + return STATE_CRITICAL; + } + + if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) { + np_dbi_print_error (conn, "CRITICAL - failed to fetch rows"); + return STATE_CRITICAL; + } + + if (dbi_result_get_numrows (res) < 1) { + printf ("WARNING - no rows returned\n"); + return STATE_WARNING; + } + + if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) { + np_dbi_print_error (conn, "CRITICAL - failed to fetch fields"); + return STATE_CRITICAL; + } + + if (dbi_result_get_numfields (res) < 1) { + printf ("WARNING - no fields returned\n"); + return STATE_WARNING; + } + + if (dbi_result_first_row (res) != 1) { + np_dbi_print_error (conn, "CRITICAL - failed to fetch first row"); + return STATE_CRITICAL; + } + + field_type = dbi_result_get_field_type_idx (res, 1); + if (field_type != DBI_TYPE_ERROR) + val = get_field (conn, res, &field_type); + + if (field_type == DBI_TYPE_ERROR) { + np_dbi_print_error (conn, "CRITICAL - failed to fetch data"); + return STATE_CRITICAL; + } + + *res_val = val; + + dbi_result_free (res); + return STATE_OK; +} + +void +np_dbi_print_error (dbi_conn conn, char *fmt, ...) +{ + const char *errmsg = NULL; + va_list ap; + + va_start (ap, fmt); + + dbi_conn_error (conn, &errmsg); + vprintf (fmt, ap); + printf (": %s\n", errmsg); + + va_end (ap); +} + |