summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.in2
-rw-r--r--plugins/.cvsignore1
-rw-r--r--plugins/Makefile.am4
-rw-r--r--plugins/check_mysql_query.c299
-rw-r--r--plugins/t/check_mysql_query.t66
-rw-r--r--plugins/utils.h6
6 files changed, 376 insertions, 2 deletions
diff --git a/configure.in b/configure.in
index d56501ac..6a041852 100644
--- a/configure.in
+++ b/configure.in
@@ -287,7 +287,7 @@ fi
287if test "$ac_cv_lib_mysqlclient_mysql_init" = "yes" -o "$ac_cv_lib_mysqlclient_mysql_close" = "yes"; then 287if test "$ac_cv_lib_mysqlclient_mysql_init" = "yes" -o "$ac_cv_lib_mysqlclient_mysql_close" = "yes"; then
288 AC_CHECK_HEADERS(mysql/mysql.h mysql/errmsg.h, MYSQLINCLUDE="-I$MYSQL/include" ) 288 AC_CHECK_HEADERS(mysql/mysql.h mysql/errmsg.h, MYSQLINCLUDE="-I$MYSQL/include" )
289 if test "$ac_cv_header_mysql_mysql_h" = "yes" -a "$ac_cv_header_mysql_errmsg_h" = "yes"; then 289 if test "$ac_cv_header_mysql_mysql_h" = "yes" -a "$ac_cv_header_mysql_errmsg_h" = "yes"; then
290 EXTRAS="$EXTRAS check_mysql" 290 EXTRAS="$EXTRAS check_mysql check_mysql_query"
291 AC_SUBST(MYSQLINCLUDE) 291 AC_SUBST(MYSQLINCLUDE)
292 AC_SUBST(MYSQLLIBS) 292 AC_SUBST(MYSQLLIBS)
293 AC_SUBST(check_mysql_LDFLAGS) 293 AC_SUBST(check_mysql_LDFLAGS)
diff --git a/plugins/.cvsignore b/plugins/.cvsignore
index 66bad73e..7ac18354 100644
--- a/plugins/.cvsignore
+++ b/plugins/.cvsignore
@@ -31,6 +31,7 @@ check_pgsql
31check_radius 31check_radius
32check_ldap 32check_ldap
33check_mysql 33check_mysql
34check_mysql_query
34check_netsaint 35check_netsaint
35check_hpjd 36check_hpjd
36check_snmp 37check_snmp
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index a67911ce..70d0cf98 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -25,7 +25,7 @@ check_tcp_programs = check_ftp check_imap check_nntp check_pop \
25EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ 25EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
26 check_swap check_fping check_ldap check_game check_dig \ 26 check_swap check_fping check_ldap check_game check_dig \
27 check_nagios check_by_ssh check_dns check_nt check_ide_smart \ 27 check_nagios check_by_ssh check_dns check_nt check_ide_smart \
28 check_procs 28 check_procs check_mysql_query
29 29
30EXTRA_DIST = t utils.c netutils.c sslutils.c popen.c utils.h netutils.h \ 30EXTRA_DIST = t utils.c netutils.c sslutils.c popen.c utils.h netutils.h \
31 popen.h common.h getaddrinfo.c getaddrinfo.h \ 31 popen.h common.h getaddrinfo.c getaddrinfo.h \
@@ -64,6 +64,7 @@ check_load_LDADD = $(BASEOBJS) popen.o
64check_mrtg_LDADD = $(BASEOBJS) 64check_mrtg_LDADD = $(BASEOBJS)
65check_mrtgtraf_LDADD = $(BASEOBJS) 65check_mrtgtraf_LDADD = $(BASEOBJS)
66check_mysql_LDADD = $(NETLIBS) $(MYSQLLIBS) 66check_mysql_LDADD = $(NETLIBS) $(MYSQLLIBS)
67check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS)
67check_nagios_LDADD = $(BASEOBJS) runcmd.o 68check_nagios_LDADD = $(BASEOBJS) runcmd.o
68check_nt_LDADD = $(NETLIBS) 69check_nt_LDADD = $(NETLIBS)
69check_nwstat_LDADD = $(NETLIBS) 70check_nwstat_LDADD = $(NETLIBS)
@@ -101,6 +102,7 @@ check_load_DEPENDENCIES = check_load.c $(BASEOBJS) popen.o $(DEPLIBS)
101check_mrtg_DEPENDENCIES = check_mrtg.c $(DEPLIBS) 102check_mrtg_DEPENDENCIES = check_mrtg.c $(DEPLIBS)
102check_mrtgtraf_DEPENDENCIES = check_mrtgtraf.c $(DEPLIBS) 103check_mrtgtraf_DEPENDENCIES = check_mrtgtraf.c $(DEPLIBS)
103check_mysql_DEPENDENCIES = check_mysql.c $(NETOBJS) $(DEPLIBS) 104check_mysql_DEPENDENCIES = check_mysql.c $(NETOBJS) $(DEPLIBS)
105check_mysql_query_DEPENDENCIES = check_mysql.c $(NETOBJS) $(DEPLIBS)
104check_nagios_DEPENDENCIES = check_nagios.c $(BASEOBJS) runcmd.o $(DEPLIBS) 106check_nagios_DEPENDENCIES = check_nagios.c $(BASEOBJS) runcmd.o $(DEPLIBS)
105check_nt_DEPENDENCIES = check_nt.c $(NETOBJS) $(DEPLIBS) 107check_nt_DEPENDENCIES = check_nt.c $(NETOBJS) $(DEPLIBS)
106check_nwstat_DEPENDENCIES = check_nwstat.c $(NETOBJS) $(DEPLIBS) 108check_nwstat_DEPENDENCIES = check_nwstat.c $(NETOBJS) $(DEPLIBS)
diff --git a/plugins/check_mysql_query.c b/plugins/check_mysql_query.c
new file mode 100644
index 00000000..321af7aa
--- /dev/null
+++ b/plugins/check_mysql_query.c
@@ -0,0 +1,299 @@
1/******************************************************************************
2*
3* CHECK_MYSQL_QUERY.C
4*
5* Program: Mysql plugin for Nagios
6* License: GPL
7* Copyright (c) 2006 Nagios Plugins Team, after Didi Rieder (check_mysql)
8*
9* $Id$
10*
11* Description:
12* This plugin is for running arbitrary SQL and checking the results
13*
14******************************************************************************/
15
16const char *progname = "check_mysql_query";
17const char *revision = "$Revision$";
18const char *copyright = "2006";
19const char *email = "nagiosplug-devel@lists.sourceforge.net";
20
21#include "common.h"
22#include "utils.h"
23#include "netutils.h"
24
25#include <mysql/mysql.h>
26#include <mysql/errmsg.h>
27
28char *db_user = NULL;
29char *db_host = NULL;
30char *db_pass = NULL;
31char *db = NULL;
32unsigned int db_port = MYSQL_PORT;
33
34int process_arguments (int, char **);
35int validate_arguments (void);
36void print_help (void);
37void print_usage (void);
38
39char *sql_query = NULL;
40int verbose = 0;
41thresholds *my_thresholds = NULL;
42
43
44int
45main (int argc, char **argv)
46{
47
48 MYSQL mysql;
49 MYSQL_RES *res;
50 MYSQL_ROW row;
51
52 double value;
53 char *error = NULL;
54 int status;
55
56 setlocale (LC_ALL, "");
57 bindtextdomain (PACKAGE, LOCALEDIR);
58 textdomain (PACKAGE);
59
60 if (process_arguments (argc, argv) == ERROR)
61 usage4 (_("Could not parse arguments"));
62
63 /* initialize mysql */
64 mysql_init (&mysql);
65
66 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"client");
67
68 /* establish a connection to the server and error checking */
69 if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,NULL,0)) {
70 if (mysql_errno (&mysql) == CR_UNKNOWN_HOST)
71 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
72 else if (mysql_errno (&mysql) == CR_VERSION_ERROR)
73 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
74 else if (mysql_errno (&mysql) == CR_OUT_OF_MEMORY)
75 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
76 else if (mysql_errno (&mysql) == CR_IPSOCK_ERROR)
77 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
78 else if (mysql_errno (&mysql) == CR_SOCKET_CREATE_ERROR)
79 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql));
80 else
81 die (STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error (&mysql));
82 }
83
84 if (mysql_query (&mysql, sql_query) != 0) {
85 error = strdup(mysql_error(&mysql));
86 mysql_close (&mysql);
87 die (STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error);
88 }
89
90 /* store the result */
91 if ( (res = mysql_store_result (&mysql)) == NULL) {
92 error = strdup(mysql_error(&mysql));
93 mysql_close (&mysql);
94 die (STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error);
95 }
96
97 /* Check there is some data */
98 if (mysql_num_rows(res) == 0) {
99 mysql_close(&mysql);
100 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned"));
101 }
102
103 /* fetch the first row */
104 if ( (row = mysql_fetch_row (res)) == NULL) {
105 error = strdup(mysql_error(&mysql));
106 mysql_free_result (res);
107 mysql_close (&mysql);
108 die (STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error);
109 }
110
111 /* free the result */
112 mysql_free_result (res);
113
114 /* close the connection */
115 mysql_close (&mysql);
116
117 if (! is_numeric(row[0])) {
118 die (STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]);
119 }
120
121 value = strtod(row[0], NULL);
122
123 if (verbose >= 3)
124 printf("mysql result: %f\n", value);
125
126 status = get_status(value, my_thresholds);
127
128 if (status == STATE_OK) {
129 printf("QUERY %s: ", _("OK"));
130 } else if (status == STATE_WARNING) {
131 printf("QUERY %s: ", _("WARNING"));
132 } else if (status == STATE_CRITICAL) {
133 printf("QUERY %s: ", _("CRITICAL"));
134 }
135 printf(_("'%s' returned %f"), sql_query, value);
136 printf("\n");
137
138 return status;
139}
140
141
142/* process command-line arguments */
143int
144process_arguments (int argc, char **argv)
145{
146 int c;
147 char *warning = NULL;
148 char *critical = NULL;
149
150 int option = 0;
151 static struct option longopts[] = {
152 {"hostname", required_argument, 0, 'H'},
153 {"database", required_argument, 0, 'd'},
154 {"username", required_argument, 0, 'u'},
155 {"password", required_argument, 0, 'p'},
156 {"port", required_argument, 0, 'P'},
157 {"verbose", no_argument, 0, 'v'},
158 {"version", no_argument, 0, 'V'},
159 {"help", no_argument, 0, 'h'},
160 {"query", required_argument, 0, 'q'},
161 {"warning", required_argument, 0, 'w'},
162 {"critical", required_argument, 0, 'c'},
163 {0, 0, 0, 0}
164 };
165
166 if (argc < 1)
167 return ERROR;
168
169 while (1) {
170 c = getopt_long (argc, argv, "hvVSP:p:u:d:H:q:w:c:", longopts, &option);
171
172 if (c == -1 || c == EOF)
173 break;
174
175 switch (c) {
176 case 'H': /* hostname */
177 if (is_host (optarg)) {
178 db_host = optarg;
179 }
180 else {
181 usage2 (_("Invalid hostname/address"), optarg);
182 }
183 break;
184 case 'd': /* hostname */
185 db = optarg;
186 break;
187 case 'u': /* username */
188 db_user = optarg;
189 break;
190 case 'p': /* authentication information: password */
191 asprintf(&db_pass, "%s", optarg);
192
193 /* Delete the password from process list */
194 while (*optarg != '\0') {
195 *optarg = 'X';
196 optarg++;
197 }
198 break;
199 case 'P': /* critical time threshold */
200 db_port = atoi (optarg);
201 break;
202 case 'v':
203 verbose++;
204 break;
205 case 'V': /* version */
206 print_revision (progname, revision);
207 exit (STATE_OK);
208 case 'h': /* help */
209 print_help ();
210 exit (STATE_OK);
211 case 'q':
212 asprintf(&sql_query, "%s", optarg);
213 break;
214 case 'w':
215 warning = optarg;
216 break;
217 case 'c':
218 critical = optarg;
219 break;
220 case '?': /* help */
221 usage2 (_("Unknown argument"), optarg);
222 }
223 }
224
225 c = optind;
226
227 set_thresholds(&my_thresholds, warning, critical);
228
229 return validate_arguments ();
230}
231
232
233int
234validate_arguments (void)
235{
236 if (sql_query == NULL)
237 usage("Must specify a SQL query to run");
238
239 if (db_user == NULL)
240 db_user = strdup("");
241
242 if (db_host == NULL)
243 db_host = strdup("");
244
245 if (db_pass == NULL)
246 db_pass == strdup("");
247
248 if (db == NULL)
249 db = strdup("");
250
251 return OK;
252}
253
254
255void
256print_help (void)
257{
258 char *myport;
259 asprintf (&myport, "%d", MYSQL_PORT);
260
261 print_revision (progname, revision);
262
263 printf (_(COPYRIGHT), copyright, email);
264
265 printf ("%s\n", _("This program checks a query result against threshold levels"));
266
267 print_usage ();
268
269
270 printf (_(UT_HELP_VRSN));
271 printf (" -q, --query=STRING\n");
272 printf (" %s\n", _("SQL query to run. Only first column in first row will be read"));
273 printf (_(UT_WARN_CRIT_RANGE));
274 printf (_(UT_HOST_PORT), 'P', myport);
275 printf (" -d, --database=STRING\n");
276 printf (" %s\n", _("Database to check"));
277 printf (" -u, --username=STRING\n");
278 printf (" %s\n", _("Username to login with"));
279 printf (" -p, --password=STRING\n");
280 printf (" %s\n", _("Password to login with"));
281 printf (" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
282
283 printf ("\n");
284
285 printf ("%s\n", _("A query is required. The result from the query should be numeric."));
286 printf ("%s\n", _("For extra security, create a user with minimal access."));
287
288 printf (_(UT_SUPPORT));
289}
290
291
292void
293print_usage (void)
294{
295 printf ("\
296Usage: %s -q SQL_query [-w warn] [-c crit]\n\
297 [-d database] [-H host] [-P port] [-u user] [-p password]\n",
298 progname);
299}
diff --git a/plugins/t/check_mysql_query.t b/plugins/t/check_mysql_query.t
new file mode 100644
index 00000000..f4743b7b
--- /dev/null
+++ b/plugins/t/check_mysql_query.t
@@ -0,0 +1,66 @@
1#! /usr/bin/perl -w -I ..
2#
3# MySQL Database Server Tests via check_mysql
4#
5# $Id$
6#
7#
8# These are the database permissions required for this test:
9# GRANT SELECT ON $db.* TO $user@$host INDENTIFIED BY '$password';
10# Check with:
11# mysql -u$user -p$password -h$host $db
12
13use strict;
14use Test::More;
15use NPTest;
16
17use vars qw($tests);
18
19plan skip_all => "check_mysql_query not compiled" unless (-x "check_mysql_query");
20
21my $mysqlserver = getTestParameter(
22 "NP_MYSQL_SERVER",
23 "A MySQL Server with no slaves setup"
24 );
25my $mysql_login_details = getTestParameter(
26 "MYSQL_LOGIN_DETAILS",
27 "Command line parameters to specify login access",
28 "-u user -ppw -d db",
29 );
30my $result;
31
32if (! $mysqlserver) {
33 plan skip_all => "No mysql server defined";
34} else {
35 plan tests => 13;
36}
37
38$result = NPTest->testCmd("./check_mysql_query -q 'SELECT 1+1' -H $mysqlserver $mysql_login_details");
39cmp_ok( $result->return_code, '==', 0, "Can run query");
40
41$result = NPTest->testCmd("./check_mysql_query -H $mysqlserver $mysql_login_details");
42cmp_ok( $result->return_code, '==', 3, "Missing query parmeter");
43like( $result->output, "/Must specify a SQL query to run/", "Missing query error message");
44
45$result = NPTest->testCmd("./check_mysql_query -q 'SELECT 1+1' -H $mysqlserver -u dummy");
46cmp_ok( $result->return_code, '==', 2, "Login failure");
47like( $result->output, "/Access denied for user /", "Expected login failure message");
48
49$result = NPTest->testCmd("./check_mysql_query -q 'SELECT PI()' -w 3 -c 4 -H $mysqlserver $mysql_login_details");
50cmp_ok( $result->return_code, '==', 1, "Got warning");
51
52$result = NPTest->testCmd("./check_mysql_query -q 'SELECT PI()*2' -w 3 -c 4 -H $mysqlserver $mysql_login_details");
53cmp_ok( $result->return_code, '==', 2, "Got critical");
54
55$result = NPTest->testCmd("./check_mysql_query -q 'SELECT * FROM adsf' -H $mysqlserver $mysql_login_details");
56cmp_ok( $result->return_code, '==', 2, "Bad query");
57like( $result->output, "/Error with query/", "Bad query error message");
58
59$result = NPTest->testCmd("./check_mysql_query -q 'SHOW VARIABLES LIKE \"bob\"' -H $mysqlserver $mysql_login_details");
60cmp_ok( $result->return_code, '==', 1, "No rows");
61like( $result->output, "/No rows returned/", "No rows error message");
62
63$result = NPTest->testCmd("./check_mysql_query -q 'SHOW VARIABLES' -H $mysqlserver $mysql_login_details");
64cmp_ok( $result->return_code, '==', 2, "Data not numeric");
65like( $result->output, "/Is not a numeric/", "Data not numeric error message");
66
diff --git a/plugins/utils.h b/plugins/utils.h
index ffcb39da..2345ed56 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -181,6 +181,12 @@ char *fperfdata (const char *,
181 -c, --critical=DOUBLE\n\ 181 -c, --critical=DOUBLE\n\
182 Response time to result in critical status (seconds)\n" 182 Response time to result in critical status (seconds)\n"
183 183
184#define UT_WARN_CRIT_RANGE "\
185 -w, --warning=RANGE\n\
186 Warning range (format: start:end). Alert if outside this range\n\
187 -c, --critical=RANGE\n\
188 Critical range\n"
189
184#define UT_TIMEOUT "\ 190#define UT_TIMEOUT "\
185 -t, --timeout=INTEGER\n\ 191 -t, --timeout=INTEGER\n\
186 Seconds before connection times out (default: %d)\n" 192 Seconds before connection times out (default: %d)\n"