X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fcollectd-nagios.c;h=29e34a4ce5a413c4af48037aade685fb1616b267;hb=b8f83ce0a28e0d8033c0f3bdc95aeb44a2d17381;hp=1bf5b3f3dc6061be372aa725d5766dbc7283fe64;hpb=b9f818d0e8f2ce608e491f0ee0ba4024a2694101;p=collectd.git diff --git a/src/collectd-nagios.c b/src/collectd-nagios.c index 1bf5b3f3..29e34a4c 100644 --- a/src/collectd-nagios.c +++ b/src/collectd-nagios.c @@ -1,15 +1,45 @@ -#include "config.h" +/** + * collectd-nagios - src/collectd-nagios.c + * Copyright (C) 2008 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#if !defined(__GNUC__) || !__GNUC__ +# define __attribute__(x) /**/ +#endif #include #include #include #include #include +#include #include #include #include +#include "libcollectdclient/client.h" + /* * This is copied directly from collectd.h. Make changes there! */ @@ -46,6 +76,7 @@ #define CON_NONE 0 #define CON_AVERAGE 1 #define CON_SUM 2 +#define CON_PERCENTAGE 3 struct range_s { @@ -69,19 +100,91 @@ static int consolitation_g = CON_NONE; static char **match_ds_g = NULL; static int match_ds_num_g = 0; -static int ignore_ds (const char *name) +/* `strdup' is an XSI extension. I don't want to pull in all of XSI just for + * that, so here's an own implementation.. It's easy enough. The GCC attributes + * are supposed to get good performance.. -octo */ +__attribute__((malloc, nonnull (1))) +static char *cn_strdup (const char *str) /* {{{ */ +{ + size_t strsize; + char *ret; + + strsize = strlen (str) + 1; + ret = (char *) malloc (strsize); + if (ret != NULL) + memcpy (ret, str, strsize); + return (ret); +} /* }}} char *cn_strdup */ + +static int filter_ds (size_t *values_num, + double **values, char ***values_names) { - int i; + gauge_t *new_values; + char **new_names; + + size_t i; if (match_ds_g == NULL) - return (0); + return (RET_OKAY); - for (i = 0; i < match_ds_num_g; i++) - if (strcasecmp (match_ds_g[i], name) == 0) - return (0); + new_values = (gauge_t *)calloc (match_ds_num_g, sizeof (*new_values)); + if (new_values == NULL) + { + fprintf (stderr, "malloc failed: %s\n", strerror (errno)); + return (RET_UNKNOWN); + } + + new_names = (char **)calloc (match_ds_num_g, sizeof (*new_names)); + if (new_names == NULL) + { + fprintf (stderr, "malloc failed: %s\n", strerror (errno)); + free (new_values); + return (RET_UNKNOWN); + } + + for (i = 0; i < (size_t) match_ds_num_g; i++) + { + size_t j; + + /* match_ds_g keeps pointers into argv but the names will be freed */ + new_names[i] = cn_strdup (match_ds_g[i]); + if (new_names[i] == NULL) + { + fprintf (stderr, "cn_strdup failed: %s\n", strerror (errno)); + free (new_values); + for (j = 0; j < i; j++) + free (new_names[j]); + free (new_names); + return (RET_UNKNOWN); + } + + for (j = 0; j < *values_num; j++) + if (strcasecmp (new_names[i], (*values_names)[j]) == 0) + break; + + if (j == *values_num) + { + printf ("ERROR: DS `%s' is not available.\n", new_names[i]); + free (new_values); + for (j = 0; j <= i; j++) + free (new_names[j]); + free (new_names); + return (RET_CRITICAL); + } + + new_values[i] = (*values)[j]; + } - return (1); -} /* int ignore_ds */ + free (*values); + for (i = 0; i < *values_num; i++) + free ((*values_names)[i]); + free (*values_names); + + *values = new_values; + *values_names = new_names; + *values_num = match_ds_num_g; + return (RET_OKAY); +} /* int filter_ds */ static void parse_range (char *string, range_t *range) { @@ -124,7 +227,7 @@ static void parse_range (char *string, range_t *range) range->max = atof (max_ptr); } /* void parse_range */ -int match_range (range_t *range, double value) +static int match_range (range_t *range, double value) { int ret = 0; @@ -134,136 +237,7 @@ int match_range (range_t *range, double value) ret = 1; return (((ret - range->invert) == 0) ? 0 : 1); -} - -static int get_values (int *ret_values_num, double **ret_values, - char ***ret_values_names) -{ - struct sockaddr_un sa; - int status; - int fd; - FILE *fh_in, *fh_out; - char buffer[4096]; - - int values_num; - double *values; - char **values_names; - - int i; - - fd = socket (PF_UNIX, SOCK_STREAM, 0); - if (fd < 0) - { - fprintf (stderr, "socket failed: %s\n", - strerror (errno)); - return (-1); - } - - memset (&sa, '\0', sizeof (sa)); - sa.sun_family = AF_UNIX; - strncpy (sa.sun_path, socket_file_g, - sizeof (sa.sun_path) - 1); - - status = connect (fd, (struct sockaddr *) &sa, sizeof (sa)); - if (status != 0) - { - fprintf (stderr, "connect failed: %s\n", - strerror (errno)); - return (-1); - } - - fh_in = fdopen (fd, "r"); - if (fh_in == NULL) - { - fprintf (stderr, "fdopen failed: %s\n", - strerror (errno)); - close (fd); - return (-1); - } - - fh_out = fdopen (fd, "w"); - if (fh_out == NULL) - { - fprintf (stderr, "fdopen failed: %s\n", - strerror (errno)); - fclose (fh_in); - return (-1); - } - - fprintf (fh_out, "GETVAL %s/%s\n", hostname_g, value_string_g); - fflush (fh_out); - - if (fgets (buffer, sizeof (buffer), fh_in) == NULL) - { - fprintf (stderr, "fgets failed: %s\n", - strerror (errno)); - fclose (fh_in); - fclose (fh_out); - return (-1); - } - - { - char *ptr = strchr (buffer, ' '); - - if (ptr != NULL) - *ptr = '\0'; - - values_num = atoi (buffer); - if (values_num < 1) - return (-1); - } - - values = (double *) malloc (values_num * sizeof (double)); - if (values == NULL) - { - fprintf (stderr, "malloc failed: %s\n", - strerror (errno)); - return (-1); - } - - values_names = (char **) malloc (values_num * sizeof (char *)); - if (values_names == NULL) - { - fprintf (stderr, "malloc failed: %s\n", - strerror (errno)); - free (values); - return (-1); - } - - i = 0; - while (fgets (buffer, sizeof (buffer), fh_in) != NULL) - { - char *key; - char *value; - - key = buffer; - - value = strchr (key, '='); - if (value == NULL) - continue; - *value = '\0'; value++; - - if (ignore_ds (key) != 0) - continue; - - values_names[i] = strdup (key); - values[i] = atof (value); - - i++; - if (i >= values_num) - break; - } - values_num = i; - - fclose (fh_in); fh_in = NULL; fd = -1; - fclose (fh_out); fh_out = NULL; - - *ret_values_num = values_num; - *ret_values = values; - *ret_values_names = values_names; - - return (0); -} /* int get_values */ +} /* int match_range */ static void usage (const char *name) { @@ -276,7 +250,7 @@ static void usage (const char *name) " -d Select the DS to examine. May be repeated to examine multiple\n" " DSes. By default all DSes are used.\n" " -g Method to use to consolidate several DSes.\n" - " Valid arguments are `none', `average' and `sum'\n" + " See below for a list of valid arguments.\n" " -H Hostname to query the values for.\n" " -c Critical range\n" " -w Warning range\n" @@ -287,17 +261,21 @@ static void usage (const char *name) " average: Calculate the average of all matching DSes and apply the\n" " warning- and critical-ranges to the calculated average.\n" " sum: Apply the ranges to the sum of all DSes.\n" + " percentage: Apply the ranges to the ratio (in percent) of the first value\n" + " and the sum of all values." "\n", name); exit (1); } /* void usage */ -int do_check_con_none (int values_num, double *values, char **values_names) +static int do_check_con_none (size_t values_num, + double *values, char **values_names) { - int i; - int num_critical = 0; int num_warning = 0; int num_okay = 0; + const char *status_str = "UNKNOWN"; + int status_code = RET_UNKNOWN; + size_t i; for (i = 0; i < values_num; i++) { @@ -311,30 +289,49 @@ int do_check_con_none (int values_num, double *values, char **values_names) num_okay++; } - printf ("%i critical, %i warning, %i okay", + if ((num_critical == 0) && (num_warning == 0) && (num_okay == 0)) + { + printf ("WARNING: No defined values found\n"); + return (RET_WARNING); + } + else if ((num_critical == 0) && (num_warning == 0)) + { + status_str = "OKAY"; + status_code = RET_OKAY; + } + else if (num_critical == 0) + { + status_str = "WARNING"; + status_code = RET_WARNING; + } + else + { + status_str = "CRITICAL"; + status_code = RET_CRITICAL; + } + + printf ("%s: %i critical, %i warning, %i okay", status_str, num_critical, num_warning, num_okay); if (values_num > 0) { printf (" |"); for (i = 0; i < values_num; i++) - printf (" %s=%lf;;;;", values_names[i], values[i]); + printf (" %s=%g;;;;", values_names[i], values[i]); } printf ("\n"); - if ((num_critical != 0) || (values_num == 0)) - return (RET_CRITICAL); - else if (num_warning != 0) - return (RET_WARNING); - - return (RET_OKAY); + return (status_code); } /* int do_check_con_none */ -int do_check_con_average (int values_num, double *values, char **values_names) +static int do_check_con_average (size_t values_num, + double *values, char **values_names) { - int i; + size_t i; double total; int total_num; double average; + const char *status_str = "UNKNOWN"; + int status_code = RET_UNKNOWN; total = 0.0; total_num = 0; @@ -348,30 +345,45 @@ int do_check_con_average (int values_num, double *values, char **values_names) } if (total_num == 0) - average = NAN; - else - average = total / total_num; - printf ("%lf average |", average); - for (i = 0; i < values_num; i++) - printf (" %s=%lf;;;;", values_names[i], values[i]); - - if (total_num == 0) + { + printf ("WARNING: No defined values found\n"); return (RET_WARNING); + } - if (isnan (average) - || match_range (&range_critical_g, average)) - return (RET_CRITICAL); + average = total / total_num; + + if (match_range (&range_critical_g, average) != 0) + { + status_str = "CRITICAL"; + status_code = RET_CRITICAL; + } else if (match_range (&range_warning_g, average) != 0) - return (RET_WARNING); + { + status_str = "WARNING"; + status_code = RET_WARNING; + } + else + { + status_str = "OKAY"; + status_code = RET_OKAY; + } - return (RET_OKAY); + printf ("%s: %g average |", status_str, average); + for (i = 0; i < values_num; i++) + printf (" %s=%g;;;;", values_names[i], values[i]); + printf ("\n"); + + return (status_code); } /* int do_check_con_average */ -int do_check_con_sum (int values_num, double *values, char **values_names) +static int do_check_con_sum (size_t values_num, + double *values, char **values_names) { - int i; + size_t i; double total; int total_num; + const char *status_str = "UNKNOWN"; + int status_code = RET_UNKNOWN; total = 0.0; total_num = 0; @@ -392,47 +404,150 @@ int do_check_con_sum (int values_num, double *values, char **values_names) if (match_range (&range_critical_g, total) != 0) { - printf ("CRITICAL: Sum = %lf\n", total); - return (RET_CRITICAL); + status_str = "CRITICAL"; + status_code = RET_CRITICAL; } else if (match_range (&range_warning_g, total) != 0) { - printf ("WARNING: Sum = %lf\n", total); - return (RET_WARNING); + status_str = "WARNING"; + status_code = RET_WARNING; } else { - printf ("OKAY: Sum = %lf\n", total); - return (RET_OKAY); + status_str = "OKAY"; + status_code = RET_OKAY; } - return (RET_UNKNOWN); + printf ("%s: %g sum |", status_str, total); + for (i = 0; i < values_num; i++) + printf (" %s=%g;;;;", values_names[i], values[i]); + printf ("\n"); + + return (status_code); } /* int do_check_con_sum */ -int do_check (void) +static int do_check_con_percentage (size_t values_num, + double *values, char **values_names) +{ + size_t i; + double sum = 0.0; + double percentage; + + const char *status_str = "UNKNOWN"; + int status_code = RET_UNKNOWN; + + if ((values_num < 1) || (isnan (values[0]))) + { + printf ("WARNING: The first value is not defined\n"); + return (RET_WARNING); + } + + for (i = 0; i < values_num; i++) + if (!isnan (values[i])) + sum += values[i]; + + if (sum == 0.0) + { + printf ("WARNING: Values sum up to zero\n"); + return (RET_WARNING); + } + + percentage = 100.0 * values[0] / sum; + + if (match_range (&range_critical_g, percentage) != 0) + { + status_str = "CRITICAL"; + status_code = RET_CRITICAL; + } + else if (match_range (&range_warning_g, percentage) != 0) + { + status_str = "WARNING"; + status_code = RET_WARNING; + } + else + { + status_str = "OKAY"; + status_code = RET_OKAY; + } + + printf ("%s: %lf percent |", status_str, percentage); + for (i = 0; i < values_num; i++) + printf (" %s=%lf;;;;", values_names[i], values[i]); + return (status_code); +} /* int do_check_con_percentage */ + +static int do_check (void) { - double *values; + lcc_connection_t *connection; + gauge_t *values; char **values_names; - int values_num; + size_t values_num; + char address[1024]; + char ident_str[1024]; + lcc_identifier_t ident; + size_t i; + int status; - if (get_values (&values_num, &values, &values_names) != 0) + snprintf (address, sizeof (address), "unix:%s", socket_file_g); + address[sizeof (address) - 1] = 0; + + snprintf (ident_str, sizeof (ident_str), "%s/%s", + hostname_g, value_string_g); + ident_str[sizeof (ident_str) - 1] = 0; + + connection = NULL; + status = lcc_connect (address, &connection); + if (status != 0) + { + printf ("ERROR: Connecting to daemon at %s failed.\n", + socket_file_g); + return (RET_CRITICAL); + } + + memset (&ident, 0, sizeof (ident)); + status = lcc_string_to_identifier (connection, &ident, ident_str); + if (status != 0) + { + printf ("ERROR: Creating an identifier failed: %s.\n", + lcc_strerror (connection)); + LCC_DESTROY (connection); + return (RET_CRITICAL); + } + + status = lcc_getval (connection, &ident, + &values_num, &values, &values_names); + if (status != 0) { - fputs ("ERROR: Cannot get values from daemon\n", stdout); + printf ("ERROR: Retrieving values from the daemon failed: %s.\n", + lcc_strerror (connection)); + LCC_DESTROY (connection); return (RET_CRITICAL); } + LCC_DESTROY (connection); + + status = filter_ds (&values_num, &values, &values_names); + if (status != RET_OKAY) + return (status); + + status = RET_UNKNOWN; if (consolitation_g == CON_NONE) - return (do_check_con_none (values_num, values, values_names)); + status = do_check_con_none (values_num, values, values_names); else if (consolitation_g == CON_AVERAGE) - return (do_check_con_average (values_num, values, values_names)); + status = do_check_con_average (values_num, values, values_names); else if (consolitation_g == CON_SUM) - return (do_check_con_sum (values_num, values, values_names)); + status = do_check_con_sum (values_num, values, values_names); + else if (consolitation_g == CON_PERCENTAGE) + status = do_check_con_percentage (values_num, values, values_names); free (values); - free (values_names); /* FIXME? */ + if (values_names != NULL) + for (i = 0; i < values_num; i++) + free (values_names[i]); + free (values_names); - return (RET_UNKNOWN); -} + return (status); +} /* int do_check */ int main (int argc, char **argv) { @@ -476,8 +591,14 @@ int main (int argc, char **argv) consolitation_g = CON_AVERAGE; else if (strcasecmp (optarg, "sum") == 0) consolitation_g = CON_SUM; + else if (strcasecmp (optarg, "percentage") == 0) + consolitation_g = CON_PERCENTAGE; else + { + fprintf (stderr, "Unknown consolidation function `%s'.\n", + optarg); usage (argv[0]); + } break; case 'd': { @@ -492,10 +613,10 @@ int main (int argc, char **argv) return (RET_UNKNOWN); } match_ds_g = tmp; - match_ds_g[match_ds_num_g] = strdup (optarg); + match_ds_g[match_ds_num_g] = cn_strdup (optarg); if (match_ds_g[match_ds_num_g] == NULL) { - fprintf (stderr, "strdup failed: %s\n", + fprintf (stderr, "cn_strdup failed: %s\n", strerror (errno)); return (RET_UNKNOWN); } @@ -509,7 +630,10 @@ int main (int argc, char **argv) if ((socket_file_g == NULL) || (value_string_g == NULL) || (hostname_g == NULL)) + { + fprintf (stderr, "Missing required arguments.\n"); usage (argv[0]); + } return (do_check ()); } /* int main */