summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/Makefile.am2
-rw-r--r--plugins/check_dbi.c339
-rw-r--r--plugins/check_dbi.d/config.h63
3 files changed, 231 insertions, 173 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index d43c1971..a0e9cabf 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -46,7 +46,7 @@ SUBDIRS = picohttpparser
46 46
47np_test_scripts = tests/test_check_swap.t 47np_test_scripts = tests/test_check_swap.t
48 48
49EXTRA_DIST = t tests $(np_test_scripts) check_swap.d 49EXTRA_DIST = t tests $(np_test_scripts) check_swap.d check_dbi.d
50 50
51PLUGINHDRS = common.h 51PLUGINHDRS = common.h
52 52
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index ae8ec952..1f4a7def 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -33,6 +33,8 @@ const char *progname = "check_dbi";
33const char *copyright = "2011-2024"; 33const char *copyright = "2011-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "../lib/monitoringplug.h"
37#include "check_dbi.d/config.h"
36#include "common.h" 38#include "common.h"
37#include "utils.h" 39#include "utils.h"
38#include "utils_cmd.h" 40#include "utils_cmd.h"
@@ -53,55 +55,24 @@ const char *email = "devel@monitoring-plugins.org";
53 55
54#include <stdarg.h> 56#include <stdarg.h>
55 57
56typedef enum {
57 METRIC_CONN_TIME,
58 METRIC_SERVER_VERSION,
59 METRIC_QUERY_RESULT,
60 METRIC_QUERY_TIME,
61} np_dbi_metric_t;
62
63typedef enum {
64 TYPE_NUMERIC,
65 TYPE_STRING,
66} np_dbi_type_t;
67
68typedef struct {
69 char *key;
70 char *value;
71} driver_option_t;
72
73static char *host = NULL;
74static int verbose = 0; 58static int verbose = 0;
75 59
76static char *warning_range = NULL; 60typedef struct {
77static char *critical_range = NULL; 61 int errorcode;
78static thresholds *dbi_thresholds = NULL; 62 check_dbi_config config;
79 63} check_dbi_config_wrapper;
80static char *expect = NULL;
81
82static regex_t expect_re;
83static char *expect_re_str = NULL;
84static int expect_re_cflags = 0;
85
86static np_dbi_metric_t metric = METRIC_QUERY_RESULT;
87static np_dbi_type_t type = TYPE_NUMERIC;
88
89static char *np_dbi_driver = NULL;
90static driver_option_t *np_dbi_options = NULL;
91static int np_dbi_options_num = 0;
92static char *np_dbi_database = NULL;
93static char *np_dbi_query = NULL;
94 64
95static int process_arguments(int, char **); 65static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
96static int validate_arguments(void); 66static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/);
97void print_usage(void); 67void print_usage(void);
98static void print_help(void); 68static void print_help(void);
99 69
100static double timediff(struct timeval, struct timeval); 70static double timediff(struct timeval /*start*/, struct timeval /*end*/);
101 71
102static void np_dbi_print_error(dbi_conn, char *, ...); 72static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...);
103 73
104static int do_query(dbi_conn, const char **, double *, double *); 74static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/, double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/,
75 mp_dbi_type /*type*/, char * /*np_dbi_query*/);
105 76
106int main(int argc, char **argv) { 77int main(int argc, char **argv) {
107 int status = STATE_UNKNOWN; 78 int status = STATE_UNKNOWN;
@@ -119,8 +90,6 @@ int main(int argc, char **argv) {
119 const char *query_val_str = NULL; 90 const char *query_val_str = NULL;
120 double query_val = 0.0; 91 double query_val = 0.0;
121 92
122 int i;
123
124 setlocale(LC_ALL, ""); 93 setlocale(LC_ALL, "");
125 bindtextdomain(PACKAGE, LOCALEDIR); 94 bindtextdomain(PACKAGE, LOCALEDIR);
126 textdomain(PACKAGE); 95 textdomain(PACKAGE);
@@ -128,10 +97,14 @@ int main(int argc, char **argv) {
128 /* Parse extra opts if any */ 97 /* Parse extra opts if any */
129 argv = np_extra_opts(&argc, argv, progname); 98 argv = np_extra_opts(&argc, argv, progname);
130 99
131 if (process_arguments(argc, argv) == ERROR) { 100 check_dbi_config_wrapper tmp = process_arguments(argc, argv);
101
102 if (tmp.errorcode == ERROR) {
132 usage4(_("Could not parse arguments")); 103 usage4(_("Could not parse arguments"));
133 } 104 }
134 105
106 check_dbi_config config = tmp.config;
107
135 /* Set signal handling and alarm */ 108 /* Set signal handling and alarm */
136 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { 109 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
137 usage4(_("Cannot catch SIGALRM")); 110 usage4(_("Cannot catch SIGALRM"));
@@ -155,12 +128,12 @@ int main(int argc, char **argv) {
155 } 128 }
156 129
157 if (verbose) { 130 if (verbose) {
158 printf("Opening DBI driver '%s'\n", np_dbi_driver); 131 printf("Opening DBI driver '%s'\n", config.dbi_driver);
159 } 132 }
160 133
161 driver = dbi_driver_open_r(np_dbi_driver, instance_p); 134 driver = dbi_driver_open_r(config.dbi_driver, instance_p);
162 if (!driver) { 135 if (!driver) {
163 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", np_dbi_driver); 136 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver);
164 137
165 printf("Known drivers:\n"); 138 printf("Known drivers:\n");
166 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) { 139 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) {
@@ -179,19 +152,19 @@ int main(int argc, char **argv) {
179 return STATE_UNKNOWN; 152 return STATE_UNKNOWN;
180 } 153 }
181 154
182 for (i = 0; i < np_dbi_options_num; ++i) { 155 for (size_t i = 0; i < config.dbi_options_num; ++i) {
183 const char *opt; 156 const char *opt;
184 157
185 if (verbose > 1) { 158 if (verbose > 1) {
186 printf("Setting DBI driver option '%s' to '%s'\n", np_dbi_options[i].key, np_dbi_options[i].value); 159 printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key, config.dbi_options[i].value);
187 } 160 }
188 161
189 if (!dbi_conn_set_option(conn, np_dbi_options[i].key, np_dbi_options[i].value)) { 162 if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) {
190 continue; 163 continue;
191 } 164 }
192 /* else: status != 0 */ 165 /* else: status != 0 */
193 166
194 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", np_dbi_options[i].key, np_dbi_options[i].value); 167 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", config.dbi_options[i].key, config.dbi_options[i].value);
195 printf("Known driver options:\n"); 168 printf("Known driver options:\n");
196 169
197 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) { 170 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) {
@@ -201,11 +174,11 @@ int main(int argc, char **argv) {
201 return STATE_UNKNOWN; 174 return STATE_UNKNOWN;
202 } 175 }
203 176
204 if (host) { 177 if (config.host) {
205 if (verbose > 1) { 178 if (verbose > 1) {
206 printf("Setting DBI driver option 'host' to '%s'\n", host); 179 printf("Setting DBI driver option 'host' to '%s'\n", config.host);
207 } 180 }
208 dbi_conn_set_option(conn, "host", host); 181 dbi_conn_set_option(conn, "host", config.host);
209 } 182 }
210 183
211 if (verbose) { 184 if (verbose) {
@@ -238,48 +211,49 @@ int main(int argc, char **argv) {
238 printf("Connected to server version %u\n", server_version); 211 printf("Connected to server version %u\n", server_version);
239 } 212 }
240 213
241 if (metric == METRIC_SERVER_VERSION) { 214 if (config.metric == METRIC_SERVER_VERSION) {
242 status = get_status(server_version, dbi_thresholds); 215 status = get_status(server_version, config.dbi_thresholds);
243 } 216 }
244 217
245 if (verbose) { 218 if (verbose) {
246 printf("Time elapsed: %f\n", conn_time); 219 printf("Time elapsed: %f\n", conn_time);
247 } 220 }
248 221
249 if (metric == METRIC_CONN_TIME) { 222 if (config.metric == METRIC_CONN_TIME) {
250 status = get_status(conn_time, dbi_thresholds); 223 status = get_status(conn_time, config.dbi_thresholds);
251 } 224 }
252 225
253 /* select a database */ 226 /* select a database */
254 if (np_dbi_database) { 227 if (config.dbi_database) {
255 if (verbose > 1) { 228 if (verbose > 1) {
256 printf("Selecting database '%s'\n", np_dbi_database); 229 printf("Selecting database '%s'\n", config.dbi_database);
257 } 230 }
258 231
259 if (dbi_conn_select_db(conn, np_dbi_database)) { 232 if (dbi_conn_select_db(conn, config.dbi_database)) {
260 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", np_dbi_database); 233 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.dbi_database);
261 return STATE_UNKNOWN; 234 return STATE_UNKNOWN;
262 } 235 }
263 } 236 }
264 237
265 if (np_dbi_query) { 238 if (config.dbi_query) {
266 /* execute query */ 239 /* execute query */
267 status = do_query(conn, &query_val_str, &query_val, &query_time); 240 status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type, config.dbi_query);
268 if (status != STATE_OK) { 241 if (status != STATE_OK) {
269 /* do_query prints an error message in this case */ 242 /* do_query prints an error message in this case */
270 return status; 243 return status;
271 } 244 }
272 245
273 if (metric == METRIC_QUERY_RESULT) { 246 if (config.metric == METRIC_QUERY_RESULT) {
274 if (expect) { 247 if (config.expect) {
275 if ((!query_val_str) || strcmp(query_val_str, expect)) { 248 if ((!query_val_str) || strcmp(query_val_str, config.expect)) {
276 status = STATE_CRITICAL; 249 status = STATE_CRITICAL;
277 } else { 250 } else {
278 status = STATE_OK; 251 status = STATE_OK;
279 } 252 }
280 } else if (expect_re_str) { 253 } else if (config.expect_re_str) {
281 int err; 254 int err;
282 255
256 regex_t expect_re = {};
283 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0); 257 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
284 if (!err) { 258 if (!err) {
285 status = STATE_OK; 259 status = STATE_OK;
@@ -292,10 +266,10 @@ int main(int argc, char **argv) {
292 status = STATE_CRITICAL; 266 status = STATE_CRITICAL;
293 } 267 }
294 } else { 268 } else {
295 status = get_status(query_val, dbi_thresholds); 269 status = get_status(query_val, config.dbi_thresholds);
296 } 270 }
297 } else if (metric == METRIC_QUERY_TIME) { 271 } else if (config.metric == METRIC_QUERY_TIME) {
298 status = get_status(query_time, dbi_thresholds); 272 status = get_status(query_time, config.dbi_thresholds);
299 } 273 }
300 } 274 }
301 275
@@ -307,49 +281,48 @@ int main(int argc, char **argv) {
307 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error 281 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
308 * which should have been reported and handled (abort) before 282 * which should have been reported and handled (abort) before
309 * ... unless we expected a string to be returned */ 283 * ... unless we expected a string to be returned */
310 assert((metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (type == TYPE_STRING)); 284 assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (config.type == TYPE_STRING));
311 285
312 assert((type != TYPE_STRING) || (expect || expect_re_str)); 286 assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
313 287
314 printf("%s - connection time: %fs", state_text(status), conn_time); 288 printf("%s - connection time: %fs", state_text(status), conn_time);
315 if (np_dbi_query) { 289 if (config.dbi_query) {
316 if (type == TYPE_STRING) { 290 if (config.type == TYPE_STRING) {
317 assert(expect || expect_re_str); 291 assert(config.expect || config.expect_re_str);
318 printf(", '%s' returned '%s' in %fs", np_dbi_query, query_val_str ? query_val_str : "<nothing>", query_time); 292 printf(", '%s' returned '%s' in %fs", config.dbi_query, query_val_str ? query_val_str : "<nothing>", query_time);
319 if (status != STATE_OK) { 293 if (status != STATE_OK) {
320 if (expect) { 294 if (config.expect) {
321 printf(" (expected '%s')", expect); 295 printf(" (expected '%s')", config.expect);
322 } else if (expect_re_str) { 296 } else if (config.expect_re_str) {
323 printf(" (expected regex /%s/%s)", expect_re_str, ((expect_re_cflags & REG_ICASE) ? "i" : "")); 297 printf(" (expected regex /%s/%s)", config.expect_re_str, ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
324 } 298 }
325 } 299 }
326 } else if (isnan(query_val)) { 300 } else if (isnan(query_val)) {
327 printf(", '%s' query execution time: %fs", np_dbi_query, query_time); 301 printf(", '%s' query execution time: %fs", config.dbi_query, query_time);
328 } else { 302 } else {
329 printf(", '%s' returned %f in %fs", np_dbi_query, query_val, query_time); 303 printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time);
330 } 304 }
331 } 305 }
332 306
333 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, 307 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
334 ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "", 308 ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
335 ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "", server_version, 309 ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", server_version,
336 ((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "", 310 ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range : "",
337 ((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : ""); 311 ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range : "");
338 if (np_dbi_query) { 312 if (config.dbi_query) {
339 if (!isnan(query_val)) { /* this is also true when -e is used */ 313 if (!isnan(query_val)) { /* this is also true when -e is used */
340 printf(" query=%f;%s;%s;;", query_val, ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "", 314 printf(" query=%f;%s;%s;;", query_val, ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) ? config.warning_range : "",
341 ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : ""); 315 ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) ? config.critical_range : "");
342 } 316 }
343 printf(" querytime=%fs;%s;%s;0;", query_time, ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "", 317 printf(" querytime=%fs;%s;%s;0;", query_time, ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range : "",
344 ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : ""); 318 ((config.metric == METRIC_QUERY_TIME) && config.critical_range) ? config.critical_range : "");
345 } 319 }
346 printf("\n"); 320 printf("\n");
347 return status; 321 return status;
348} 322}
349 323
350/* process command-line arguments */ 324/* process command-line arguments */
351int process_arguments(int argc, char **argv) { 325check_dbi_config_wrapper process_arguments(int argc, char **argv) {
352 int c;
353 326
354 int option = 0; 327 int option = 0;
355 static struct option longopts[] = {STD_LONG_OPTS, 328 static struct option longopts[] = {STD_LONG_OPTS,
@@ -364,14 +337,19 @@ int process_arguments(int argc, char **argv) {
364 {"database", required_argument, 0, 'D'}, 337 {"database", required_argument, 0, 'D'},
365 {0, 0, 0, 0}}; 338 {0, 0, 0, 0}};
366 339
367 while (1) { 340 check_dbi_config_wrapper result = {
368 c = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option); 341 .config = check_dbi_config_init(),
342 .errorcode = OK,
343 };
344 int option_char;
345 while (true) {
346 option_char = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option);
369 347
370 if (c == EOF) { 348 if (option_char == EOF) {
371 break; 349 break;
372 } 350 }
373 351
374 switch (c) { 352 switch (option_char) {
375 case '?': /* usage */ 353 case '?': /* usage */
376 usage5(); 354 usage5();
377 case 'h': /* help */ 355 case 'h': /* help */
@@ -382,46 +360,49 @@ int process_arguments(int argc, char **argv) {
382 exit(STATE_UNKNOWN); 360 exit(STATE_UNKNOWN);
383 361
384 case 'c': /* critical range */ 362 case 'c': /* critical range */
385 critical_range = optarg; 363 result.config.critical_range = optarg;
386 type = TYPE_NUMERIC; 364 result.config.type = TYPE_NUMERIC;
387 break; 365 break;
388 case 'w': /* warning range */ 366 case 'w': /* warning range */
389 warning_range = optarg; 367 result.config.warning_range = optarg;
390 type = TYPE_NUMERIC; 368 result.config.type = TYPE_NUMERIC;
391 break; 369 break;
392 case 'e': 370 case 'e':
393 expect = optarg; 371 result.config.expect = optarg;
394 type = TYPE_STRING; 372 result.config.type = TYPE_STRING;
395 break; 373 break;
396 case 'R': 374 case 'R':
397 expect_re_cflags = REG_ICASE; 375 result.config.expect_re_cflags = REG_ICASE;
398 /* fall through */ 376 /* fall through */
399 case 'r': { 377 case 'r': {
400 int err; 378 int err;
401 379
402 expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 380 result.config.expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
403 expect_re_str = optarg; 381 result.config.expect_re_str = optarg;
404 type = TYPE_STRING; 382 result.config.type = TYPE_STRING;
405 383
406 err = regcomp(&expect_re, expect_re_str, expect_re_cflags); 384 regex_t expect_re = {};
385 err = regcomp(&expect_re, result.config.expect_re_str, result.config.expect_re_cflags);
407 if (err) { 386 if (err) {
408 char errmsg[1024]; 387 char errmsg[1024];
409 regerror(err, &expect_re, errmsg, sizeof(errmsg)); 388 regerror(err, &expect_re, errmsg, sizeof(errmsg));
410 printf("ERROR - failed to compile regular expression: %s\n", errmsg); 389 printf("ERROR - failed to compile regular expression: %s\n", errmsg);
411 return ERROR; 390
391 result.errorcode = ERROR;
392 return result;
412 } 393 }
413 break; 394 break;
414 } 395 }
415 396
416 case 'm': 397 case 'm':
417 if (!strcasecmp(optarg, "CONN_TIME")) { 398 if (!strcasecmp(optarg, "CONN_TIME")) {
418 metric = METRIC_CONN_TIME; 399 result.config.metric = METRIC_CONN_TIME;
419 } else if (!strcasecmp(optarg, "SERVER_VERSION")) { 400 } else if (!strcasecmp(optarg, "SERVER_VERSION")) {
420 metric = METRIC_SERVER_VERSION; 401 result.config.metric = METRIC_SERVER_VERSION;
421 } else if (!strcasecmp(optarg, "QUERY_RESULT")) { 402 } else if (!strcasecmp(optarg, "QUERY_RESULT")) {
422 metric = METRIC_QUERY_RESULT; 403 result.config.metric = METRIC_QUERY_RESULT;
423 } else if (!strcasecmp(optarg, "QUERY_TIME")) { 404 } else if (!strcasecmp(optarg, "QUERY_TIME")) {
424 metric = METRIC_QUERY_TIME; 405 result.config.metric = METRIC_QUERY_TIME;
425 } else { 406 } else {
426 usage2(_("Invalid metric"), optarg); 407 usage2(_("Invalid metric"), optarg);
427 } 408 }
@@ -438,7 +419,7 @@ int process_arguments(int argc, char **argv) {
438 if (!is_host(optarg)) { 419 if (!is_host(optarg)) {
439 usage2(_("Invalid hostname/address"), optarg); 420 usage2(_("Invalid hostname/address"), optarg);
440 } else { 421 } else {
441 host = optarg; 422 result.config.host = optarg;
442 } 423 }
443 break; 424 break;
444 case 'v': 425 case 'v':
@@ -446,82 +427,81 @@ int process_arguments(int argc, char **argv) {
446 break; 427 break;
447 428
448 case 'd': 429 case 'd':
449 np_dbi_driver = optarg; 430 result.config.dbi_driver = optarg;
450 break; 431 break;
451 case 'o': { 432 case 'o': {
452 driver_option_t *new; 433 driver_option_t *new = NULL;
453 434
454 char *k; 435 char *key = optarg;
455 char *v; 436 char *value = strchr(key, '=');
456 437
457 k = optarg; 438 if (!value) {
458 v = strchr(k, (int)'=');
459
460 if (!v) {
461 usage2(_("Option must be '<key>=<value>'"), optarg); 439 usage2(_("Option must be '<key>=<value>'"), optarg);
462 } 440 }
463 441
464 *v = '\0'; 442 *value = '\0';
465 ++v; 443 ++value;
466 444
467 new = realloc(np_dbi_options, (np_dbi_options_num + 1) * sizeof(*new)); 445 new = realloc(result.config.dbi_options, (result.config.dbi_options_num + 1) * sizeof(*new));
468 if (!new) { 446 if (!new) {
469 printf("UNKNOWN - failed to reallocate memory\n"); 447 printf("UNKNOWN - failed to reallocate memory\n");
470 exit(STATE_UNKNOWN); 448 exit(STATE_UNKNOWN);
471 } 449 }
472 450
473 np_dbi_options = new; 451 result.config.dbi_options = new;
474 new = np_dbi_options + np_dbi_options_num; 452 new = result.config.dbi_options + result.config.dbi_options_num;
475 ++np_dbi_options_num; 453 result.config.dbi_options_num++;
476 454
477 new->key = k; 455 new->key = key;
478 new->value = v; 456 new->value = value;
479 } break; 457 } break;
480 case 'q': 458 case 'q':
481 np_dbi_query = optarg; 459 result.config.dbi_query = optarg;
482 break; 460 break;
483 case 'D': 461 case 'D':
484 np_dbi_database = optarg; 462 result.config.dbi_database = optarg;
485 break; 463 break;
486 } 464 }
487 } 465 }
488 466
489 set_thresholds(&dbi_thresholds, warning_range, critical_range); 467 set_thresholds(&result.config.dbi_thresholds, result.config.warning_range, result.config.critical_range);
490 468
491 return validate_arguments(); 469 return validate_arguments(result);
492} 470}
493 471
494int validate_arguments(void) { 472check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) {
495 if (!np_dbi_driver) { 473 if (!config_wrapper.config.dbi_driver) {
496 usage("Must specify a DBI driver"); 474 usage("Must specify a DBI driver");
497 } 475 }
498 476
499 if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME)) && (!np_dbi_query)) { 477 if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) || (config_wrapper.config.metric == METRIC_QUERY_TIME)) &&
478 (!config_wrapper.config.dbi_query)) {
500 usage("Must specify a query to execute (metric == QUERY_RESULT)"); 479 usage("Must specify a query to execute (metric == QUERY_RESULT)");
501 } 480 }
502 481
503 if ((metric != METRIC_CONN_TIME) && (metric != METRIC_SERVER_VERSION) && (metric != METRIC_QUERY_RESULT) && 482 if ((config_wrapper.config.metric != METRIC_CONN_TIME) && (config_wrapper.config.metric != METRIC_SERVER_VERSION) &&
504 (metric != METRIC_QUERY_TIME)) { 483 (config_wrapper.config.metric != METRIC_QUERY_RESULT) && (config_wrapper.config.metric != METRIC_QUERY_TIME)) {
505 usage("Invalid metric specified"); 484 usage("Invalid metric specified");
506 } 485 }
507 486
508 if (expect && (warning_range || critical_range || expect_re_str)) { 487 if (config_wrapper.config.expect && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect_re_str)) {
509 usage("Do not mix -e and -w/-c/-r/-R"); 488 usage("Do not mix -e and -w/-c/-r/-R");
510 } 489 }
511 490
512 if (expect_re_str && (warning_range || critical_range || expect)) { 491 if (config_wrapper.config.expect_re_str && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect)) {
513 usage("Do not mix -r/-R and -w/-c/-e"); 492 usage("Do not mix -r/-R and -w/-c/-e");
514 } 493 }
515 494
516 if (expect && (metric != METRIC_QUERY_RESULT)) { 495 if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
517 usage("Option -e requires metric QUERY_RESULT"); 496 usage("Option -e requires metric QUERY_RESULT");
518 } 497 }
519 498
520 if (expect_re_str && (metric != METRIC_QUERY_RESULT)) { 499 if (config_wrapper.config.expect_re_str && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
521 usage("Options -r/-R require metric QUERY_RESULT"); 500 usage("Options -r/-R require metric QUERY_RESULT");
522 } 501 }
523 502
524 return OK; 503 config_wrapper.errorcode = OK;
504 return config_wrapper;
525} 505}
526 506
527void print_help(void) { 507void print_help(void) {
@@ -551,6 +531,8 @@ void print_help(void) {
551 printf(" %s\n", _("DBI driver options")); 531 printf(" %s\n", _("DBI driver options"));
552 printf(" %s\n", "-q, --query=STRING"); 532 printf(" %s\n", "-q, --query=STRING");
553 printf(" %s\n", _("query to execute")); 533 printf(" %s\n", _("query to execute"));
534 printf(" %s\n", "-H STRING");
535 printf(" %s\n", _("target database host"));
554 printf("\n"); 536 printf("\n");
555 537
556 printf(UT_WARN_CRIT_RANGE); 538 printf(UT_WARN_CRIT_RANGE);
@@ -625,13 +607,7 @@ void print_usage(void) {
625 printf(" [-e <string>] [-r|-R <regex>]\n"); 607 printf(" [-e <string>] [-r|-R <regex>]\n");
626} 608}
627 609
628#define CHECK_IGNORE_ERROR(s) \ 610const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type, mp_dbi_metric metric, mp_dbi_type type) {
629 do { \
630 if (metric != METRIC_QUERY_RESULT) \
631 return (s); \
632 } while (0)
633
634const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type) {
635 const char *str; 611 const char *str;
636 612
637 if (field_type != DBI_TYPE_STRING) { 613 if (field_type != DBI_TYPE_STRING) {
@@ -641,7 +617,9 @@ const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_ty
641 617
642 str = dbi_result_get_string_idx(res, 1); 618 str = dbi_result_get_string_idx(res, 1);
643 if ((!str) || (strcmp(str, "ERROR") == 0)) { 619 if ((!str) || (strcmp(str, "ERROR") == 0)) {
644 CHECK_IGNORE_ERROR(NULL); 620 if (metric != METRIC_QUERY_RESULT) {
621 return NULL;
622 }
645 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value"); 623 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value");
646 return NULL; 624 return NULL;
647 } 625 }
@@ -652,7 +630,7 @@ const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_ty
652 return str; 630 return str;
653} 631}
654 632
655double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) { 633double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, mp_dbi_type type) {
656 double val = NAN; 634 double val = NAN;
657 635
658 if (*field_type == DBI_TYPE_INTEGER) { 636 if (*field_type == DBI_TYPE_INTEGER) {
@@ -663,16 +641,20 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
663 const char *val_str; 641 const char *val_str;
664 char *endptr = NULL; 642 char *endptr = NULL;
665 643
666 val_str = get_field_str(conn, res, *field_type); 644 val_str = get_field_str(conn, res, *field_type, metric, type);
667 if (!val_str) { 645 if (!val_str) {
668 CHECK_IGNORE_ERROR(NAN); 646 if (metric != METRIC_QUERY_RESULT) {
647 return NAN;
648 }
669 *field_type = DBI_TYPE_ERROR; 649 *field_type = DBI_TYPE_ERROR;
670 return NAN; 650 return NAN;
671 } 651 }
672 652
673 val = strtod(val_str, &endptr); 653 val = strtod(val_str, &endptr);
674 if (endptr == val_str) { 654 if (endptr == val_str) {
675 CHECK_IGNORE_ERROR(NAN); 655 if (metric != METRIC_QUERY_RESULT) {
656 return NAN;
657 }
676 printf("CRITICAL - result value is not a numeric: %s\n", val_str); 658 printf("CRITICAL - result value is not a numeric: %s\n", val_str);
677 *field_type = DBI_TYPE_ERROR; 659 *field_type = DBI_TYPE_ERROR;
678 return NAN; 660 return NAN;
@@ -683,7 +665,9 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
683 } 665 }
684 } 666 }
685 } else { 667 } else {
686 CHECK_IGNORE_ERROR(NAN); 668 if (metric != METRIC_QUERY_RESULT) {
669 return NAN;
670 }
687 printf("CRITICAL - cannot parse value of type %s (%i)\n", 671 printf("CRITICAL - cannot parse value of type %s (%i)\n",
688 (*field_type == DBI_TYPE_BINARY) ? "BINARY" 672 (*field_type == DBI_TYPE_BINARY) ? "BINARY"
689 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME" 673 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME"
@@ -695,36 +679,46 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
695 return val; 679 return val;
696} 680}
697 681
698double get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val) { 682mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val, mp_dbi_metric metric, mp_dbi_type type) {
699 unsigned short field_type; 683 unsigned short field_type;
700 double val = NAN; 684 double val = NAN;
701 685
702 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) { 686 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
703 CHECK_IGNORE_ERROR(STATE_OK); 687 if (metric != METRIC_QUERY_RESULT) {
688 return STATE_OK;
689 }
704 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows"); 690 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows");
705 return STATE_CRITICAL; 691 return STATE_CRITICAL;
706 } 692 }
707 693
708 if (dbi_result_get_numrows(res) < 1) { 694 if (dbi_result_get_numrows(res) < 1) {
709 CHECK_IGNORE_ERROR(STATE_OK); 695 if (metric != METRIC_QUERY_RESULT) {
696 return STATE_OK;
697 }
710 printf("WARNING - no rows returned\n"); 698 printf("WARNING - no rows returned\n");
711 return STATE_WARNING; 699 return STATE_WARNING;
712 } 700 }
713 701
714 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) { 702 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
715 CHECK_IGNORE_ERROR(STATE_OK); 703 if (metric != METRIC_QUERY_RESULT) {
704 return STATE_OK;
705 }
716 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields"); 706 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
717 return STATE_CRITICAL; 707 return STATE_CRITICAL;
718 } 708 }
719 709
720 if (dbi_result_get_numfields(res) < 1) { 710 if (dbi_result_get_numfields(res) < 1) {
721 CHECK_IGNORE_ERROR(STATE_OK); 711 if (metric != METRIC_QUERY_RESULT) {
712 return STATE_OK;
713 }
722 printf("WARNING - no fields returned\n"); 714 printf("WARNING - no fields returned\n");
723 return STATE_WARNING; 715 return STATE_WARNING;
724 } 716 }
725 717
726 if (dbi_result_first_row(res) != 1) { 718 if (dbi_result_first_row(res) != 1) {
727 CHECK_IGNORE_ERROR(STATE_OK); 719 if (metric != METRIC_QUERY_RESULT) {
720 return STATE_OK;
721 }
728 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row"); 722 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
729 return STATE_CRITICAL; 723 return STATE_CRITICAL;
730 } 724 }
@@ -733,16 +727,18 @@ double get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str,
733 if (field_type != DBI_TYPE_ERROR) { 727 if (field_type != DBI_TYPE_ERROR) {
734 if (type == TYPE_STRING) { 728 if (type == TYPE_STRING) {
735 /* the value will be freed in dbi_result_free */ 729 /* the value will be freed in dbi_result_free */
736 *res_val_str = strdup(get_field_str(conn, res, field_type)); 730 *res_val_str = strdup(get_field_str(conn, res, field_type, metric, type));
737 } else { 731 } else {
738 val = get_field(conn, res, &field_type); 732 val = get_field(conn, res, &field_type, metric, type);
739 } 733 }
740 } 734 }
741 735
742 *res_val = val; 736 *res_val = val;
743 737
744 if (field_type == DBI_TYPE_ERROR) { 738 if (field_type == DBI_TYPE_ERROR) {
745 CHECK_IGNORE_ERROR(STATE_OK); 739 if (metric != METRIC_QUERY_RESULT) {
740 return STATE_OK;
741 }
746 np_dbi_print_error(conn, "CRITICAL - failed to fetch data"); 742 np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
747 return STATE_CRITICAL; 743 return STATE_CRITICAL;
748 } 744 }
@@ -751,14 +747,13 @@ double get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str,
751 return STATE_OK; 747 return STATE_OK;
752} 748}
753 749
754#undef CHECK_IGNORE_ERROR 750mp_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,
755 751 char *np_dbi_query) {
756int do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time) {
757 dbi_result res; 752 dbi_result res;
758 753
759 struct timeval timeval_start; 754 struct timeval timeval_start;
760 struct timeval timeval_end; 755 struct timeval timeval_end;
761 int status = STATE_OK; 756 mp_state_enum status = STATE_OK;
762 757
763 assert(np_dbi_query); 758 assert(np_dbi_query);
764 759
@@ -774,7 +769,7 @@ int do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *r
774 return STATE_CRITICAL; 769 return STATE_CRITICAL;
775 } 770 }
776 771
777 status = get_query_result(conn, res, res_val_str, res_val); 772 status = get_query_result(conn, res, res_val_str, res_val, metric, type);
778 773
779 gettimeofday(&timeval_end, NULL); 774 gettimeofday(&timeval_end, NULL);
780 *res_time = timediff(timeval_start, timeval_end); 775 *res_time = timediff(timeval_start, timeval_end);
diff --git a/plugins/check_dbi.d/config.h b/plugins/check_dbi.d/config.h
new file mode 100644
index 00000000..f6f0d7b3
--- /dev/null
+++ b/plugins/check_dbi.d/config.h
@@ -0,0 +1,63 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include "../../lib/monitoringplug.h"
6
7typedef enum {
8 METRIC_CONN_TIME,
9 METRIC_SERVER_VERSION,
10 METRIC_QUERY_RESULT,
11 METRIC_QUERY_TIME,
12} mp_dbi_metric;
13
14typedef enum {
15 TYPE_NUMERIC,
16 TYPE_STRING,
17} mp_dbi_type;
18
19typedef struct {
20 char *key;
21 char *value;
22} driver_option_t;
23
24typedef struct {
25 char *dbi_driver;
26 char *host;
27 driver_option_t *dbi_options;
28 size_t dbi_options_num;
29 char *dbi_database;
30 char *dbi_query;
31
32 char *expect;
33 char *expect_re_str;
34 int expect_re_cflags;
35 mp_dbi_metric metric;
36 mp_dbi_type type;
37 char *warning_range;
38 char *critical_range;
39 thresholds *dbi_thresholds;
40
41} check_dbi_config;
42
43check_dbi_config check_dbi_config_init() {
44 check_dbi_config tmp = {
45 .dbi_driver = NULL,
46 .host = NULL,
47 .dbi_options = NULL,
48 .dbi_options_num = 0,
49 .dbi_database = NULL,
50 .dbi_query = NULL,
51
52 .expect = NULL,
53 .expect_re_str = NULL,
54 .expect_re_cflags = 0,
55 .metric = METRIC_QUERY_RESULT,
56 .type = TYPE_NUMERIC,
57
58 .warning_range = NULL,
59 .critical_range = NULL,
60 .dbi_thresholds = NULL,
61 };
62 return tmp;
63}