diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/Makefile.am | 2 | ||||
-rw-r--r-- | plugins/check_snmp.c | 173 | ||||
-rwxr-xr-x | plugins/tests/check_snmp.t | 39 | ||||
-rw-r--r-- | plugins/tests/check_snmp_agent.pl | 6 |
4 files changed, 199 insertions, 21 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 4570fb7a..36a28b0b 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -39,7 +39,7 @@ EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ check_nagios check_by_ssh check_dns check_nt check_ide_smart \ check_procs check_mysql_query check_apt -EXTRA_DIST = t utils.c netutils.c sslutils.c popen.c utils.h netutils.h \ +EXTRA_DIST = t tests utils.c netutils.c sslutils.c popen.c utils.h netutils.h \ popen.h common.h runcmd.c runcmd.h PLUGINHDRS = common.h diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c index 2bc6024f..bf210222 100644 --- a/plugins/check_snmp.c +++ b/plugins/check_snmp.c @@ -59,6 +59,10 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; #define MAX_OIDS 8 +/* Longopts only arguments */ +#define L_CALCULATE_RATE CHAR_MAX+1 +#define L_RATE_MULTIPLIER CHAR_MAX+2 + /* Gobble to string - stop incrementing c when c[0] match one of the * characters in s */ #define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; } @@ -131,12 +135,16 @@ char *delimiter; char *output_delim; char *miblist = NULL; int needmibs = FALSE; +int calculate_rate = 0; +int rate_multiplier = 1; +state_data *previous_state; +double previous_value[MAX_OIDS]; int main (int argc, char **argv) { - int i, len, line; + int i, len, line, total_oids; unsigned int bk_count = 0, dq_count = 0; int iresult = STATE_UNKNOWN; int result = STATE_UNKNOWN; @@ -154,6 +162,17 @@ main (int argc, char **argv) char *th_crit=NULL; char type[8] = ""; output chld_out, chld_err; + char *previous_string=NULL; + char *ap=NULL; + char *state_string=NULL; + size_t response_length, current_length, string_length; + char *temp_string=NULL; + int is_numeric=0; + time_t current_time; + double temp_double; + time_t duration; + char *conv = "12345678"; + int is_counter=0; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); @@ -173,12 +192,33 @@ main (int argc, char **argv) timeout_interval = DEFAULT_TIMEOUT; retries = DEFAULT_RETRIES; + np_init( (char *) progname, argc, argv ); + /* Parse extra opts if any */ argv=np_extra_opts (&argc, argv, progname); + np_set_args(argc, argv); + if (process_arguments (argc, argv) == ERROR) usage4 (_("Could not parse arguments")); + if(calculate_rate) { + if (!strcmp(label, "SNMP")) + label = strdup("SNMP RATE"); + time(¤t_time); + i=0; + previous_state = np_state_read(); + if(previous_state!=NULL) { + /* Split colon separated values */ + previous_string = strdup((char *) previous_state->data); + while((ap = strsep(&previous_string, ":")) != NULL) { + if(verbose>2) + printf("State for %d=%s\n", i, ap); + previous_value[i++]=strtod(ap,NULL); + } + } + } + /* Populate the thresholds */ th_warn=warning_thresholds; th_crit=critical_thresholds; @@ -271,7 +311,10 @@ main (int argc, char **argv) } for (line=0, i=0; line < chld_out.lines; line++, i++) { - const char *conv = "%.0f"; + if(calculate_rate) + conv = "%.10g"; + else + conv = "%.0f"; ptr = chld_out.line[line]; oidname = strpcpy (oidname, ptr, delimiter); @@ -286,21 +329,34 @@ main (int argc, char **argv) /* Clean up type array - Sol10 does not necessarily zero it out */ bzero(type, sizeof(type)); + is_counter=0; /* We strip out the datatype indicator for PHBs */ - if (strstr (response, "Gauge: ")) + if (strstr (response, "Gauge: ")) { show = strstr (response, "Gauge: ") + 7; - else if (strstr (response, "Gauge32: ")) + is_numeric++; + } + else if (strstr (response, "Gauge32: ")) { show = strstr (response, "Gauge32: ") + 9; + is_numeric++; + } else if (strstr (response, "Counter32: ")) { show = strstr (response, "Counter32: ") + 11; - strcpy(type, "c"); + is_numeric++; + is_counter=1; + if(!calculate_rate) + strcpy(type, "c"); } else if (strstr (response, "Counter64: ")) { show = strstr (response, "Counter64: ") + 11; - strcpy(type, "c"); + is_numeric++; + is_counter=1; + if(!calculate_rate) + strcpy(type, "c"); } - else if (strstr (response, "INTEGER: ")) + else if (strstr (response, "INTEGER: ")) { show = strstr (response, "INTEGER: ") + 9; + is_numeric++; + } else if (strstr (response, "STRING: ")) { show = strstr (response, "STRING: ") + 8; conv = "%.10g"; @@ -345,14 +401,33 @@ main (int argc, char **argv) iresult = STATE_DEPENDENT; - /* Process this block for integer comparisons */ - if (thlds[i]->warning || thlds[i]->critical) { + /* Process this block for numeric comparisons */ + if (is_numeric) { ptr = strpbrk (show, "0123456789"); if (ptr == NULL) die (STATE_UNKNOWN,_("No valid data returned")); response_value[i] = strtod (ptr, NULL); - iresult = get_status(response_value[i], thlds[i]); - asprintf (&show, conv, response_value[i]); + + if(calculate_rate) { + if (previous_state!=NULL) { + duration = current_time-previous_state->time; + if(duration<=0) + die(STATE_UNKNOWN,_("Time duration between plugin calls is invalid")); + temp_double = (response_value[i]-previous_value[i])/duration; + /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */ + if(is_counter) { + if(temp_double<(double)0.0) + temp_double+=(double)4294967296.0; /* 2^32 */ + if(temp_double<(double)0.0) + temp_double+=(double)18446744069414584320.0; /* 2^64-2^32 */; + } + iresult = get_status(temp_double, thlds[i]); + asprintf (&show, conv, temp_double); + } + } else { + iresult = get_status(response_value[i], thlds[i]); + asprintf (&show, conv, response_value[i]); + } } /* Process this block for string matching */ @@ -380,6 +455,7 @@ main (int argc, char **argv) } /* Process this block for existence-nonexistence checks */ + /* TV: Should this be outside of this else block? */ else { if (eval_method[i] & CRIT_PRESENT) iresult = STATE_CRITICAL; @@ -393,7 +469,7 @@ main (int argc, char **argv) result = max_state (result, iresult); /* Prepend a label for this OID if there is one */ - if (nlabels > (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) + if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) asprintf (&outbuff, "%s%s%s %s%s%s", outbuff, (i == 0) ? " " : output_delim, labels[i], mark (iresult), show, mark (iresult)); @@ -409,7 +485,13 @@ main (int argc, char **argv) ptr = NULL; strtod(show, &ptr); if (ptr > show) { - strncat(perfstr, oidname, sizeof(perfstr)-strlen(perfstr)-1); + if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) + temp_string=labels[i]; + else + temp_string=oidname; + if(calculate_rate) + asprintf(&temp_string,"%s-rate",temp_string); + strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1); strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1); len = sizeof(perfstr)-strlen(perfstr)-1; strncat(perfstr, show, len>ptr-show ? ptr-show : len); @@ -419,6 +501,44 @@ main (int argc, char **argv) strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1); } } + total_oids=i; + + /* Save state data, as all data collected now */ + if(calculate_rate) { + string_length=1024; + state_string=malloc(string_length); + if(state_string==NULL) + die(STATE_UNKNOWN, _("Cannot malloc")); + + current_length=0; + for(i=0; i<total_oids; i++) { + asprintf(&temp_string,"%.0f",response_value[i]); + if(temp_string==NULL) + die(STATE_UNKNOWN,_("Cannot asprintf()")); + response_length = strlen(temp_string); + if(current_length+response_length>string_length) { + string_length=current_length+1024; + state_string=realloc(state_string,string_length); + if(state_string==NULL) + die(STATE_UNKNOWN, _("Cannot realloc()")); + } + strcpy(&state_string[current_length],temp_string); + current_length=current_length+response_length; + state_string[current_length]=':'; + current_length++; + free(temp_string); + } + state_string[--current_length]='\0'; + if (verbose > 2) + printf("State string=%s\n",state_string); + + /* This is not strictly the same as time now, but any subtle variations will cancel out */ + np_state_write_string(current_time, state_string ); + if(previous_state==NULL) { + /* Or should this be highest state? */ + die( STATE_OK, _("No previous data to calculate rate - assume okay" ) ); + } + } printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr); if (mult_resp) printf ("%s", mult_resp); @@ -462,6 +582,8 @@ process_arguments (int argc, char **argv) {"authpasswd", required_argument, 0, 'A'}, {"privpasswd", required_argument, 0, 'X'}, {"next", no_argument, 0, 'n'}, + {"rate", no_argument, 0, L_CALCULATE_RATE}, + {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER}, {0, 0, 0, 0} }; @@ -609,7 +731,6 @@ process_arguments (int argc, char **argv) output_delim = strscpy (output_delim, optarg); break; case 'l': /* label */ - label = optarg; nlabels++; if (nlabels >= labels_size) { labels_size += 8; @@ -666,7 +787,15 @@ process_arguments (int argc, char **argv) unitv[nunits - 1] = ptr; } break; - + case L_CALCULATE_RATE: + if(calculate_rate==0) + np_enable_state(NULL, 1); + calculate_rate = 1; + break; + case L_RATE_MULTIPLIER: + if(!is_integer(optarg)||(rate_multiplier=atoi(optarg)<=0)) + usage2(_("Rate multiplier must be a positive integer"),optarg); + break; } } @@ -905,6 +1034,8 @@ print_help (void) printf (" %s\n", _("Warning threshold range(s)")); printf (" %s\n", "-c, --critical=THRESHOLD(s)"); printf (" %s\n", _("Critical threshold range(s)")); + printf (" %s\n", "--rate"); + printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below")); /* Tests Against Strings */ printf (" %s\n", "-s, --string=STRING"); @@ -914,7 +1045,7 @@ print_help (void) printf (" %s\n", "-R, --eregi=REGEX"); printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); printf (" %s\n", "-l, --label=STRING"); - printf (" %s\n", _("Prefix label for output from plugin (default -s 'SNMP')")); + printf (" %s\n", _("Prefix label for output from plugin (default -l 'SNMP')")); /* Output Formatting */ printf (" %s\n", "-u, --units=STRING"); @@ -945,6 +1076,16 @@ print_help (void) printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); printf (" %s\n", _("returned from the SNMP query is an unsigned integer.")); + printf("\n"); + printf("%s\n", _("Rate Calculation:")); + printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when")); + printf(" %s\n", _("calculating the counter difference since the last check. check_snmp")); + printf(" %s\n", _("saves the last state information in a file so that the rate can be")); + printf(" %s\n", _("calculated. Use the --rate option to save state information. On the")); + printf(" %s\n", _("first run, there will be no prior state - this will return with OK.")); + printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so")); + printf(" %s\n", _("changing the arguments will create a new state file.")); + printf (UT_SUPPORT); } diff --git a/plugins/tests/check_snmp.t b/plugins/tests/check_snmp.t index b5f3f89e..17420792 100755 --- a/plugins/tests/check_snmp.t +++ b/plugins/tests/check_snmp.t @@ -51,7 +51,7 @@ if ($ARGV[0] && $ARGV[0] eq "-d") { } } -my $tests = 9; +my $tests = 21; if (-x "./check_snmp") { plan tests => $tests; } else { @@ -106,3 +106,40 @@ like($res->output, '/'.quotemeta('SNMP OK - And now have fun with with this: \"C "And now have fun with with this: \"C:\\\\\" because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3"); +system("rm /usr/local/nagios/var/check_snmp/*"); +$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); +is($res->return_code, 0, "Returns OK"); +is($res->output, "No previous data to calculate rate - assume okay"); + +# Need to sleep, otherwise duration=0 +sleep 1; + +$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); +is($res->return_code, 1, "WARNING - due to going above rate calculation" ); +is($res->output, "SNMP RATE WARNING - *666* | iso.3.6.1.4.1.8072.3.2.67.10-rate=666 "); + +$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); +is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" ); +is($res->output, "Time duration between plugin calls is invalid"); + + +$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); +is($res->return_code, 0, "OK for first call" ); +is($res->output, "No previous data to calculate rate - assume okay" ); + +# Need to sleep, otherwise duration=0 +sleep 1; + +$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); +is($res->return_code, 0, "OK as no thresholds" ); +is($res->output, "SNMP RATE OK - inoctets 666 | inoctets-rate=666 ", "Check label"); + +sleep 2; + +$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); +is($res->return_code, 0, "OK as no thresholds" ); +is($res->output, "SNMP RATE OK - inoctets 333 | inoctets-rate=333 ", "Check rate decreases due to longer interval"); + + + + diff --git a/plugins/tests/check_snmp_agent.pl b/plugins/tests/check_snmp_agent.pl index 302ba6e7..425caeb3 100644 --- a/plugins/tests/check_snmp_agent.pl +++ b/plugins/tests/check_snmp_agent.pl @@ -33,9 +33,9 @@ ends with with this: C:\\'; my $multilin5 = 'And now have fun with with this: "C:\\" because we\'re not done yet!'; -my @fields = (ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_UNSIGNED, ASN_UNSIGNED, ASN_COUNTER, ASN_COUNTER64, ASN_UNSIGNED); -my @values = ($multiline, $multilin2, $multilin3, $multilin4, $multilin5, 4294965296, 1000, 4294965296, uint64("18446744073709351616"), int(rand(2**32))); -my @incrts = (undef, undef, undef, undef, undef, 1000, -500, 1000, 100000, undef); +my @fields = (ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_UNSIGNED, ASN_UNSIGNED, ASN_COUNTER, ASN_COUNTER64, ASN_UNSIGNED, ASN_COUNTER); +my @values = ($multiline, $multilin2, $multilin3, $multilin4, $multilin5, 4294965296, 1000, 4294965296, uint64("18446744073709351616"), int(rand(2**32)), 64000); +my @incrts = (undef, undef, undef, undef, undef, 1000, -500, 1000, 100000, undef, 666); # Number of elements in our OID my $oidelts; |