monitoring-plugins-cyconet/check_nwc_health/check_nwc_health-3.1/plugins-scripts/GLPlugin.pm

1746 lines
50 KiB
Perl
Raw Normal View History

2014-08-24 20:14:08 +00:00
package GLPlugin;
use strict;
use IO::File;
use File::Basename;
use Digest::MD5 qw(md5_hex);
use Errno;
use AutoLoader;
our $AUTOLOAD;
use constant { OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3 };
{
our $mode = undef;
our $plugin = undef;
our $pluginname = basename($ENV{'NAGIOS_PLUGIN'} || $0);
2014-08-24 20:14:08 +00:00
our $blacklist = undef;
our $info = [];
our $extendedinfo = [];
our $summary = [];
our $variables = {};
}
sub new {
my $class = shift;
my %params = @_;
my $self = {};
bless $self, $class;
$GLPlugin::plugin = GLPlugin::Commandline->new(%params);
return $self;
}
sub init {
my $self = shift;
if ($self->opts->can("blacklist") && $self->opts->blacklist &&
-f $self->opts->blacklist) {
$self->opts->blacklist = do {
local (@ARGV, $/) = $self->opts->blacklist; <> };
}
}
sub dumper {
my $self = shift;
my $object = shift;
my $run = $object->{runtime};
delete $object->{runtime};
printf STDERR "%s\n", Data::Dumper::Dumper($object);
$object->{runtime} = $run;
}
sub no_such_mode {
my $self = shift;
printf "Mode %s is not implemented for this type of device\n",
$self->opts->mode;
exit 3;
}
#########################################################
# framework-related. setup, options
#
sub add_modes {
my $self = shift;
my $modes = shift;
my $modestring = "";
my @modes = @{$modes};
my $longest = length ((reverse sort {length $a <=> length $b} map { $_->[1] } @modes)[0]);
my $format = " %-".
(length ((reverse sort {length $a <=> length $b} map { $_->[1] } @modes)[0])).
"s\t(%s)\n";
foreach (@modes) {
$modestring .= sprintf $format, $_->[1], $_->[3];
}
$modestring .= sprintf "\n";
$GLPlugin::plugin->{modestring} = $modestring;
}
sub add_arg {
my $self = shift;
my %args = @_;
if ($args{help} =~ /^--mode/) {
$args{help} .= "\n".$GLPlugin::plugin->{modestring};
}
$GLPlugin::plugin->{opts}->add_arg(%args);
}
sub add_mode {
my $self = shift;
my %args = @_;
push(@{$GLPlugin::plugin->{modes}}, \%args);
my $longest = length ((reverse sort {length $a <=> length $b} map { $_->{spec} } @{$GLPlugin::plugin->{modes}})[0]);
my $format = " %-".
(length ((reverse sort {length $a <=> length $b} map { $_->{spec} } @{$GLPlugin::plugin->{modes}})[0])).
"s\t(%s)\n";
$GLPlugin::plugin->{modestring} = "";
foreach (@{$GLPlugin::plugin->{modes}}) {
$GLPlugin::plugin->{modestring} .= sprintf $format, $_->{spec}, $_->{help};
}
$GLPlugin::plugin->{modestring} .= "\n";
}
sub validate_args {
my $self = shift;
if ($self->opts->mode =~ /^my-([^\-.]+)/) {
my $param = $self->opts->mode;
$param =~ s/\-/::/g;
$self->add_mode(
internal => $param,
spec => $self->opts->mode,
alias => undef,
help => 'my extension',
);
} elsif ($self->opts->mode eq 'encode') {
my $input = <>;
chomp $input;
$input =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
printf "%s\n", $input;
exit 0;
} elsif ((! grep { $self->opts->mode eq $_ } map { $_->{spec} } @{$GLPlugin::plugin->{modes}}) &&
(! grep { $self->opts->mode eq $_ } map { defined $_->{alias} ? @{$_->{alias}} : () } @{$GLPlugin::plugin->{modes}})) {
printf "UNKNOWN - mode %s\n", $self->opts->mode;
$self->opts->print_help();
exit 3;
}
if ($self->opts->name && $self->opts->name =~ /(%22)|(%27)/) {
my $name = $self->opts->name;
$name =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
$self->override_opt('name', $name);
}
$GLPlugin::mode = (
map { $_->{internal} }
grep {
($self->opts->mode eq $_->{spec}) ||
( defined $_->{alias} && grep { $self->opts->mode eq $_ } @{$_->{alias}})
} @{$GLPlugin::plugin->{modes}}
)[0];
if ($self->opts->multiline) {
$ENV{NRPE_MULTILINESUPPORT} = 1;
} else {
$ENV{NRPE_MULTILINESUPPORT} = 0;
}
if (! $self->opts->statefilesdir) {
if (exists $ENV{OMD_ROOT}) {
$self->override_opt('statefilesdir', $ENV{OMD_ROOT}."/var/tmp/".$GLPlugin::plugin->{name});
} else {
$self->override_opt('statefilesdir', "/var/tmp/".$GLPlugin::plugin->{name});
}
}
$GLPlugin::plugin->{statefilesdir} = $self->opts->statefilesdir;
if ($self->opts->can("warningx") && $self->opts->warningx) {
foreach my $key (keys %{$self->opts->warningx}) {
$self->set_thresholds(metric => $key,
warning => $self->opts->warningx->{$key});
}
}
if ($self->opts->can("criticalx") && $self->opts->criticalx) {
foreach my $key (keys %{$self->opts->criticalx}) {
$self->set_thresholds(metric => $key,
critical => $self->opts->criticalx->{$key});
}
}
$self->set_timeout_alarm() if ! $SIG{'ALRM'};
}
sub set_timeout_alarm {
my $self = shift;
$SIG{'ALRM'} = sub {
printf "UNKNOWN - %s timed out after %d seconds\n",
$GLPlugin::plugin->{name}, $self->opts->timeout;
exit 3;
};
alarm($self->opts->timeout);
}
#########################################################
# global helpers
#
sub set_variable {
my $self = shift;
my $key = shift;
my $value = shift;
$GLPlugin::variables->{$key} = $value;
}
sub get_variable {
my $self = shift;
my $key = shift;
my $fallback = shift;
return exists $GLPlugin::variables->{$key} ?
$GLPlugin::variables->{$key} : $fallback;
}
sub debug {
my $self = shift;
my $format = shift;
my $tracefile = "/tmp/".$GLPlugin::pluginname.".trace";
2014-08-24 20:14:08 +00:00
$self->{trace} = -f $tracefile ? 1 : 0;
if ($self->get_variable("verbose") &&
$self->get_variable("verbose") > $self->get_variable("verbosity", 10)) {
printf("%s: ", scalar localtime);
printf($format, @_);
printf "\n";
}
if ($self->{trace}) {
my $logfh = new IO::File;
$logfh->autoflush(1);
if ($logfh->open($tracefile, "a")) {
$logfh->printf("%s: ", scalar localtime);
$logfh->printf($format, @_);
$logfh->printf("\n");
$logfh->close();
}
}
}
sub filter_namex {
my $self = shift;
my $opt = shift;
my $name = shift;
if ($opt) {
if ($self->opts->regexp) {
if ($name =~ /$opt/i) {
return 1;
}
} else {
if (lc $opt eq lc $name) {
return 1;
}
}
} else {
return 1;
}
return 0;
}
sub filter_name {
my $self = shift;
my $name = shift;
return $self->filter_namex($self->opts->name, $name);
}
sub filter_name2 {
my $self = shift;
my $name = shift;
return $self->filter_namex($self->opts->name2, $name);
}
sub filter_name3 {
my $self = shift;
my $name = shift;
return $self->filter_namex($self->opts->name3, $name);
}
sub version_is_minimum {
my $self = shift;
my $version = shift;
my $installed_version;
my $newer = 1;
if ($self->get_variable("version")) {
$installed_version = $self->get_variable("version");
} elsif (exists $self->{version}) {
$installed_version = $self->{version};
} else {
return 0;
}
my @v1 = map { $_ eq "x" ? 0 : $_ } split(/\./, $version);
my @v2 = split(/\./, $installed_version);
if (scalar(@v1) > scalar(@v2)) {
push(@v2, (0) x (scalar(@v1) - scalar(@v2)));
} elsif (scalar(@v2) > scalar(@v1)) {
push(@v1, (0) x (scalar(@v2) - scalar(@v1)));
}
foreach my $pos (0..$#v1) {
if ($v2[$pos] > $v1[$pos]) {
$newer = 1;
last;
} elsif ($v2[$pos] < $v1[$pos]) {
$newer = 0;
last;
}
}
return $newer;
}
sub accentfree {
my $self = shift;
my $text = shift;
# thanks mycoyne who posted this accent-remove-algorithm
# http://www.experts-exchange.com/Programming/Languages/Scripting/Perl/Q_23275533.html#a21234612
my @transformed;
my %replace = (
'9a' => 's', '9c' => 'oe', '9e' => 'z', '9f' => 'Y', 'c0' => 'A', 'c1' => 'A',
'c2' => 'A', 'c3' => 'A', 'c4' => 'A', 'c5' => 'A', 'c6' => 'AE', 'c7' => 'C',
'c8' => 'E', 'c9' => 'E', 'ca' => 'E', 'cb' => 'E', 'cc' => 'I', 'cd' => 'I',
'ce' => 'I', 'cf' => 'I', 'd0' => 'D', 'd1' => 'N', 'd2' => 'O', 'd3' => 'O',
'd4' => 'O', 'd5' => 'O', 'd6' => 'O', 'd8' => 'O', 'd9' => 'U', 'da' => 'U',
'db' => 'U', 'dc' => 'U', 'dd' => 'Y', 'e0' => 'a', 'e1' => 'a', 'e2' => 'a',
'e3' => 'a', 'e4' => 'a', 'e5' => 'a', 'e6' => 'ae', 'e7' => 'c', 'e8' => 'e',
'e9' => 'e', 'ea' => 'e', 'eb' => 'e', 'ec' => 'i', 'ed' => 'i', 'ee' => 'i',
'ef' => 'i', 'f0' => 'o', 'f1' => 'n', 'f2' => 'o', 'f3' => 'o', 'f4' => 'o',
'f5' => 'o', 'f6' => 'o', 'f8' => 'o', 'f9' => 'u', 'fa' => 'u', 'fb' => 'u',
'fc' => 'u', 'fd' => 'y', 'ff' => 'y',
);
my @letters = split //, $text;;
for (my $i = 0; $i <= $#letters; $i++) {
my $hex = sprintf "%x", ord($letters[$i]);
$letters[$i] = $replace{$hex} if (exists $replace{$hex});
}
push @transformed, @letters;
return join '', @transformed;
}
sub dump {
my $self = shift;
my $class = ref($self);
$class =~ s/^.*:://;
if (exists $self->{flat_indices}) {
printf "[%s_%s]\n", uc $class, $self->{flat_indices};
} else {
printf "[%s]\n", uc $class;
}
foreach (grep !/^(info|trace|warning|critical|blacklisted|extendedinfo|flat_indices|indices)/, sort keys %{$self}) {
printf "%s: %s\n", $_, $self->{$_} if defined $self->{$_} && ref($self->{$_}) ne "ARRAY";
}
if ($self->{info}) {
printf "info: %s\n", $self->{info};
}
printf "\n";
foreach (grep !/^(info|trace|warning|critical|blacklisted|extendedinfo|flat_indices|indices)/, sort keys %{$self}) {
if (defined $self->{$_} && ref($self->{$_}) eq "ARRAY") {
foreach my $obj (@{$self->{$_}}) {
$obj->dump();
}
}
}
}
sub table_ascii {
my $self = shift;
my $table = shift;
my $titles = shift;
my $text = "";
my $column_length = {};
my $column = 0;
foreach (@{$titles}) {
$column_length->{$column++} = length($_);
}
foreach my $tr (@{$table}) {
@{$tr} = map { ref($_) eq "ARRAY" ? $_->[0] : $_; } @{$tr};
$column = 0;
foreach my $td (@{$tr}) {
if (length($td) > $column_length->{$column}) {
$column_length->{$column} = length($td);
}
$column++;
}
}
$column = 0;
foreach (@{$titles}) {
$column_length->{$column} = "%".($column_length->{$column} + 3)."s";
$column++;
}
$column = 0;
foreach (@{$titles}) {
$text .= sprintf $column_length->{$column++}, $_;
}
$text .= "\n";
foreach my $tr (@{$table}) {
$column = 0;
foreach my $td (@{$tr}) {
$text .= sprintf $column_length->{$column++}, $td;
}
$text .= "\n";
}
return $text;
}
sub table_html {
my $self = shift;
my $table = shift;
my $titles = shift;
my $text = "";
$text .= "<table style=\"border-collapse:collapse; border: 1px solid black;\">";
$text .= "<tr>";
foreach (@{$titles}) {
$text .= sprintf "<th style=\"text-align: left; padding-left: 4px; padding-right: 6px;\">%s</th>", $_;
}
$text .= "</tr>";
foreach my $tr (@{$table}) {
$text .= "<tr>";
foreach my $td (@{$tr}) {
my $class = "statusOK";
if (ref($td) eq "ARRAY") {
$class = {
0 => "statusOK",
1 => "statusWARNING",
2 => "statusCRITICAL",
3 => "statusUNKNOWN",
}->{$td->[1]};
$td = $td->[0];
}
$text .= sprintf "<td style=\"text-align: left; padding-left: 4px; padding-right: 6px;\" class=\"%s\">%s</td>", $class, $td;
}
$text .= "</tr>";
}
$text .= "</table>";
return $text;
}
sub load_my_extension {
my $self = shift;
if ($self->opts->mode =~ /^my-([^-.]+)/) {
my $class = $1;
my $loaderror = undef;
substr($class, 0, 1) = uc substr($class, 0, 1);
if (! $self->opts->get("with-mymodules-dyn-dir")) {
$self->override_opt("with-mymodules-dyn-dir", "");
}
my $plugin_name = $GLPlugin::pluginname;
2014-08-24 20:14:08 +00:00
$plugin_name =~ /check_(.*?)_health/;
$plugin_name = "Check".uc(substr($1, 0, 1)).substr($1, 1)."Health";
foreach my $libpath (split(":", $self->opts->get("with-mymodules-dyn-dir"))) {
foreach my $extmod (glob $libpath."/".$plugin_name."*.pm") {
my $stderrvar;
*SAVEERR = *STDERR;
open OUT ,'>',\$stderrvar;
*STDERR = *OUT;
eval {
$self->debug(sprintf "loading module %s", $extmod);
require $extmod;
};
*STDERR = *SAVEERR;
if ($@) {
$loaderror = $extmod;
$self->debug(sprintf "failed loading module %s: %s", $extmod, $@);
}
}
}
my $original_class = ref($self);
my $original_init = $self->can("init");
bless $self, "My$class";
if ($self->isa("GLPlugin")) {
my $new_init = $self->can("init");
if ($new_init == $original_init) {
$self->add_unknown(
sprintf "Class %s needs an init() method", ref($self));
} else {
# now go back to check_*_health.pl where init() will be called
}
} else {
bless $self, $original_class;
$self->add_unknown(
sprintf "Class %s is not a subclass of GLPlugin%s",
"My$class",
$loaderror ? sprintf " (syntax error in %s?)", $loaderror : "" );
my ($code, $message) = $self->check_messages(join => ', ', join_all => ', ');
$self->nagios_exit($code, $message);
}
}
}
#########################################################
# runtime methods
#
sub mode {
my $self = shift;
return $GLPlugin::mode;
}
sub statefilesdir {
my $self = shift;
return $GLPlugin::plugin->{statefilesdir};
}
sub opts { # die beiden _nicht_ in AUTOLOAD schieben, das kracht!
my $self = shift;
return $GLPlugin::plugin->opts();
}
sub getopts {
my $self = shift;
my $envparams = shift || [];
$GLPlugin::plugin->getopts();
# es kann sein, dass beim aufraeumen zum schluss als erstes objekt
# das $GLPlugin::plugin geloescht wird. in anderen destruktoren
# (insb. fuer dbi disconnect) steht dann $self->opts->verbose
# nicht mehr zur verfuegung bzw. $GLPlugin::plugin->opts ist undef.
$self->set_variable("verbose", $self->opts->verbose);
#
# die gueltigkeit von modes wird bereits hier geprueft und nicht danach
# in validate_args. (zwischen getopts und validate_args wird
# normalerweise classify aufgerufen, welches bereits eine verbindung
# zum endgeraet herstellt. bei falschem mode waere das eine verschwendung
# bzw. durch den exit3 ein evt. unsauberes beenden der verbindung.
if ((! grep { $self->opts->mode eq $_ } map { $_->{spec} } @{$GLPlugin::plugin->{modes}}) &&
(! grep { $self->opts->mode eq $_ } map { defined $_->{alias} ? @{$_->{alias}} : () } @{$GLPlugin::plugin->{modes}})) {
printf "UNKNOWN - mode %s\n", $self->opts->mode;
$self->opts->print_help();
exit 3;
}
}
sub add_ok {
my $self = shift;
my $message = shift || $self->{info};
$self->add_message(OK, $message);
}
sub add_warning {
my $self = shift;
my $message = shift || $self->{info};
$self->add_message(WARNING, $message);
}
sub add_critical {
my $self = shift;
my $message = shift || $self->{info};
$self->add_message(CRITICAL, $message);
}
sub add_unknown {
my $self = shift;
my $message = shift || $self->{info};
$self->add_message(UNKNOWN, $message);
}
sub add_message {
my $self = shift;
my $level = shift;
my $message = shift || $self->{info};
$GLPlugin::plugin->add_message($level, $message)
unless $self->is_blacklisted();
if (exists $self->{failed}) {
if ($level == UNKNOWN && $self->{failed} == OK) {
$self->{failed} = $level;
} elsif ($level > $self->{failed}) {
$self->{failed} = $level;
}
}
}
sub clear_ok {
my $self = shift;
$self->clear_messages(OK);
}
sub clear_warning {
my $self = shift;
$self->clear_messages(WARNING);
}
sub clear_critical {
my $self = shift;
$self->clear_messages(CRITICAL);
}
sub clear_unknown {
my $self = shift;
$self->clear_messages(UNKNOWN);
}
sub clear_all { # deprecated, use clear_messages
my $self = shift;
$self->clear_ok();
$self->clear_warning();
$self->clear_critical();
$self->clear_unknown();
}
sub set_level {
my $self = shift;
my $code = shift;
$code = (qw(ok warning critical unknown))[$code] if $code =~ /^\d+$/;
$code = lc $code;
if (! exists $self->{tmp_level}) {
$self->{tmp_level} = {
ok => 0,
warning => 0,
critical => 0,
unknown => 0,
};
}
$self->{tmp_level}->{$code}++;
}
sub get_level {
my $self = shift;
return OK if ! exists $self->{tmp_level};
my $code = OK;
$code ||= CRITICAL if $self->{tmp_level}->{critical};
$code ||= WARNING if $self->{tmp_level}->{warning};
$code ||= UNKNOWN if $self->{tmp_level}->{unknown};
return $code;
}
#########################################################
# blacklisting
#
sub blacklist {
my $self = shift;
$self->{blacklisted} = 1;
}
sub add_blacklist {
my $self = shift;
my $list = shift;
$GLPlugin::blacklist = join('/',
(split('/', $self->opts->blacklist), $list));
}
sub is_blacklisted {
my $self = shift;
if (! $self->opts->can("blacklist")) {
return 0;
}
if (! exists $self->{blacklisted}) {
$self->{blacklisted} = 0;
}
if (exists $self->{blacklisted} && $self->{blacklisted}) {
return $self->{blacklisted};
}
# FAN:459,203/TEMP:102229/ENVSUBSYSTEM
# FAN_459,FAN_203,TEMP_102229,ENVSUBSYSTEM
if ($self->opts->blacklist =~ /_/) {
foreach my $bl_item (split(/,/, $self->opts->blacklist)) {
if ($bl_item eq $self->internal_name()) {
$self->{blacklisted} = 1;
}
}
} else {
foreach my $bl_items (split(/\//, $self->opts->blacklist)) {
if ($bl_items =~ /^(\w+):([\:\d\-,]+)$/) {
my $bl_type = $1;
my $bl_names = $2;
foreach my $bl_name (split(/,/, $bl_names)) {
if ($bl_type."_".$bl_name eq $self->internal_name()) {
$self->{blacklisted} = 1;
}
}
} elsif ($bl_items =~ /^(\w+)$/) {
if ($bl_items eq $self->internal_name()) {
$self->{blacklisted} = 1;
}
}
}
}
return $self->{blacklisted};
}
#########################################################
# additional info
#
sub add_info {
my $self = shift;
my $info = shift;
$info = $self->is_blacklisted() ? $info.' (blacklisted)' : $info;
$self->{info} = $info;
push(@{$GLPlugin::info}, $info);
}
sub annotate_info { # deprecated
my $self = shift;
my $annotation = shift;
my $lastinfo = pop(@{$GLPlugin::info});
$lastinfo .= sprintf ' (%s)', $annotation;
push(@{$GLPlugin::info}, $lastinfo);
}
sub add_extendedinfo { # deprecated
my $self = shift;
my $info = shift;
$self->{extendedinfo} = $info;
return if ! $self->opts->extendedinfo;
push(@{$GLPlugin::extendedinfo}, $info);
}
sub get_info {
my $self = shift;
my $separator = shift || ' ';
return join($separator , @{$GLPlugin::info});
}
sub get_extendedinfo {
my $self = shift;
my $separator = shift || ' ';
return join($separator, @{$GLPlugin::extendedinfo});
}
sub add_summary { # deprecated
my $self = shift;
my $summary = shift;
push(@{$GLPlugin::summary}, $summary);
}
sub get_summary {
my $self = shift;
return join(', ', @{$GLPlugin::summary});
}
#########################################################
# persistency
#
sub valdiff {
my $self = shift;
my $pparams = shift;
my %params = %{$pparams};
my @keys = @_;
my $now = time;
my $newest_history_set = {};
my $last_values = $self->load_state(%params) || eval {
my $empty_events = {};
foreach (@keys) {
if (ref($self->{$_}) eq "ARRAY") {
$empty_events->{$_} = [];
} else {
$empty_events->{$_} = 0;
}
}
$empty_events->{timestamp} = 0;
if ($self->opts->lookback) {
$empty_events->{lookback_history} = {};
}
$empty_events;
};
$self->{'delta_timestamp'} = $now - $last_values->{timestamp};
foreach (@keys) {
if ($self->opts->lookback) {
# find a last_value in the history which fits lookback best
# and overwrite $last_values->{$_} with historic data
if (exists $last_values->{lookback_history}->{$_}) {
foreach my $date (sort {$a <=> $b} keys %{$last_values->{lookback_history}->{$_}}) {
$newest_history_set->{$_} = $last_values->{lookback_history}->{$_}->{$date};
$newest_history_set->{timestamp} = $date;
}
foreach my $date (sort {$a <=> $b} keys %{$last_values->{lookback_history}->{$_}}) {
if ($date >= ($now - $self->opts->lookback)) {
$last_values->{$_} = $last_values->{lookback_history}->{$_}->{$date};
$last_values->{timestamp} = $date;
last;
} else {
delete $last_values->{lookback_history}->{$_}->{$date};
}
}
}
}
if ($self->{$_} =~ /^\d+$/) {
$last_values->{$_} = 0 if ! exists $last_values->{$_};
if ($self->{$_} >= $last_values->{$_}) {
$self->{'delta_'.$_} = $self->{$_} - $last_values->{$_};
} else {
# vermutlich db restart und zaehler alle auf null
$self->{'delta_'.$_} = $self->{$_};
}
$self->debug(sprintf "delta_%s %f", $_, $self->{'delta_'.$_});
$self->{$_.'_per_sec'} = $self->{'delta_timestamp'} ?
$self->{'delta_'.$_} / $self->{'delta_timestamp'} : 0;
} elsif (ref($self->{$_}) eq "ARRAY") {
if ((! exists $last_values->{$_} || ! defined $last_values->{$_}) && exists $params{lastarray}) {
# innerhalb der lookback-zeit wurde nichts in der lookback_history
# gefunden. allenfalls irgendwas aelteres. normalerweise
# wuerde jetzt das array als [] initialisiert.
# d.h. es wuerde ein delta geben, @found s.u.
# wenn man das nicht will, sondern einfach aktuelles array mit
# dem array des letzten laufs vergleichen will, setzt man lastarray
$last_values->{$_} = %{$newest_history_set} ?
$newest_history_set->{$_} : []
} elsif ((! exists $last_values->{$_} || ! defined $last_values->{$_}) && ! exists $params{lastarray}) {
$last_values->{$_} = [] if ! exists $last_values->{$_};
} elsif (exists $last_values->{$_} && ! defined $last_values->{$_}) {
# $_ kann es auch ausserhalb des lookback_history-keys als normalen
# key geben. der zeigt normalerweise auf den entspr. letzten
# lookback_history eintrag. wurde der wegen ueberalterung abgeschnitten
# ist der hier auch undef.
$last_values->{$_} = %{$newest_history_set} ?
$newest_history_set->{$_} : []
}
my %saved = map { $_ => 1 } @{$last_values->{$_}};
my %current = map { $_ => 1 } @{$self->{$_}};
my @found = grep(!defined $saved{$_}, @{$self->{$_}});
my @lost = grep(!defined $current{$_}, @{$last_values->{$_}});
$self->{'delta_found_'.$_} = \@found;
$self->{'delta_lost_'.$_} = \@lost;
}
}
$params{save} = eval {
my $empty_events = {};
foreach (@keys) {
$empty_events->{$_} = $self->{$_};
}
$empty_events->{timestamp} = $now;
if ($self->opts->lookback) {
$empty_events->{lookback_history} = $last_values->{lookback_history};
foreach (@keys) {
$empty_events->{lookback_history}->{$_}->{$now} = $self->{$_};
}
}
$empty_events;
};
$self->save_state(%params);
}
sub create_statefilesdir {
my $self = shift;
if (! -d $self->statefilesdir()) {
eval {
use File::Path;
mkpath $self->statefilesdir();
};
if ($@ || ! -w $self->statefilesdir()) {
$self->add_message(UNKNOWN,
sprintf "cannot create status dir %s! check your filesystem (permissions/usage/integrity) and disk devices", $self->statefilesdir());
}
} elsif (! -w $self->statefilesdir()) {
$self->add_message(UNKNOWN,
sprintf "cannot write status dir %s! check your filesystem (permissions/usage/integrity) and disk devices", $self->statefilesdir());
}
}
sub create_statefile {
my $self = shift;
my %params = @_;
my $extension = "";
$extension .= $params{name} ? '_'.$params{name} : '';
$extension =~ s/\//_/g;
$extension =~ s/\(/_/g;
$extension =~ s/\)/_/g;
$extension =~ s/\*/_/g;
$extension =~ s/\s/_/g;
return sprintf "%s/%s%s", $self->statefilesdir(),
$self->opts->mode, lc $extension;
}
sub schimpf {
my $self = shift;
printf "statefilesdir %s is not writable.\nYou didn't run this plugin as root, didn't you?\n", $self->statefilesdir();
}
# $self->protect_value('1.1-flat_index', 'cpu_busy', 'percent');
sub protect_value {
my $self = shift;
my $ident = shift;
my $key = shift;
my $validfunc = shift;
if (ref($validfunc) ne "CODE" && $validfunc eq "percent") {
$validfunc = sub {
my $value = shift;
return ($value < 0 || $value > 100) ? 0 : 1;
};
} elsif (ref($validfunc) ne "CODE" && $validfunc eq "positive") {
$validfunc = sub {
my $value = shift;
return ($value < 0) ? 0 : 1;
};
}
if (&$validfunc($self->{$key})) {
$self->save_state(name => 'protect_'.$ident.'_'.$key, save => {
$key => $self->{$key},
exception => 0,
});
} else {
# if the device gives us an clearly wrong value, simply use the last value.
my $laststate = $self->load_state(name => 'protect_'.$ident.'_'.$key);
$self->debug(sprintf "self->{%s} is %s and invalid for the %dth time",
$key, $self->{$key}, $laststate->{exception} + 1);
if ($laststate->{exception} <= 5) {
# but only 5 times.
# if the error persists, somebody has to check the device.
$self->{$key} = $laststate->{$key};
}
$self->save_state(name => 'protect_'.$ident.'_'.$key, save => {
$key => $laststate->{$key},
exception => $laststate->{exception}++,
});
}
}
sub save_state {
my $self = shift;
my %params = @_;
$self->create_statefilesdir();
my $statefile = $self->create_statefile(%params);
my $tmpfile = $self->statefilesdir().'/check__health_tmp_'.$$;
if ((ref($params{save}) eq "HASH") && exists $params{save}->{timestamp}) {
$params{save}->{localtime} = scalar localtime $params{save}->{timestamp};
}
my $seekfh = new IO::File;
if ($seekfh->open($tmpfile, "w")) {
$seekfh->printf("%s", Data::Dumper::Dumper($params{save}));
$seekfh->flush();
$seekfh->close();
$self->debug(sprintf "saved %s to %s",
Data::Dumper::Dumper($params{save}), $statefile);
}
if (! rename $tmpfile, $statefile) {
$self->add_message(UNKNOWN,
sprintf "cannot write status file %s! check your filesystem (permissions/usage/integrity) and disk devices", $statefile);
}
}
sub load_state {
my $self = shift;
my %params = @_;
my $statefile = $self->create_statefile(%params);
if ( -f $statefile) {
our $VAR1;
eval {
require $statefile;
};
if($@) {
printf "rumms\n";
}
$self->debug(sprintf "load %s", Data::Dumper::Dumper($VAR1));
return $VAR1;
} else {
return undef;
}
}
#########################################################
# daemon mode
#
sub check_pidfile {
my $self = shift;
my $fh = new IO::File;
if ($fh->open($self->{pidfile}, "r")) {
my $pid = $fh->getline();
$fh->close();
if (! $pid) {
$self->debug("Found pidfile %s with no valid pid. Exiting.",
$self->{pidfile});
return 0;
} else {
$self->debug("Found pidfile %s with pid %d", $self->{pidfile}, $pid);
kill 0, $pid;
if ($! == Errno::ESRCH) {
$self->debug("This pidfile is stale. Writing a new one");
$self->write_pidfile();
return 1;
} else {
$self->debug("This pidfile is held by a running process. Exiting");
return 0;
}
}
} else {
$self->debug("Found no pidfile. Writing a new one");
$self->write_pidfile();
return 1;
}
}
sub write_pidfile {
my $self = shift;
if (! -d dirname($self->{pidfile})) {
eval "require File::Path;";
if (defined(&File::Path::mkpath)) {
import File::Path;
eval { mkpath(dirname($self->{pidfile})); };
} else {
my @dirs = ();
map {
push @dirs, $_;
mkdir(join('/', @dirs))
if join('/', @dirs) && ! -d join('/', @dirs);
} split(/\//, dirname($self->{pidfile}));
}
}
my $fh = new IO::File;
$fh->autoflush(1);
if ($fh->open($self->{pidfile}, "w")) {
$fh->printf("%s", $$);
$fh->close();
} else {
$self->debug("Could not write pidfile %s", $self->{pidfile});
die "pid file could not be written";
}
}
sub AUTOLOAD {
my $self = shift;
return if ($AUTOLOAD =~ /DESTROY/);
$self->debug("AUTOLOAD %s\n", $AUTOLOAD)
if $self->opts->verbose >= 2;
if ($AUTOLOAD =~ /^(.*)::analyze_and_check_(.*)_subsystem$/) {
my $class = $1;
my $subsystem = $2;
my $analyze = sprintf "analyze_%s_subsystem", $subsystem;
my $check = sprintf "check_%s_subsystem", $subsystem;
my @params = @_;
if (@params) {
# analyzer class
my $subsystem_class = shift @params;
$self->{components}->{$subsystem.'_subsystem'} = $subsystem_class->new();
$self->debug(sprintf "\$self->{components}->{%s_subsystem} = %s->new()",
$subsystem, $subsystem_class);
} else {
$self->$analyze();
$self->debug("call %s()", $analyze);
}
$self->$check();
} elsif ($AUTOLOAD =~ /^(.*)::check_(.*)_subsystem$/) {
my $class = $1;
my $subsystem = sprintf "%s_subsystem", $2;
$self->{components}->{$subsystem}->check();
$self->{components}->{$subsystem}->dump()
if $self->opts->verbose >= 2;
} elsif ($AUTOLOAD =~ /^.*::(status_code|check_messages|nagios_exit|html_string|perfdata_string|selected_perfdata|check_thresholds|get_thresholds|opts)$/) {
return $GLPlugin::plugin->$1(@_);
} elsif ($AUTOLOAD =~ /^.*::(clear_messages|suppress_messages|add_html|add_perfdata|override_opt|create_opt|set_thresholds|force_thresholds)$/) {
$GLPlugin::plugin->$1(@_);
} else {
$self->debug("AUTOLOAD: class %s has no method %s\n",
ref($self), $AUTOLOAD);
}
}
package GLPlugin::Commandline;
use strict;
use constant { OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3, DEPENDENT => 4 };
our %ERRORS = (
'OK' => OK,
'WARNING' => WARNING,
'CRITICAL' => CRITICAL,
'UNKNOWN' => UNKNOWN,
'DEPENDENT' => DEPENDENT,
);
our %STATUS_TEXT = reverse %ERRORS;
sub new {
my $class = shift;
my %params = @_;
my $self = {
perfdata => [],
messages => {
ok => [],
warning => [],
critical => [],
unknown => [],
},
args => [],
opts => GLPlugin::Commandline::Getopt->new(%params),
modes => [],
statefilesdir => undef,
};
foreach (qw(shortname usage version url plugin blurb extra
license timeout)) {
$self->{$_} = $params{$_};
}
bless $self, $class;
$self->{name} = $self->{plugin};
$GLPlugin::plugin = $self;
}
sub AUTOLOAD {
my $self = shift;
return if ($AUTOLOAD =~ /DESTROY/);
$self->debug("AUTOLOAD %s\n", $AUTOLOAD)
if $self->{opts}->verbose >= 2;
if ($AUTOLOAD =~ /^.*::(add_arg|override_opt|create_opt)$/) {
$self->{opts}->$1(@_);
}
}
sub DESTROY {
my $self = shift;
# ohne dieses DESTROY rennt nagios_exit in obiges AUTOLOAD rein
# und fliegt aufs Maul, weil {opts} bereits nicht mehr existiert.
# Unerklaerliches Verhalten.
}
sub debug {
my $self = shift;
my $format = shift;
my $tracefile = "/tmp/".$GLPlugin::pluginname.".trace";
2014-08-24 20:14:08 +00:00
$self->{trace} = -f $tracefile ? 1 : 0;
if ($self->opts->verbose && $self->opts->verbose > 10) {
printf("%s: ", scalar localtime);
printf($format, @_);
printf "\n";
}
if ($self->{trace}) {
my $logfh = new IO::File;
$logfh->autoflush(1);
if ($logfh->open($tracefile, "a")) {
$logfh->printf("%s: ", scalar localtime);
$logfh->printf($format, @_);
$logfh->printf("\n");
$logfh->close();
}
}
}
sub opts {
my $self = shift;
return $self->{opts};
}
sub getopts {
my $self = shift;
$self->opts->getopts();
}
sub add_message {
my $self = shift;
my ($code, @messages) = @_;
$code = (qw(ok warning critical unknown))[$code] if $code =~ /^\d+$/;
$code = lc $code;
push @{$self->{messages}->{$code}}, @messages;
}
sub selected_perfdata {
my $self = shift;
my $label = shift;
if ($self->opts->can("selectedperfdata") && $self->opts->selectedperfdata) {
my $pattern = $self->opts->selectedperfdata;
return ($label =~ /$pattern/i) ? 1 : 0;
} else {
return 1;
}
}
sub add_perfdata {
my ($self, %args) = @_;
#printf "add_perfdata %s\n", Data::Dumper::Dumper(\%args);
#printf "add_perfdata %s\n", Data::Dumper::Dumper($self->{thresholds});
#
# wenn warning, critical, dann wird von oben ein expliziter wert mitgegeben
# wenn thresholds
# wenn label in
# warningx $self->{thresholds}->{$label}->{warning} existiert
# dann nimm $self->{thresholds}->{$label}->{warning}
# ansonsten thresholds->default->warning
#
my $label = $args{label};
my $value = $args{value};
my $uom = $args{uom} || "";
my $format = '%d';
if ($value =~ /\./) {
if (defined $args{places}) {
$value = sprintf '%.'.$args{places}.'f', $value;
} else {
$value = sprintf "%.2f", $value;
}
} else {
$value = sprintf "%d", $value;
}
my $warn = "";
my $crit = "";
my $min = defined $args{min} ? $args{min} : "";
my $max = defined $args{max} ? $args{max} : "";
if ($args{thresholds} || (! exists $args{warning} && ! exists $args{critical})) {
if (exists $self->{thresholds}->{$label}->{warning}) {
$warn = $self->{thresholds}->{$label}->{warning};
} elsif (exists $self->{thresholds}->{default}->{warning}) {
$warn = $self->{thresholds}->{default}->{warning};
}
if (exists $self->{thresholds}->{$label}->{critical}) {
$crit = $self->{thresholds}->{$label}->{critical};
} elsif (exists $self->{thresholds}->{default}->{critical}) {
$crit = $self->{thresholds}->{default}->{critical};
}
} else {
if ($args{warning}) {
$warn = $args{warning};
}
if ($args{critical}) {
$crit = $args{critical};
}
}
if ($uom eq "%") {
$min = 0;
$max = 100;
}
if (defined $args{places}) {
# cut off excessive decimals which may be the result of a division
# length = places*2, no trailing zeroes
if ($warn ne "") {
$warn = join("", map {
s/\.0+$//; $_
} map {
s/(\.[1-9]+)0+$/$1/; $_
} map {
/[\+\-\d\.]+/ ? sprintf '%.'.2*$args{places}.'f', $_ : $_;
} split(/([\+\-\d\.]+)/, $warn));
}
if ($crit ne "") {
$crit = join("", map {
s/\.0+$//; $_
} map {
s/(\.[1-9]+)0+$/$1/; $_
} map {
/[\+\-\d\.]+/ ? sprintf '%.'.2*$args{places}.'f', $_ : $_;
} split(/([\+\-\d\.]+)/, $crit));
}
if ($min ne "") {
$min = join("", map {
s/\.0+$//; $_
} map {
s/(\.[1-9]+)0+$/$1/; $_
} map {
/[\+\-\d\.]+/ ? sprintf '%.'.2*$args{places}.'f', $_ : $_;
} split(/([\+\-\d\.]+)/, $min));
}
if ($max ne "") {
$max = join("", map {
s/\.0+$//; $_
} map {
s/(\.[1-9]+)0+$/$1/; $_
} map {
/[\+\-\d\.]+/ ? sprintf '%.'.2*$args{places}.'f', $_ : $_;
} split(/([\+\-\d\.]+)/, $max));
}
}
push @{$self->{perfdata}}, sprintf("'%s'=%s%s;%s;%s;%s;%s",
$label, $value, $uom, $warn, $crit, $min, $max)
if $self->selected_perfdata($label);
}
sub add_html {
my $self = shift;
my $line = shift;
push @{$self->{html}}, $line;
}
sub suppress_messages {
my $self = shift;
$self->{suppress_messages} = 1;
}
sub clear_messages {
my $self = shift;
my $code = shift;
$code = (qw(ok warning critical unknown))[$code] if $code =~ /^\d+$/;
$code = lc $code;
$self->{messages}->{$code} = [];
}
sub check_messages {
my $self = shift;
my %args = @_;
# Add object messages to any passed in as args
for my $code (qw(critical warning unknown ok)) {
my $messages = $self->{messages}->{$code} || [];
if ($args{$code}) {
unless (ref $args{$code} eq 'ARRAY') {
if ($code eq 'ok') {
$args{$code} = [ $args{$code} ];
}
}
push @{$args{$code}}, @$messages;
} else {
$args{$code} = $messages;
}
}
my %arg = %args;
$arg{join} = ' ' unless defined $arg{join};
# Decide $code
my $code = OK;
$code ||= CRITICAL if @{$arg{critical}};
$code ||= WARNING if @{$arg{warning}};
$code ||= UNKNOWN if @{$arg{unknown}};
return $code unless wantarray;
# Compose message
my $message = '';
if ($arg{join_all}) {
$message = join( $arg{join_all},
map { @$_ ? join( $arg{'join'}, @$_) : () }
$arg{critical},
$arg{warning},
$arg{unknown},
$arg{ok} ? (ref $arg{ok} ? $arg{ok} : [ $arg{ok} ]) : []
);
}
else {
$message ||= join( $arg{'join'}, @{$arg{critical}} )
if $code == CRITICAL;
$message ||= join( $arg{'join'}, @{$arg{warning}} )
if $code == WARNING;
$message ||= join( $arg{'join'}, @{$arg{unknown}} )
if $code == UNKNOWN;
$message ||= ref $arg{ok} ? join( $arg{'join'}, @{$arg{ok}} ) : $arg{ok}
if $arg{ok};
}
return ($code, $message);
}
sub status_code {
my $self = shift;
my $code = shift;
$code = (qw(ok warning critical unknown))[$code] if $code =~ /^\d+$/;
$code = uc $code;
$code = $ERRORS{$code} if defined $code && exists $ERRORS{$code};
$code = UNKNOWN unless defined $code && exists $STATUS_TEXT{$code};
return "$STATUS_TEXT{$code}";
}
sub perfdata_string {
my $self = shift;
if (scalar (@{$self->{perfdata}})) {
return join(" ", @{$self->{perfdata}});
} else {
return "";
}
}
sub html_string {
my $self = shift;
if (scalar (@{$self->{html}})) {
return join(" ", @{$self->{html}});
} else {
return "";
}
}
sub nagios_exit {
my $self = shift;
my ($code, $message, $arg) = @_;
$code = $ERRORS{$code} if defined $code && exists $ERRORS{$code};
$code = UNKNOWN unless defined $code && exists $STATUS_TEXT{$code};
$message = '' unless defined $message;
if (ref $message && ref $message eq 'ARRAY') {
$message = join(' ', map { chomp; $_ } @$message);
} else {
chomp $message;
}
if ($self->opts->negate) {
foreach my $from (keys %{$self->opts->negate}) {
if ((uc $from) =~ /^(OK|WARNING|CRITICAL|UNKNOWN)$/ &&
(uc $self->opts->negate->{$from}) =~ /^(OK|WARNING|CRITICAL|UNKNOWN)$/) {
if ($code == $ERRORS{uc $from}) {
$code = $ERRORS{uc $self->opts->negate->{$from}};
}
}
}
}
my $output = "$STATUS_TEXT{$code}";
$output .= " - $message" if defined $message && $message ne '';
if (scalar (@{$self->{perfdata}})) {
$output .= " | ".$self->perfdata_string();
}
$output .= "\n";
if (! exists $self->{suppress_messages}) {
print $output;
}
exit $code;
}
sub set_thresholds {
my $self = shift;
my %params = @_;
if (exists $params{metric}) {
my $metric = $params{metric};
# erst die hartcodierten defaultschwellwerte
$self->{thresholds}->{$metric}->{warning} = $params{warning};
$self->{thresholds}->{$metric}->{critical} = $params{critical};
# dann die defaultschwellwerte von der kommandozeile
if (defined $self->opts->warning) {
$self->{thresholds}->{$metric}->{warning} = $self->opts->warning;
}
if (defined $self->opts->critical) {
$self->{thresholds}->{$metric}->{critical} = $self->opts->critical;
}
# dann die ganz spezifischen schwellwerte von der kommandozeile
if ($self->opts->warningx) { # muss nicht auf defined geprueft werden, weils ein hash ist
foreach my $key (keys %{$self->opts->warningx}) {
next if $key ne $metric;
$self->{thresholds}->{$metric}->{warning} = $self->opts->warningx->{$key};
}
}
if ($self->opts->criticalx) {
foreach my $key (keys %{$self->opts->criticalx}) {
next if $key ne $metric;
$self->{thresholds}->{$metric}->{critical} = $self->opts->criticalx->{$key};
}
}
} else {
$self->{thresholds}->{default}->{warning} =
defined $self->opts->warning ? $self->opts->warning : defined $params{warning} ? $params{warning} : 0;
$self->{thresholds}->{default}->{critical} =
defined $self->opts->critical ? $self->opts->critical : defined $params{critical} ? $params{critical} : 0;
}
}
sub force_thresholds {
my $self = shift;
my %params = @_;
if (exists $params{metric}) {
my $metric = $params{metric};
$self->{thresholds}->{$metric}->{warning} = $params{warning} || 0;
$self->{thresholds}->{$metric}->{critical} = $params{critical} || 0;
} else {
$self->{thresholds}->{default}->{warning} = $params{warning} || 0;
$self->{thresholds}->{default}->{critical} = $params{critical} || 0;
}
}
sub get_thresholds {
my $self = shift;
my @params = @_;
if (scalar(@params) > 1) {
my %params = @params;
my $metric = $params{metric};
return ($self->{thresholds}->{$metric}->{warning},
$self->{thresholds}->{$metric}->{critical});
} else {
return ($self->{thresholds}->{default}->{warning},
$self->{thresholds}->{default}->{critical});
}
}
sub check_thresholds {
my $self = shift;
my @params = @_;
my $level = $ERRORS{OK};
my $warningrange;
my $criticalrange;
my $value;
if (scalar(@params) > 1) {
my %params = @params;
$value = $params{value};
my $metric = $params{metric};
if ($metric ne 'default') {
$warningrange = exists $self->{thresholds}->{$metric}->{warning} ?
$self->{thresholds}->{$metric}->{warning} :
$self->{thresholds}->{default}->{warning};
$criticalrange = exists $self->{thresholds}->{$metric}->{critical} ?
$self->{thresholds}->{$metric}->{critical} :
$self->{thresholds}->{default}->{critical};
} else {
$warningrange = (defined $params{warning}) ?
$params{warning} : $self->{thresholds}->{default}->{warning};
$criticalrange = (defined $params{critical}) ?
$params{critical} : $self->{thresholds}->{default}->{critical};
}
} else {
$value = $params[0];
$warningrange = $self->{thresholds}->{default}->{warning};
$criticalrange = $self->{thresholds}->{default}->{critical};
}
if ($warningrange =~ /^([-+]?[0-9]*\.?[0-9]+)$/) {
# warning = 10, warn if > 10 or < 0
$level = $ERRORS{WARNING}
if ($value > $1 || $value < 0);
} elsif ($warningrange =~ /^([-+]?[0-9]*\.?[0-9]+):$/) {
# warning = 10:, warn if < 10
$level = $ERRORS{WARNING}
if ($value < $1);
} elsif ($warningrange =~ /^~:([-+]?[0-9]*\.?[0-9]+)$/) {
# warning = ~:10, warn if > 10
$level = $ERRORS{WARNING}
if ($value > $1);
} elsif ($warningrange =~ /^([-+]?[0-9]*\.?[0-9]+):([-+]?[0-9]*\.?[0-9]+)$/) {
# warning = 10:20, warn if < 10 or > 20
$level = $ERRORS{WARNING}
if ($value < $1 || $value > $2);
} elsif ($warningrange =~ /^@([-+]?[0-9]*\.?[0-9]+):([-+]?[0-9]*\.?[0-9]+)$/) {
# warning = @10:20, warn if >= 10 and <= 20
$level = $ERRORS{WARNING}
if ($value >= $1 && $value <= $2);
}
if ($criticalrange =~ /^([-+]?[0-9]*\.?[0-9]+)$/) {
# critical = 10, crit if > 10 or < 0
$level = $ERRORS{CRITICAL}
if ($value > $1 || $value < 0);
} elsif ($criticalrange =~ /^([-+]?[0-9]*\.?[0-9]+):$/) {
# critical = 10:, crit if < 10
$level = $ERRORS{CRITICAL}
if ($value < $1);
} elsif ($criticalrange =~ /^~:([-+]?[0-9]*\.?[0-9]+)$/) {
# critical = ~:10, crit if > 10
$level = $ERRORS{CRITICAL}
if ($value > $1);
} elsif ($criticalrange =~ /^([-+]?[0-9]*\.?[0-9]+):([-+]?[0-9]*\.?[0-9]+)$/) {
# critical = 10:20, crit if < 10 or > 20
$level = $ERRORS{CRITICAL}
if ($value < $1 || $value > $2);
} elsif ($criticalrange =~ /^@([-+]?[0-9]*\.?[0-9]+):([-+]?[0-9]*\.?[0-9]+)$/) {
# critical = @10:20, crit if >= 10 and <= 20
$level = $ERRORS{CRITICAL}
if ($value >= $1 && $value <= $2);
}
return $level;
}
package GLPlugin::Commandline::Getopt;
use strict;
use File::Basename;
use Getopt::Long qw(:config no_ignore_case bundling);
# Standard defaults
my %DEFAULT = (
timeout => 15,
verbose => 0,
license =>
"This monitoring plugin is free software, and comes with ABSOLUTELY NO WARRANTY.
It may be used, redistributed and/or modified under the terms of the GNU
General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt).",
);
# Standard arguments
my @ARGS = ({
spec => 'usage|?',
help => "-?, --usage\n Print usage information",
}, {
spec => 'help|h',
help => "-h, --help\n Print detailed help screen",
}, {
spec => 'version|V',
help => "-V, --version\n Print version information",
}, {
#spec => 'extra-opts:s@',
#help => "--extra-opts=[<section>[@<config_file>]]\n Section and/or config_file from which to load extra options (may repeat)",
}, {
spec => 'timeout|t=i',
help => sprintf("-t, --timeout=INTEGER\n Seconds before plugin times out (default: %s)", $DEFAULT{timeout}),
default => $DEFAULT{timeout},
}, {
spec => 'verbose|v+',
help => "-v, --verbose\n Show details for command-line debugging (can repeat up to 3 times)",
default => $DEFAULT{verbose},
},
);
# Standard arguments we traditionally display last in the help output
my %DEFER_ARGS = map { $_ => 1 } qw(timeout verbose);
sub _init {
my $self = shift;
my %params = @_;
# Check params
my %attr = (
usage => 1,
version => 0,
url => 0,
plugin => { default => $GLPlugin::pluginname },
2014-08-24 20:14:08 +00:00
blurb => 0,
extra => 0,
'extra-opts' => 0,
license => { default => $DEFAULT{license} },
timeout => { default => $DEFAULT{timeout} },
);
# Add attr to private _attr hash (except timeout)
$self->{timeout} = delete $attr{timeout};
$self->{_attr} = { %attr };
foreach (keys %{$self->{_attr}}) {
if (exists $params{$_}) {
$self->{_attr}->{$_} = $params{$_};
} else {
$self->{_attr}->{$_} = $self->{_attr}->{$_}->{default}
if ref ($self->{_attr}->{$_}) eq 'HASH' &&
exists $self->{_attr}->{$_}->{default};
}
}
# Chomp _attr values
chomp foreach values %{$self->{_attr}};
# Setup initial args list
$self->{_args} = [ grep { exists $_->{spec} } @ARGS ];
$self
}
sub new {
my $class = shift;
my $self = bless {}, $class;
$self->_init(@_);
}
sub add_arg {
my $self = shift;
my %arg = @_;
push (@{$self->{_args}}, \%arg);
}
sub getopts {
my $self = shift;
my %commandline = ();
my @params = map { $_->{spec} } @{$self->{_args}};
if (! GetOptions(\%commandline, @params)) {
$self->print_help();
exit 0;
} else {
no strict 'refs';
no warnings 'redefine';
do { $self->print_help(); exit 0; } if $commandline{help};
do { $self->print_version(); exit 0 } if $commandline{version};
do { $self->print_usage(); exit 3 } if $commandline{usage};
foreach (map { $_->{spec} =~ /^([\w\-]+)/; $1; } @{$self->{_args}}) {
my $field = $_;
*{"$field"} = sub {
return $self->{opts}->{$field};
};
}
foreach (map { $_->{spec} =~ /^([\w\-]+)/; $1; }
grep { exists $_->{required} && $_->{required} } @{$self->{_args}}) {
do { $self->print_usage(); exit 0 } if ! exists $commandline{$_};
}
foreach (grep { exists $_->{default} } @{$self->{_args}}) {
$_->{spec} =~ /^([\w\-]+)/;
my $spec = $1;
$self->{opts}->{$spec} = $_->{default};
}
foreach (keys %commandline) {
$self->{opts}->{$_} = $commandline{$_};
}
foreach (grep { exists $_->{env} } @{$self->{_args}}) {
$_->{spec} =~ /^([\w\-]+)/;
my $spec = $1;
if (exists $ENV{'NAGIOS__HOST'.$_->{env}}) {
$self->{opts}->{$spec} = $ENV{'NAGIOS__HOST'.$_->{env}};
}
if (exists $ENV{'NAGIOS__SERVICE'.$_->{env}}) {
$self->{opts}->{$spec} = $ENV{'NAGIOS__SERVICE'.$_->{env}};
}
}
foreach (grep { exists $_->{aliasfor} } @{$self->{_args}}) {
my $field = $_->{aliasfor};
$_->{spec} =~ /^([\w\-]+)/;
my $aliasfield = $1;
next if $self->{opts}->{$field};
*{"$field"} = sub {
return $self->{opts}->{$aliasfield};
};
}
}
}
sub create_opt {
my $self = shift;
my $key = shift;
no strict 'refs';
*{"$key"} = sub {
return $self->{opts}->{$key};
};
}
sub override_opt {
my $self = shift;
my $key = shift;
my $value = shift;
$self->{opts}->{$key} = $value;
}
sub get {
my $self = shift;
my $opt = shift;
return $self->{opts}->{$opt};
}
sub print_help {
my $self = shift;
$self->print_version();
printf "\n%s\n", $self->{_attr}->{license};
printf "\n%s\n\n", $self->{_attr}->{blurb};
$self->print_usage();
foreach (@{$self->{_args}}) {
printf " %s\n", $_->{help};
}
exit 0;
}
sub print_usage {
my $self = shift;
printf $self->{_attr}->{usage}, $self->{_attr}->{plugin};
print "\n";
}
sub print_version {
my $self = shift;
printf "%s %s", $self->{_attr}->{plugin}, $self->{_attr}->{version};
printf " [%s]", $self->{_attr}->{url} if $self->{_attr}->{url};
print "\n";
}
sub print_license {
my $self = shift;
printf "%s\n", $self->{_attr}->{license};
print "\n";
}
package GLPlugin::Item;
our @ISA = qw(GLPlugin);
use strict;
sub new {
my $class = shift;
my %params = @_;
my $self = {
blacklisted => 0,
info => undef,
extendedinfo => undef,
};
bless $self, $class;
$self->init(%params);
return $self;
}
sub check {
my $self = shift;
my $lists = shift;
my @lists = $lists ? @{$lists} : grep { ref($self->{$_}) eq "ARRAY" } keys %{$self};
foreach my $list (@lists) {
$self->add_info('checking '.$list);
foreach my $element (@{$self->{$list}}) {
$element->blacklist() if $self->is_blacklisted();
$element->check();
}
}
}
package GLPlugin::TableItem;
our @ISA = qw(GLPlugin::Item);
use strict;
sub new {
my $class = shift;
my %params = @_;
my $self = {};
bless $self, $class;
foreach (keys %params) {
$self->{$_} = $params{$_};
}
if ($self->can("finish")) {
$self->finish(%params);
}
return $self;
}
sub check {
my $self = shift;
# some tableitems are not checkable, they are only used to enhance other
# items (e.g. sensorthresholds enhance sensors)
# normal tableitems should have their own check-method
}