summaryrefslogtreecommitdiffstats
path: root/plugins/check_dbi.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_dbi.c')
-rw-r--r--plugins/check_dbi.c516
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 @@
1/*****************************************************************************
2*
3* Nagios check_dbi plugin
4*
5* License: GPL
6* Copyright (c) 2011 Nagios Plugins Development Team
7* Author: Sebastian 'tokkee' Harl <sh@teamix.net>
8*
9* Description:
10*
11* This file contains the check_dbi plugin
12*
13* Runs an arbitrary SQL command and checks the result.
14*
15*
16* This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version.
20*
21* This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details.
25*
26* You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>.
28*
29*
30*****************************************************************************/
31
32const char *progname = "check_dbi";
33const char *copyright = "2011";
34const char *email = "nagiosplug-devel@lists.sourceforge.net";
35
36#include "common.h"
37#include "utils.h"
38
39#include "netutils.h"
40
41#include <dbi/dbi.h>
42
43#include <stdarg.h>
44
45typedef struct {
46 char *key;
47 char *value;
48} driver_option_t;
49
50char *host = NULL;
51int verbose = 0;
52
53char *warning_range = NULL;
54char *critical_range = NULL;
55thresholds *query_thresholds = NULL;
56
57char *np_dbi_driver = NULL;
58driver_option_t *np_dbi_options = NULL;
59int np_dbi_options_num = 0;
60char *np_dbi_database = NULL;
61char *np_dbi_query = NULL;
62
63int process_arguments (int, char **);
64int validate_arguments (void);
65void print_usage (void);
66void print_help (void);
67
68void np_dbi_print_error (dbi_conn, char *, ...);
69
70int do_query (dbi_conn, double *);
71
72int
73main (int argc, char **argv)
74{
75 int status = STATE_UNKNOWN;
76
77 dbi_driver driver;
78 dbi_conn conn;
79
80 struct timeval start_timeval, end_timeval;
81 double elapsed_time;
82
83 double query_val = 0.0;
84
85 int i;
86
87 setlocale (LC_ALL, "");
88 bindtextdomain (PACKAGE, LOCALEDIR);
89 textdomain (PACKAGE);
90
91 /* Parse extra opts if any */
92 argv = np_extra_opts (&argc, argv, progname);
93
94 if (process_arguments (argc, argv) == ERROR)
95 usage4 (_("Could not parse arguments"));
96
97 /* Set signal handling and alarm */
98 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
99 usage4 (_("Cannot catch SIGALRM"));
100 }
101 alarm (timeout_interval);
102
103 if (verbose > 2)
104 printf ("Initializing DBI\n");
105
106 if (dbi_initialize (NULL) < 0) {
107 printf ("UNKNOWN - failed to initialize DBI.\n");
108 return STATE_UNKNOWN;
109 }
110
111 if (verbose)
112 printf ("Opening DBI driver '%s'\n", np_dbi_driver);
113
114 driver = dbi_driver_open (np_dbi_driver);
115 if (! driver) {
116 printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n",
117 np_dbi_driver);
118
119 printf ("Known drivers:\n");
120 for (driver = dbi_driver_list (NULL); driver; driver = dbi_driver_list (driver)) {
121 printf (" - %s\n", dbi_driver_get_name (driver));
122 }
123 return STATE_UNKNOWN;
124 }
125
126 /* make a connection to the database */
127 gettimeofday (&start_timeval, NULL);
128
129 conn = dbi_conn_open (driver);
130 if (! conn) {
131 printf ("UNKNOWN - failed top open connection object.\n");
132 dbi_conn_close (conn);
133 return STATE_UNKNOWN;
134 }
135
136 for (i = 0; i < np_dbi_options_num; ++i) {
137 const char *opt;
138
139 if (verbose > 1)
140 printf ("Setting DBI driver option '%s' to '%s'\n",
141 np_dbi_options[i].key, np_dbi_options[i].value);
142
143 if (! dbi_conn_set_option (conn, np_dbi_options[i].key, np_dbi_options[i].value))
144 continue;
145 /* else: status != 0 */
146
147 np_dbi_print_error (conn, "UNKNOWN - failed to set option '%s' to '%s'",
148 np_dbi_options[i].key, np_dbi_options[i].value);
149 printf ("Known driver options:\n");
150
151 for (opt = dbi_conn_get_option_list (conn, NULL); opt;
152 opt = dbi_conn_get_option_list (conn, opt)) {
153 printf (" - %s\n", opt);
154 }
155 dbi_conn_close (conn);
156 return STATE_UNKNOWN;
157 }
158
159 if (host) {
160 if (verbose > 1)
161 printf ("Setting DBI driver option 'host' to '%s'\n", host);
162 dbi_conn_set_option (conn, "host", host);
163 }
164
165 if (verbose) {
166 const char *dbname, *host;
167
168 dbname = dbi_conn_get_option (conn, "dbname");
169 host = dbi_conn_get_option (conn, "host");
170
171 if (! dbname)
172 dbname = "<unspecified>";
173 if (! host)
174 host = "<unspecified>";
175
176 printf ("Connecting to database '%s' at host '%s'\n",
177 dbname, host);
178 }
179
180 if (dbi_conn_connect (conn) < 0) {
181 np_dbi_print_error (conn, "UNKOWN - failed to connect to database");
182 return STATE_UNKNOWN;
183 }
184
185 gettimeofday (&end_timeval, NULL);
186 while (start_timeval.tv_usec > end_timeval.tv_usec) {
187 --end_timeval.tv_sec;
188 end_timeval.tv_usec += 1000000;
189 }
190 elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec)
191 + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0;
192
193 if (verbose)
194 printf("Time elapsed: %f\n", elapsed_time);
195
196 /* select a database */
197 if (np_dbi_database) {
198 if (verbose > 1)
199 printf ("Selecting database '%s'\n", np_dbi_database);
200
201 if (dbi_conn_select_db (conn, np_dbi_database)) {
202 np_dbi_print_error (conn, "UNKOWN - failed to select database '%s'",
203 np_dbi_database);
204 return STATE_UNKNOWN;
205 }
206 }
207
208 /* execute query */
209 status = do_query (conn, &query_val);
210 if (status != STATE_OK)
211 /* do_query prints an error message in this case */
212 return status;
213
214 status = get_status (query_val, query_thresholds);
215
216 if (verbose)
217 printf("Closing connection\n");
218 dbi_conn_close (conn);
219
220 printf ("%s - connection time: %fs, '%s' returned %f",
221 state_text (status), elapsed_time, np_dbi_query, query_val);
222 printf (" | conntime=%fs;;;0 query=%f;%s;%s;0\n", elapsed_time, query_val,
223 warning_range ? warning_range : "", critical_range ? critical_range : "");
224 return status;
225}
226
227/* process command-line arguments */
228int
229process_arguments (int argc, char **argv)
230{
231 int c;
232
233 int option = 0;
234 static struct option longopts[] = {
235 STD_LONG_OPTS,
236
237 {"driver", required_argument, 0, 'd'},
238 {"option", required_argument, 0, 'o'},
239 {"query", required_argument, 0, 'q'},
240 {"database", required_argument, 0, 'D'},
241 {0, 0, 0, 0}
242 };
243
244 while (1) {
245 c = getopt_long (argc, argv, "Vvht:c:w:H:d:o:q:D:",
246 longopts, &option);
247
248 if (c == EOF)
249 break;
250
251 switch (c) {
252 case '?': /* usage */
253 usage5 ();
254 case 'h': /* help */
255 print_help ();
256 exit (STATE_OK);
257 case 'V': /* version */
258 print_revision (progname, NP_VERSION);
259 exit (STATE_OK);
260
261 case 'c': /* critical range */
262 critical_range = optarg;
263 break;
264 case 'w': /* warning range */
265 warning_range = optarg;
266 break;
267 case 't': /* timeout */
268 if (!is_intnonneg (optarg))
269 usage2 (_("Timeout interval must be a positive integer"), optarg);
270 else
271 timeout_interval = atoi (optarg);
272
273 case 'H': /* host */
274 if (!is_host (optarg))
275 usage2 (_("Invalid hostname/address"), optarg);
276 else
277 host = optarg;
278 break;
279 case 'v':
280 verbose++;
281 break;
282
283 case 'd':
284 np_dbi_driver = optarg;
285 break;
286 case 'o':
287 {
288 driver_option_t *new;
289
290 char *k, *v;
291
292 k = optarg;
293 v = strchr (k, (int)'=');
294
295 if (! v)
296 usage2 (_("Option must be '<key>=<value>'"), optarg);
297
298 *v = '\0';
299 ++v;
300
301 new = realloc (np_dbi_options,
302 (np_dbi_options_num + 1) * sizeof (*new));
303 if (! new) {
304 printf ("UNKOWN - failed to reallocate memory\n");
305 exit (STATE_UNKNOWN);
306 }
307
308 np_dbi_options = new;
309 new = np_dbi_options + np_dbi_options_num;
310 ++np_dbi_options_num;
311
312 new->key = k;
313 new->value = v;
314 }
315 break;
316 case 'q':
317 np_dbi_query = optarg;
318 break;
319 case 'D':
320 np_dbi_database = optarg;
321 break;
322 }
323 }
324
325 set_thresholds (&query_thresholds, warning_range, critical_range);
326
327 return validate_arguments ();
328}
329
330int
331validate_arguments ()
332{
333 if (! np_dbi_driver)
334 usage ("Must specify a DBI driver");
335
336 if (! np_dbi_query)
337 usage ("Must specify an SQL query to execute");
338
339 return OK;
340}
341
342void
343print_help (void)
344{
345 print_revision (progname, NP_VERSION);
346
347 printf (COPYRIGHT, copyright, email);
348
349 printf (_("This program checks a query result against threshold levels"));
350
351 printf ("\n\n");
352
353 print_usage ();
354
355 printf (UT_HELP_VRSN);
356 printf ("\n");
357
358 printf (" %s\n", "-d, --driver=STRING");
359 printf (" %s\n", _("DBI driver to use"));
360 printf (" %s\n", "-o, --option=STRING");
361 printf (" %s\n", _("DBI driver options"));
362 printf (" %s\n", "-q, --query=STRING");
363 printf (" %s\n", _("SQL query to execute"));
364 printf ("\n");
365
366 printf (UT_WARN_CRIT_RANGE);
367
368 printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
369
370 printf (UT_VERBOSE);
371
372 printf ("\n");
373 printf (" %s\n", _("A DBI driver (-d option) and a query (-q option) are required."));
374 printf (" %s\n", _("This plugin connects to an SQL database using libdbi and executes the"));
375 printf (" %s\n", _("specified SQL query. The first column of the first row of the result"));
376 printf (" %s\n", _("will be used as the check result and, if specified, compared with the"));
377 printf (" %s\n", _("warning and critical ranges. The result from the query has to be numeric"));
378 printf (" %s\n\n", _("(strings representing numbers are fine)."));
379
380 printf (" %s\n", _("The number and type of required DBI driver options depends on the actual"));
381 printf (" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/"));
382 printf (" %s\n", _("for details."));
383
384 printf (UT_SUPPORT);
385}
386
387void
388print_usage (void)
389{
390 printf ("%s\n", _("Usage:"));
391 printf ("%s -d <DBI driver> [-o <DBI driver option> [...]] -q <SQL query>\n", progname);
392 printf (" [-H <host>] [-c <critical value>] [-w <warning value>]\n");
393}
394
395double
396get_field (dbi_conn conn, dbi_result res, unsigned short *field_type)
397{
398 double val = 0.0;
399
400 if (*field_type == DBI_TYPE_INTEGER) {
401 val = (double)dbi_result_get_longlong_idx (res, 1);
402 }
403 else if (*field_type == DBI_TYPE_DECIMAL) {
404 val = dbi_result_get_double_idx (res, 1);
405 }
406 else if (*field_type == DBI_TYPE_STRING) {
407 const char *val_str;
408 char *endptr = NULL;
409
410 val_str = dbi_result_get_string_idx (res, 1);
411 if ((! val_str) || (strcmp (val_str, "ERROR") == 0)) {
412 np_dbi_print_error (conn, "CRITICAL - failed to fetch string value");
413 *field_type = DBI_TYPE_ERROR;
414 return 0.0;
415 }
416
417 if (verbose > 2)
418 printf ("Query returned string '%s'\n", val_str);
419
420 val = strtod (val_str, &endptr);
421 if (endptr == val_str) {
422 printf ("CRITICAL - result value is not a numeric: %s\n", val_str);
423 *field_type = DBI_TYPE_ERROR;
424 return 0.0;
425 }
426 else if ((endptr != NULL) && (*endptr != '\0')) {
427 if (verbose)
428 printf ("Garbage after value: %s\n", endptr);
429 }
430 }
431 else {
432 printf ("CRITICAL - cannot parse value of type %s (%i)\n",
433 (*field_type == DBI_TYPE_BINARY)
434 ? "BINARY"
435 : (*field_type == DBI_TYPE_DATETIME)
436 ? "DATETIME"
437 : "<unknown>",
438 *field_type);
439 *field_type = DBI_TYPE_ERROR;
440 return 0.0;
441 }
442 return val;
443}
444
445int
446do_query (dbi_conn conn, double *res_val)
447{
448 dbi_result res;
449
450 unsigned short field_type;
451 double val = 0.0;
452
453 if (verbose)
454 printf ("Executing query '%s'\n", np_dbi_query);
455
456 res = dbi_conn_query (conn, np_dbi_query);
457 if (! res) {
458 np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query);
459 return STATE_CRITICAL;
460 }
461
462 if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) {
463 np_dbi_print_error (conn, "CRITICAL - failed to fetch rows");
464 return STATE_CRITICAL;
465 }
466
467 if (dbi_result_get_numrows (res) < 1) {
468 printf ("WARNING - no rows returned\n");
469 return STATE_WARNING;
470 }
471
472 if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) {
473 np_dbi_print_error (conn, "CRITICAL - failed to fetch fields");
474 return STATE_CRITICAL;
475 }
476
477 if (dbi_result_get_numfields (res) < 1) {
478 printf ("WARNING - no fields returned\n");
479 return STATE_WARNING;
480 }
481
482 if (dbi_result_first_row (res) != 1) {
483 np_dbi_print_error (conn, "CRITICAL - failed to fetch first row");
484 return STATE_CRITICAL;
485 }
486
487 field_type = dbi_result_get_field_type_idx (res, 1);
488 if (field_type != DBI_TYPE_ERROR)
489 val = get_field (conn, res, &field_type);
490
491 if (field_type == DBI_TYPE_ERROR) {
492 np_dbi_print_error (conn, "CRITICAL - failed to fetch data");
493 return STATE_CRITICAL;
494 }
495
496 *res_val = val;
497
498 dbi_result_free (res);
499 return STATE_OK;
500}
501
502void
503np_dbi_print_error (dbi_conn conn, char *fmt, ...)
504{
505 const char *errmsg = NULL;
506 va_list ap;
507
508 va_start (ap, fmt);
509
510 dbi_conn_error (conn, &errmsg);
511 vprintf (fmt, ap);
512 printf (": %s\n", errmsg);
513
514 va_end (ap);
515}
516