#
# $Id$
#
-# Copyright (C) 2008-2010 Trond H. Amundsen
+# Copyright (C) 2008-2011 Trond H. Amundsen
#
# 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
# Version and similar info
$NAME = 'check_openmanage';
-$VERSION = '3.6.4-beta3';
+$VERSION = '3.7.0';
$AUTHOR = 'Trond H. Amundsen';
$CONTACT = 't.h.amundsen@usit.uio.no';
GENERAL OPTIONS:
- -p, --perfdata Output performance data [default=no]
- -t, --timeout Plugin timeout in seconds [default=30]
- -c, --critical Custom temperature critical limits
- -w, --warning Custom temperature warning limits
- -d, --debug Debug output, reports everything
- -h, --help Display this help text
- -V, --version Display version info
+ -f, --config Specify configuration file
+ -p, --perfdata Output performance data [default=no]
+ -t, --timeout Plugin timeout in seconds [default=30]
+ -c, --critical Custom temperature critical limits
+ -w, --warning Custom temperature warning limits
+ -F, --fahrenheit Use Fahrenheit as temperature unit
+ -d, --debug Debug output, reports everything
+ -h, --help Display this help text
+ -V, --version Display version info
SNMP OPTIONS:
- -H, --hostname Hostname or IP (required for SNMP)
- -C, --community SNMP community string [default=public]
- -P, --protocol SNMP protocol version [default=2]
- --port SNMP port number [default=161]
- -6, --ipv6 Use IPv6 instead of IPv4 [default=no]
- --tcp Use TCP instead of UDP [default=no]
+ -H, --hostname Hostname or IP (required for SNMP)
+ -C, --community SNMP community string [default=public]
+ -P, --protocol SNMP protocol version [default=2]
+ --port SNMP port number [default=161]
+ -6, --ipv6 Use IPv6 instead of IPv4 [default=no]
+ --tcp Use TCP instead of UDP [default=no]
OUTPUT OPTIONS:
- -i, --info Prefix any alerts with the service tag
- -e, --extinfo Append system info to alerts
- -s, --state Prefix alerts with alert state
- -S, --short-state Prefix alerts with alert state abbreviated
- -o, --okinfo Verbosity when check result is OK
- -I, --htmlinfo HTML output with clickable links
+ -i, --info Prefix any alerts with the service tag
+ -e, --extinfo Append system info to alerts
+ -s, --state Prefix alerts with alert state
+ -S, --short-state Prefix alerts with alert state abbreviated
+ -o, --okinfo Verbosity when check result is OK
+ -B, --show-blacklist Show blacklistings in OK output
+ -I, --htmlinfo HTML output with clickable links
CHECK CONTROL AND BLACKLISTING:
- -a, --all Check everything, even log content
- -b, --blacklist Blacklist missing and/or failed components
- --only Only check a certain component or alert type
- --check Fine-tune which components are checked
- --no-storage Don't check storage
+ -a, --all Check everything, even log content
+ -b, --blacklist Blacklist missing and/or failed components
+ --only Only check a certain component or alert type
+ --check Fine-tune which components are checked
+ --no-storage Don't check storage
For more information and advanced options, see the manual page or URL:
http://folk.uio.no/trondham/software/check_openmanage.html
# Version and license text
$LICENSE = <<"END_LICENSE";
$NAME $VERSION
-Copyright (C) 2008-2010 $AUTHOR
+Copyright (C) 2008-2011 $AUTHOR
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
'check' => [], # check control
'critical' => [], # temperature critical limits
'warning' => [], # temperature warning limits
+ 'tempunit' => 'C', # temperature unit
+ 'fahrenheit' => 0, # Use fahrenheit
+ 'configfile' => undef, # configuration file
'timeout' => 30, # default timeout is 30 seconds
'debug' => 0, # debugging / verbose output
'help' => 0, # display help output
'perfdata' => undef, # output performance data
+ 'legacy_perfdata' => 0, # legacy performance data output
'info' => 0, # display servicetag
'extinfo' => 0, # display extra info
'htmlinfo' => undef, # html tags in output
'state' => 0, # display alert type
'short-state' => 0, # display alert type (short)
'okinfo' => 0, # default "ok" output level
+ 'show_blacklist' => 0, # show blacklisted components
'linebreak' => undef, # specify linebreak
'version' => 0, # plugin version info
'all' => 0, # check everything
'check=s' => \@{ $opt{check} },
'c|critical=s' => \@{ $opt{critical} },
'w|warning=s' => \@{ $opt{warning} },
+ 'tempunit=s' => \$opt{tempunit},
+ 'F|fahrenheit' => \$opt{fahrenheit},
+ 'f|configfile=s' => \$opt{configfile},
't|timeout=i' => \$opt{timeout},
'd|debug' => \$opt{debug},
'h|help' => \$opt{help},
'V|version' => \$opt{version},
'p|perfdata:s' => \$opt{perfdata},
+ 'legacy-perfdata' => \$opt{legacy_perfdata},
'i|info' => \$opt{info},
'e|extinfo' => \$opt{extinfo},
'I|htmlinfo:s' => \$opt{htmlinfo},
's|state' => \$opt{state},
'S|short-state' => \$opt{shortstate},
'o|ok-info=i' => \$opt{okinfo},
+ 'B|show-blacklist' => \$opt{show_blacklist},
'linebreak=s' => \$opt{linebreak},
'a|all' => \$opt{all},
'only=s' => \$opt{only},
# If user requested help
if ($opt{help}) {
print $USAGE, $HELP;
- exit $E_OK;
+ exit $E_UNKNOWN;
}
# If user requested version info
if ($opt{version}) {
print $LICENSE;
- exit $E_OK;
-}
-
-# Setting timeout
-$SIG{ALRM} = sub {
- print "PLUGIN TIMEOUT: $NAME timed out after $opt{timeout} seconds\n";
exit $E_UNKNOWN;
-};
-alarm $opt{timeout};
-
-# If we're using SNMP
-$snmp = defined $opt{hostname} ? 1 : 0;
-
-# SNMP session variables
-$snmp_session = undef;
-$snmp_error = undef;
+}
-# The omreport command
-$omreport = undef;
+# Initialize blacklist
+%blacklist = ();
# Check flags, override available with the --check option
%check = ( 'storage' => 1, # check storage subsystem
'esmhealth' => 1, # check the ESM log overall health
);
+# Messages
+@report_storage = (); # messages with associated nagios level (storage)
+@report_chassis = (); # messages with associated nagios level (chassis)
+@report_other = (); # messages with associated nagios level (other)
+
+# Read config file
+parse_configfile() if defined $opt{configfile};
+
+# Setting timeout
+$SIG{ALRM} = sub {
+ print "PLUGIN TIMEOUT: $NAME timed out after $opt{timeout} seconds\n";
+ exit $E_UNKNOWN;
+};
+alarm $opt{timeout};
+
+# If we're using SNMP
+$snmp = defined $opt{hostname} ? 1 : 0;
+
+# SNMP session variables
+$snmp_session = undef;
+$snmp_error = undef;
+
+# The omreport command
+$omreport = undef;
+
# Default line break
$linebreak = isatty(*STDOUT) ? "\n" : '<br/>';
@enclosures = (); # enclosures
%snmp_enclosure = (); # enclosures
-# Messages
-@report_storage = (); # messages with associated nagios level (storage)
-@report_chassis = (); # messages with associated nagios level (chassis)
-@report_other = (); # messages with associated nagios level (other)
-
# Counters for everything
%count
= (
adjust_checks() if defined $opt{check};
# Blacklisted components
-%blacklist = defined $opt{blacklist} ? %{ get_blacklist() } : ();
+set_blacklist($opt{blacklist}) if defined $opt{blacklist};
# If blacklisting is in effect, don't check global health status
if (scalar keys %blacklist > 0) {
check_omreport_options();
}
+# Temperature unit
+if ($opt{fahrenheit}) {
+ $opt{tempunit} = 'F';
+}
+
+# Check tempunit syntax
+if ($opt{tempunit} !~ m{\A C|F|K|R \z}xms) {
+ print "ERROR: Unknown temperature unit '$opt{tempunit}'\n";
+ exit $E_UNKNOWN;
+}
#---------------------------------------------------------------------
# Helper functions
#---------------------------------------------------------------------
+# Make a regex from a glob pattern. Shamelessly stolen from Perl
+# Cookbook chapter 6.9
+sub glob2regex {
+ my $globstr = shift;
+ my %patmap
+ = ( '*' => '.*',
+ '?' => '.',
+ '[' => '[',
+ ']' => ']',
+ );
+ $globstr =~ s{(.)} { $patmap{$1} || "\Q$1" }ge;
+ return '\A' . $globstr . '\z';
+}
+
+#
+# Read config file
+#
+sub parse_configfile {
+ our $tiny = undef;
+
+ # Regexp for boolean values
+ our $off = qr{\A (0|off|false) \s* \z}ixms;
+ our $on = qr{\A (1|on|true) \s* \z}ixms;
+
+ # Mapping between command line options and the corresponding
+ # config file options
+ our %opt2config
+ = ( 'info' => 'output_servicetag',
+ 'extinfo' => 'output_sysinfo',
+ 'postmsg' => 'output_post_message',
+ 'state' => 'output_servicestate',
+ 'shortstate' => 'output_servicestate_abbr',
+ 'show_blacklist' => 'output_blacklist',
+ 'htmlinfo' => 'output_html',
+ 'okinfo' => 'output_ok_verbosity',
+ 'protocol' => 'snmp_version',
+ 'community' => 'snmp_community',
+ 'port' => 'snmp_port',
+ 'ipv6' => 'snmp_use_ipv6',
+ 'tcp' => 'snmp_use_tcp',
+ 'warning' => 'temp_threshold_warning',
+ 'critical' => 'temp_threshold_critical',
+ 'all' => 'check_everything',
+ 'perfdata' => 'performance_data',
+ 'tempunit' => 'temperature_unit',
+ 'timeout' => 'timeout',
+ 'blacklist' => 'blacklist',
+ 'legacy_perfdata' => 'legacy_performance_data',
+ );
+
+ # Load the perl module
+ if ( eval { require Config::Tiny; 1 } ) {
+ $tiny = Config::Tiny->new();
+ }
+ else {
+ print "ERROR: Required perl module 'Config::Tiny' not found\n";
+ exit $E_UNKNOWN;
+ }
+
+ # Read the config file
+ $tiny = Config::Tiny->read($opt{configfile})
+ or do { report('other', (sprintf q{Couldn't read configuration file: %s}, Config::Tiny->errstr()), $E_UNKNOWN);
+ return; };
+
+ # Syntax check
+ foreach my $section (keys %{ $tiny }) {
+ KEYWORD:
+ foreach my $keyword (keys %{ $tiny->{$section} }) {
+ next KEYWORD if $keyword eq 'check_everything';
+ if ($keyword =~ m{\A check_(.+)}xms) {
+ my $c = $1;
+ foreach my $cl (keys %check) {
+ next KEYWORD if $c eq $cl;
+ }
+ }
+ else {
+ LEGAL:
+ foreach my $legal (keys %opt2config) {
+ next KEYWORD if $keyword eq $opt2config{$legal};
+ }
+ }
+ if ($section eq '_') {
+ report('other', qq{CONFIG ERROR: In the global section: Unknown statement "$keyword"}, $E_UNKNOWN);
+ }
+ else {
+ report('other', qq{CONFIG ERROR: Unknown statement "$keyword" in section "$section"}, $E_UNKNOWN);
+ }
+ }
+ }
+
+ # Adjust checks according to statements in the configuration file
+ sub configfile_adjust_checks {
+ my $keyword = shift;
+ CHECK_CONFIG:
+ foreach my $key (keys %check) {
+ my $copt = join '_', 'check', $key;
+ next CHECK_CONFIG if !defined $tiny->{$keyword}->{$copt} or $tiny->{$keyword}->{$copt} eq q{};
+ if ($tiny->{$keyword}->{$copt} =~ m{$on}ixms) {
+ $check{$key} = 1;
+ }
+ elsif ($tiny->{$keyword}->{$copt} =~ m{$off}ixms) {
+ $check{$key} = 0;
+ }
+ else {
+ report('other', "CONFIG ERROR: Rvalue for '$copt' must be boolean (True/False)", $E_UNKNOWN);
+ }
+ }
+ return;
+ }
+
+ # Set blacklist according to statements in the configuration file
+ sub configfile_set_blacklist {
+ my $keyword = shift;
+ if (defined $tiny->{$keyword}->{blacklist} and $tiny->{$keyword}->{blacklist} ne q{}) {
+ # set_blacklist() takes an array ref
+ set_blacklist([$tiny->{$keyword}->{blacklist}]);
+ }
+ return;
+ }
+
+ # Set timeout according to statements in the configuration file
+ sub configfile_set_timeout {
+ my $keyword = shift;
+ if (defined $tiny->{$keyword}->{timeout} and $tiny->{$keyword}->{timeout} ne q{}) {
+ if ($tiny->{$keyword}->{timeout} =~ m{\A \d+ \z}xms) { # integer
+ $opt{timeout} = $tiny->{$keyword}->{timeout};
+ }
+ else {
+ report('other', "CONFIG ERROR: Rvalue for 'timeout' must be a positive integer", $E_UNKNOWN);
+ }
+ }
+ return;
+ }
+
+ # Set a boolean option
+ sub configfile_set_boolean {
+ my ($keyword, $bool) = @_;
+ my $cbool = $opt2config{$bool};
+ if (defined $tiny->{$keyword}->{$cbool} and $tiny->{$keyword}->{$cbool} ne q{}) {
+ if ($tiny->{$keyword}->{$cbool} =~ m{$on}ixms) {
+ $opt{$bool} = 1;
+ }
+ elsif ($tiny->{$keyword}->{$cbool} =~ m{$off}ixms) {
+ $opt{$bool} = 0;
+ }
+ else {
+ report('other', "CONFIG ERROR: Rvalue for '$cbool' must be boolean (True/False)", $E_UNKNOWN);
+ }
+ }
+ return;
+ }
+
+ # Set htmlinfo option from config file
+ sub configfile_set_htmlinfo {
+ my $keyword = shift;
+ my $conf = $opt2config{htmlinfo};
+ if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+ if ($tiny->{$keyword}->{$conf} =~ m{$on}ixms) {
+ $opt{htmlinfo} = 1;
+ }
+ elsif ($tiny->{$keyword}->{$conf} =~ m{$off}ixms) {
+ $opt{htmlinfo} = undef;
+ }
+ else {
+ $opt{htmlinfo} = $tiny->{$keyword}->{$conf};
+ }
+ }
+ return;
+ }
+
+ # Set OK output verbosity
+ sub configfile_set_ok_verbosity {
+ my $keyword = shift;
+ my $conf = $opt2config{okinfo};
+ if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+ if ($tiny->{$keyword}->{$conf} =~ m{\A \d+ \z}xms) {
+ $opt{okinfo} = $tiny->{$keyword}->{$conf};
+ }
+ else {
+ report('other', "CONFIG ERROR: Rvalue for '$conf' must be a positive integer", $E_UNKNOWN);
+ }
+ }
+ return;
+ }
+
+ # Set SNMP protocol version from config file
+ sub configfile_set_snmp_version {
+ my $keyword = shift;
+ my $conf = $opt2config{protocol};
+ if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+ if ($tiny->{$keyword}->{$conf} =~ m{\A 1|2|3 \z}xms) {
+ $opt{protocol} = $tiny->{$keyword}->{$conf};
+ }
+ else {
+ report('other', "CONFIG ERROR: Rvalue for '$conf' must be '1', '2' or '3'", $E_UNKNOWN);
+ }
+ }
+ return;
+ }
+
+ # Set SNMP community name from config file
+ sub configfile_set_snmp_community {
+ my $keyword = shift;
+ my $conf = $opt2config{community};
+ if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+ $opt{community} = $tiny->{$keyword}->{$conf};
+ }
+ return;
+ }
+
+ # Set SNMP port number from config file
+ sub configfile_set_snmp_port {
+ my $keyword = shift;
+ my $conf = $opt2config{port};
+ if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+ if ($tiny->{$keyword}->{$conf} =~ m{\A \d+ \z}xms) { # integer
+ $opt{port} = $tiny->{$keyword}->{$conf};
+ }
+ else {
+ report('other', "CONFIG ERROR: Rvalue for '$conf' must be a positive integer", $E_UNKNOWN);
+ }
+ }
+ return;
+ }
+
+ # Set temperature threshold from config file
+ sub configfile_set_temp_threshold {
+ my $keyword = shift;
+ my $level = shift;
+ my $conf = $opt2config{$level};
+ if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+ $opt{$level} = [$tiny->{$keyword}->{$conf}]; # array ref
+ }
+ return;
+ }
+
+ # Set perfdata from config file
+ sub configfile_set_perfdata {
+ my $keyword = shift;
+ my $conf = $opt2config{perfdata};
+ if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+ if ($tiny->{$keyword}->{$conf} =~ m{$on}ixms) {
+ $opt{perfdata} = 1;
+ }
+ elsif ($tiny->{$keyword}->{$conf} =~ m{$off}ixms) {
+ $opt{perfdata} = undef;
+ }
+ elsif ($tiny->{$keyword}->{$conf} =~ m{\A minimal|multiline \z}xms) {
+ $opt{perfdata} = $tiny->{$keyword}->{$conf};
+ }
+ else {
+ report('other', "CONFIG ERROR: Rvalue for '$conf' must be either boolean, 'minimal' or 'multiline'", $E_UNKNOWN);
+ }
+ }
+ return;
+ }
+
+ # Set temp unit from config file
+ sub configfile_set_tempunit {
+ my $keyword = shift;
+ my $conf = $opt2config{tempunit};
+ if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+ if ($tiny->{$keyword}->{$conf} =~ m{\A C|F|K|R \z}ixms) {
+ $opt{tempunit} = $tiny->{$keyword}->{$conf};
+ }
+ else {
+ report('other', "CONFIG ERROR: Rvalue for '$conf' must one of C/F/K/R", $E_UNKNOWN);
+ }
+ }
+ return;
+ }
+
+ # Set postmsg string from config file
+ sub configfile_set_postmsg {
+ my $keyword = shift;
+ my $conf = $opt2config{postmsg};
+ if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+ $opt{postmsg} = $tiny->{$keyword}->{$conf}; # array ref
+ }
+ return;
+ }
+
+ # Sections in the config file to check for statements
+ my @sections = ();
+
+ # First: Populate the sections array with the global section
+ @sections = ('_');
+
+ # Second: Populate the sections array with host glob pattern (but
+ # not exact match)
+ PATTERN:
+ foreach my $glob (sort keys %{ $tiny }) {
+ next PATTERN if $glob eq '_'; # global section
+ next PATTERN if $glob eq $opt{hostname}; # exact match
+ my $regex = glob2regex($glob); # make regexp
+ if ($opt{hostname} =~ m{$regex}) {
+ push @sections, $glob;
+ }
+ }
+
+ # Third: Populate the sections array with exact hostname
+ if (defined $tiny->{$opt{hostname}}) {
+ push @sections, $opt{hostname};
+ }
+
+ # Loop through the sections array and get options
+ foreach my $sect (@sections) {
+ configfile_adjust_checks($sect);
+ configfile_set_blacklist($sect);
+ configfile_set_timeout($sect);
+ configfile_set_htmlinfo($sect);
+ configfile_set_ok_verbosity($sect);
+ configfile_set_boolean($sect, 'all');
+ configfile_set_boolean($sect, 'info');
+ configfile_set_boolean($sect, 'extinfo');
+ configfile_set_boolean($sect, 'state');
+ configfile_set_boolean($sect, 'shortstate');
+ configfile_set_boolean($sect, 'show_blacklist');
+ configfile_set_boolean($sect, 'ipv6');
+ configfile_set_boolean($sect, 'tcp');
+ configfile_set_boolean($sect, 'legacy_perfdata');
+ configfile_set_snmp_version($sect);
+ configfile_set_snmp_community($sect);
+ configfile_set_snmp_port($sect);
+ configfile_set_temp_threshold($sect, 'warning');
+ configfile_set_temp_threshold($sect, 'critical');
+ configfile_set_perfdata($sect);
+ configfile_set_tempunit($sect);
+ configfile_set_postmsg($sect);
+ }
+
+ return;
+}
+
#
# Store a message in one of the message arrays
#
return push @{ $type2array{$type} }, [ $msg, $exval, $id ];
}
-
#
# Run command, put resulting output lines in an array and return a
# pointer to that array
# Detecting blade via SNMP
#
sub snmp_detect_blade {
- my $DellBaseBoardType = '1.3.6.1.4.1.674.10892.1.300.80.1.7.1.1';
- my $result = $snmp_session->get_request(-varbindlist => [$DellBaseBoardType]);
+ # In some setups, the IDs for the blade and interconnect
+ # board are mixed up, so we need to check both.
+ my $DellBaseBoardType1 = '1.3.6.1.4.1.674.10892.1.300.80.1.7.1.1';
+ my $DellBaseBoardType2 = '1.3.6.1.4.1.674.10892.1.300.80.1.7.1.2';
+ my $result1 = $snmp_session->get_request(-varbindlist => [$DellBaseBoardType1]);
+ my $result2 = $snmp_session->get_request(-varbindlist => [$DellBaseBoardType2]);
# Identify blade. Older models (4th and 5th gen models) and/or old
# OMSA (4.x) don't have this OID. If we get "noSuchInstance" or
# similar, we assume that this isn't a blade
- if (exists $result->{$DellBaseBoardType} && $result->{$DellBaseBoardType} eq '3') {
+ if (exists $result1->{$DellBaseBoardType1} && $result1->{$DellBaseBoardType1} eq '3') {
$blade = 1;
+ return;
+ }
+ if (exists $result2->{$DellBaseBoardType2} && $result2->{$DellBaseBoardType2} eq '3') {
+ $blade = 1;
+ return;
}
return;
}
# Read the blacklist option and return a hash containing the
# blacklisted components
#
-sub get_blacklist {
+sub set_blacklist {
+ my $foo = shift;
my @bl = ();
- my %blacklist = ();
- if (scalar @{ $opt{blacklist} } >= 0) {
- foreach my $black (@{ $opt{blacklist} }) {
+ if (scalar @{ $foo } >= 0) {
+ foreach my $black (@{ $foo }) {
my $tmp = q{};
if (-f $black) {
open my $BL, '<', $black
next if $c !~ m/=/xms;
my ($key, $val) = split /=/xms, $c;
my @vals = split /,/xms, $val;
- $blacklist{$key} = \@vals;
+ push @{ $blacklist{$key} }, @vals;
}
}
- return \%blacklist;
+ return;
}
#
# adjust the check hash
if ($opt{only} eq 'chassis') {
- map { $check{$_} = 1 } qw(memory fans power temp cpu voltage
+ map { $check{$_} = 1 } qw(memory fans power temp cpu voltage sdcard
batteries amperage intrusion esmhealth);
}
else {
# Workaround for Openmanage BUG introduced in OMSA 5.5.0
$rawtext =~ s{\n;}{;}gxms if $command eq 'storage controller';
+ # Workaround for logical connectors where there are extra
+ # information that isn't possible to parse consistently. Remove
+ # everything after and including "Path Health"
+ if ($command =~ m{\A storage\sconnector}xms) {
+ $rawtext =~ s{Path\sHealth.*}{}xms;
+ }
+
# Report if no controllers found
if ($command eq 'storage controller' and $rawtext =~ m{No\scontrollers\sfound}xms) {
report('storage', 'Storage Error! No controllers found', $E_UNKNOWN);
# This helper function returns the corresponding value of a hash key,
# but takes into account that the key may not exist
sub get_hashval {
- my $key = shift || return undef;
+ my $key = shift || return;
my $hash = shift;
return defined $hash->{$key} ? $hash->{$key} : "Undefined value $key";
}
return $alt;
}
+# Converts from Celsius to something else
+sub temp_from_celsius {
+ my $x = shift;
+ my $to = shift;
+
+ if ($to eq 'F') {
+ return sprintf '%.1f', ($x * 9/5 + 32);
+ }
+ elsif ($to eq 'K') {
+ return sprintf '%.1f', ($x + 273.15);
+ }
+ elsif ($to eq 'R') {
+ return sprintf '%.1f', ($x * 9/5 + 32 + 459.67);
+ }
+ return $x;
+}
+
#---------------------------------------------------------------------
# Check functions
# STORAGE: Check controllers
#-----------------------------------------
sub check_controllers {
- return if blacklisted('ctrl', 'all');
-
my $nexus = undef;
my $name = undef;
my $state = undef;
#-----------------------------------------
sub check_physical_disks {
return if $#controllers == -1;
- return if blacklisted('pdisk', 'all');
my $nexus = undef;
my $name = undef;
my $media = undef; # media type (e.g. HDD, SSD)
my $bus = undef; # bus protocol (e.g. SAS, SATA)
my $spare = undef; # spare state (e.g. global hotspare)
+ my $cert = undef; # if drive is certified or not
my @output = ();
if ($snmp) {
'1.3.6.1.4.1.674.10893.1.20.130.4.1.26' => 'arrayDiskNexusID',
'1.3.6.1.4.1.674.10893.1.20.130.4.1.31' => 'arrayDiskSmartAlertIndication',
'1.3.6.1.4.1.674.10893.1.20.130.4.1.35' => 'arrayDiskMediaType',
+ '1.3.6.1.4.1.674.10893.1.20.130.4.1.36' => 'arrayDiskDellCertified',
'1.3.6.1.4.1.674.10893.1.20.130.5.1.7' => 'arrayDiskEnclosureConnectionControllerNumber',
'1.3.6.1.4.1.674.10893.1.20.130.6.1.7' => 'arrayDiskChannelConnectionControllerNumber',
);
$spare = get_hashval($out->{arrayDiskSpareState}, \%spare_state) || q{};
$bus = get_hashval($out->{arrayDiskBusType}, \%bus_type);
$media = get_hashval($out->{arrayDiskMediaType}, \%media_type);
+ $cert = defined $out->{arrayDiskDellCertified} ? $out->{arrayDiskDellCertified} : 1;
$capacity = exists $out->{arrayDiskLengthInMB}
? $out->{arrayDiskLengthInMB} * 1024**2 : -1;
$media = get_nonempty_string('Media', $out, undef);
$bus = get_nonempty_string('Bus Protocol', $out, undef);
$spare = get_nonempty_string('Hot Spare', $out, q{});
+ $cert = get_nonempty_string('Certified', $out, 1);
$ctrl = $out->{ctrl};
$capacity = get_nonempty_string('Capacity', $out, q{});
$capacity =~ s{\A .*? \((\d+) \s bytes\) \z}{$1}xms;
if ($capacity eq 'Unavailable') {
$capacity = -1;
}
+ if ($cert eq 'Yes' or $cert eq 'Not Applicable') {
+ $cert = 1;
+ }
+ else {
+ $cert = 0;
+ }
}
- next PDISK if blacklisted('pdisk', $nexus);
$count{pdisk}++;
+ next PDISK if blacklisted('pdisk', $nexus);
$vendor =~ s{\s+\z}{}xms; # remove trailing whitespace
$product =~ s{\s+\z}{}xms; # remove trailing whitespace
$name, $vendor, $product, $capacity, $ctrl, $state, $progr;
report('storage', $msg, $E_WARNING, $nexus);
}
+ # Special case: Uncertified disk
+ elsif ($status eq 'Non-Critical' and !$cert) {
+ if (blacklisted('pdisk_cert', $nexus)) {
+ my $msg = sprintf '%s [%s %s, %s] on ctrl %d is %s, Not Certified',
+ $name, $vendor, $product, $capacity, $ctrl, $state;
+ report('storage', $msg, $E_OK, $nexus);
+ }
+ else {
+ my $msg = sprintf '%s [%s %s, %s] on ctrl %d is Not Certified',
+ $name, $vendor, $product, $capacity, $ctrl;
+ report('storage', $msg, $E_WARNING, $nexus);
+ }
+ }
# Default
elsif ($status ne 'Ok') {
my $msg = sprintf '%s [%s %s, %s] on ctrl %d needs attention: %s',
#-----------------------------------------
sub check_virtual_disks {
return if $#controllers == -1;
- return if blacklisted('vdisk', 'all');
my $name = undef;
my $nexus = undef;
1 => 'Concatenated',
2 => 'RAID-0',
3 => 'RAID-1',
+ 4 => 'UNSUPPORTED:raid-2',
+ 5 => 'UNSUPPORTED:raid-3',
+ 6 => 'UNSUPPORTED:raid-4',
7 => 'RAID-5',
8 => 'RAID-6',
+ 9 => 'UNSUPPORTED:raid-7',
10 => 'RAID-10',
+ 11 => 'UNSUPPORTED:raid-30',
12 => 'RAID-50',
+ 13 => 'UNSUPPORTED:addSpares',
+ 14 => 'UNSUPPORTED:deleteLogical',
+ 15 => 'UNSUPPORTED:transformLogical',
+ 18 => 'UNSUPPORTED:raid-0-plus-1',
19 => 'Concatenated RAID-1',
+ 20 => 'UNSUPPORTED:concatRaid-5',
+ 21 => 'UNSUPPORTED:noRaid',
+ 22 => 'UNSUPPORTED:volume',
+ 23 => 'UNSUPPORTED:raidMorph',
24 => 'RAID-60',
25 => 'CacheCade',
);
$nexus = join q{:}, $ctrl, get_nonempty_string('ID', $out, '9999');
}
- next VDISK if blacklisted('vdisk', $nexus);
$count{vdisk}++;
+ next VDISK if blacklisted('vdisk', $nexus);
# The device name is undefined sometimes
$dev = q{} if !defined $dev;
#-----------------------------------------
sub check_cache_battery {
return if $#controllers == -1;
- return if blacklisted('bat', 'all');
my $id = undef;
my $nexus = undef;
$id, $ctrl, $state, $status;
report('storage', $msg, $E_WARNING, $nexus);
}
- # Special case: Failed
- elsif ($state eq 'Failed' && $status eq 'Critical') {
- next BATTERY if blacklisted('bat_charge', $nexus);
- my $msg = sprintf 'Cache Battery %d in controller %d is %s [replace battery]',
- $id, $ctrl, $state;
- report('storage', $msg, $status2nagios{$status}, $nexus);
- }
# Default
else {
my $msg = sprintf 'Cache Battery %d in controller %d is %s',
#-----------------------------------------
sub check_connectors {
return if $#controllers == -1;
- return if blacklisted('conn', 'all');
my $nexus = undef;
my $name = undef;
# STORAGE: Check enclosures
#-----------------------------------------
sub check_enclosures {
- return if blacklisted('encl', 'all');
-
my $id = undef;
my $nexus = undef;
my $name = undef;
#-----------------------------------------
sub check_enclosure_fans {
return if $#controllers == -1;
- return if blacklisted('encl_fan', 'all');
my $nexus = undef;
my $name = undef;
#-----------------------------------------
sub check_enclosure_pwr {
return if $#controllers == -1;
- return if blacklisted('encl_ps', 'all');
my $nexus = undef;
my $name = undef;
#-----------------------------------------
sub check_enclosure_temp {
return if $#controllers == -1;
- return if blacklisted('encl_temp', 'all');
my $nexus = undef;
my $name = undef;
$min_warn =~ s{\A \s* (-?\d+) \s* C? \s* \z}{$1}xms or $min_warn = '[N/A]';
$min_crit =~ s{\A \s* (-?\d+) \s* C? \s* \z}{$1}xms or $min_crit = '[N/A]';
+ # Convert temp units
+ if ($opt{tempunit} ne 'C') {
+ $reading = temp_from_celsius($reading, $opt{tempunit});
+ $max_warn = temp_from_celsius($max_warn, $opt{tempunit});
+ $max_crit = temp_from_celsius($max_crit, $opt{tempunit});
+ $min_warn = temp_from_celsius($min_warn, $opt{tempunit});
+ $min_crit = temp_from_celsius($min_crit, $opt{tempunit});
+ }
+
# Inactive temp probes
if ($status eq 'Unknown' and $state eq 'Inactive') {
my $msg = sprintf '%s in enclosure %s [%s] is %s',
report('storage', $msg, $E_OK, $nexus);
}
elsif ($status ne 'Ok' and $max_crit ne '[N/A]' and $reading > $max_crit) {
- my $msg = sprintf '%s in enclosure %s [%s] is critically high at %d C',
- $name, $encl_id, $encl_name, $reading;
+ my $msg = sprintf '%s in enclosure %s [%s] is critically high at %s %s',
+ $name, $encl_id, $encl_name, $reading, $opt{tempunit};
my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
report('chassis', $msg, $err, $nexus);
}
elsif ($status ne 'Ok' and $max_warn ne '[N/A]' and $reading > $max_warn) {
- my $msg = sprintf '%s in enclosure %s [%s] is too high at %d C',
- $name, $encl_id, $encl_name, $reading;
+ my $msg = sprintf '%s in enclosure %s [%s] is too high at %s %s',
+ $name, $encl_id, $encl_name, $reading, $opt{tempunit};
my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
report('chassis', $msg, $err, $nexus);
}
elsif ($status ne 'Ok' and $min_crit ne '[N/A]' and $reading < $min_crit) {
- my $msg = sprintf '%s in enclosure %s [%s] is critically low at %d C',
- $name, $encl_id, $encl_name, $reading;
+ my $msg = sprintf '%s in enclosure %s [%s] is critically low at %s %s',
+ $name, $encl_id, $encl_name, $reading, $opt{tempunit};
my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
report('chassis', $msg, $err, $nexus);
}
elsif ($status ne 'Ok' and $min_warn ne '[N/A]' and $reading < $min_warn) {
- my $msg = sprintf '%s in enclosure %s [%s] is too low at %d C',
- $name, $encl_id, $encl_name, $reading;
+ my $msg = sprintf '%s in enclosure %s [%s] is too low at %s %s',
+ $name, $encl_id, $encl_name, $reading, $opt{tempunit};
my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
report('chassis', $msg, $err, $nexus);
}
if (defined $reading && $reading =~ m{\A -?\d+ \z}xms) {
# take into account that with certain states the
# reading doesn't exist or is not an integer
- $msg .= sprintf ' at %s C', $reading;
+ $msg .= sprintf ' at %s %s', $reading, $opt{tempunit};
if ($min_warn eq '[N/A]' or $min_crit eq '[N/A]') {
$msg .= sprintf ' (max=%s/%s)', $max_warn, $max_crit;
}
if (defined $reading && $reading ne '[N/A]') {
# take into account that with certain states the
# reading doesn't exist or is not an integer
- $msg .= sprintf ' reads %d C', $reading;
+ $msg .= sprintf ' reads %s %s', $reading, $opt{tempunit};
if ($min_warn eq '[N/A]' or $min_crit eq '[N/A]') {
$msg .= sprintf ' (max=%s/%s)', $max_warn, $max_crit;
}
# Collect performance data
if (defined $opt{perfdata} && $reading ne '[N/A]') {
- $name =~ s{\A Temperature\sProbe\s(\d+) \z}{temp_$1}gxms;
- my $label = "enclosure_${encl_id}_${name}";
- my $mini = $label;
- $mini =~ s{enclosure_(.+?)_temp_(.+?)}{e$1t$2}xms;
+ my $index = $name;
+ $index =~ s{\A Temperature\sProbe\s(\d+) \z}{$1}gxms;
+ my $legacy_name = $name;
+ $legacy_name =~ s{\A Temperature\sProbe\s(\d+) \z}{temp_$1}gxms;
+ my $legacy_label = lc "enclosure_${encl_id}_${legacy_name}";
+ my $legacy_mini = $legacy_label;
+ $legacy_mini =~ s{enclosure_(.+?)_temp_(.+?)}{e$1t$2}xms;
push @perfdata, {
- label => $label,
- mini => $mini,
- value => $reading,
- warn => $max_warn,
- crit => $max_crit,
+ type => 'E',
+ id => $opt{perfdata} eq 'minimal' ? "${encl_id}_t${index}" : "${encl_id}_temp_${index}",
+ unit => $opt{tempunit},
+ label => q{},
+ legacy => $legacy_label,
+ mini => $legacy_mini,
+ value => $reading,
+ warn => $max_warn,
+ crit => $max_crit,
};
}
}
#-----------------------------------------
sub check_enclosure_emms {
return if $#controllers == -1;
- return if blacklisted('encl_emm', 'all');
my $nexus = undef;
my $name = undef;
# CHASSIS: Check memory modules
#-----------------------------------------
sub check_memory {
- return if blacklisted('dimm', 'all');
-
my $index = undef;
my $status = undef;
my $location = undef;
$msize =~ s{\A (\d+) \s MB}{$1}xms;
$count{mem} += $msize;
- next DIMM if blacklisted('dimm', $index);
-
# Ignore empty memory slots
next DIMM if !defined $index;
+
$count{dimm}++;
+ next DIMM if blacklisted('dimm', $index);
if ($status ne 'Ok') {
my $msg = undef;
# CHASSIS: Check fans
#-----------------------------------------
sub check_fans {
- return if blacklisted('fan', 'all');
-
my $index = undef;
my $status = undef;
my $reading = undef;
$max_crit =~ s{\A (\d+).* \z}{$1}xms;
}
- next FAN if blacklisted('fan', $index);
$count{fan}++;
+ next FAN if blacklisted('fan', $index);
- if ($status ne 'Ok') {
- my $msg = sprintf 'Chassis fan %d [%s] needs attention: %s',
- $index, $location, $status;
- my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
- report('chassis', $msg, $err, $index);
- }
- else {
- my $msg = sprintf 'Chassis fan %d [%s]: %s',
- $index, $location, $reading;
- report('chassis', $msg, $E_OK, $index);
- }
+ # Default
+ my $msg = sprintf 'Chassis fan %d [%s] reading: %s RPM',
+ $index, $location, $reading;
+ my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
+ report('chassis', $msg, $err, $index);
# Collect performance data
if (defined $opt{perfdata}) {
- my $pname = lc $location;
+ my $pname = $location;
$pname =~ s{\s}{_}gxms;
$pname =~ s{proc_}{cpu#}xms;
+ my $legacy_pname = $pname;
+ $pname =~ s{_rpm\z}{}ixms;
push @perfdata, {
- label => "fan_${index}_${pname}",
- mini => "f$index",
- value => $reading,
- warn => $max_warn,
- crit => $max_crit,
+ type => 'F',
+ id => $index,
+ unit => 'rpm',
+ label => $pname,
+ legacy => lc "fan_${index}_${legacy_pname}",
+ mini => "f$index",
+ value => $reading,
+ warn => $max_warn,
+ crit => $max_crit,
};
}
}
# CHASSIS: Check power supplies
#-----------------------------------------
sub check_powersupplies {
- return if blacklisted('ps', 'all');
-
my $index = undef;
my $status = undef;
my $type = undef;
$state = get_nonempty_string('Online Status', $out, 'Unknown state');
}
- next PS if blacklisted('ps', $index);
$count{power}++;
+ next PS if blacklisted('ps', $index);
if ($status ne 'Ok') {
my $msg = sprintf 'Power Supply %d [%s] needs attention: %s',
# CHASSIS: Check temperatures
#-----------------------------------------
sub check_temperatures {
- return if blacklisted('temp', 'all');
-
my $index = undef;
my $status = undef;
my $reading = undef;
$discrete = $reading;
}
- next TEMP if blacklisted('temp', $index);
$count{temp}++;
+ next TEMP if blacklisted('temp', $index);
+
+ # Convert temp units
+ if ($opt{tempunit} ne 'C') {
+ $reading = temp_from_celsius($reading, $opt{tempunit});
+ $max_warn = temp_from_celsius($max_warn, $opt{tempunit});
+ $max_crit = temp_from_celsius($max_crit, $opt{tempunit});
+ $min_warn = temp_from_celsius($min_warn, $opt{tempunit});
+ $min_crit = temp_from_celsius($min_crit, $opt{tempunit});
+ }
if ($type eq 'Discrete') {
my $msg = sprintf 'Temperature probe %d [%s] is %s',
# First check according to custom thresholds
if (exists $crit_threshold{$index}{max} and $reading > $crit_threshold{$index}{max}) {
# Custom critical MAX
- my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom max=%d)',
- $index, $location, $reading, $crit_threshold{$index}{max};
+ my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom max=%s)',
+ $index, $location, $reading, $opt{tempunit}, $crit_threshold{$index}{max};
report('chassis', $msg, $E_CRITICAL, $index);
}
elsif (exists $warn_threshold{$index}{max} and $reading > $warn_threshold{$index}{max}) {
# Custom warning MAX
- my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom max=%d)',
- $index, $location, $reading, $warn_threshold{$index}{max};
+ my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom max=%s)',
+ $index, $location, $reading, $opt{tempunit}, $warn_threshold{$index}{max};
report('chassis', $msg, $E_WARNING, $index);
}
elsif (exists $crit_threshold{$index}{min} and $reading < $crit_threshold{$index}{min}) {
# Custom critical MIN
- my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom min=%d)',
- $index, $location, $reading, $crit_threshold{$index}{min};
+ my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom min=%s)',
+ $index, $location, $reading, $opt{tempunit}, $crit_threshold{$index}{min};
report('chassis', $msg, $E_CRITICAL, $index);
}
elsif (exists $warn_threshold{$index}{min} and $reading < $warn_threshold{$index}{min}) {
# Custom warning MIN
- my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom min=%d)',
- $index, $location, $reading, $warn_threshold{$index}{min};
+ my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom min=%s)',
+ $index, $location, $reading, $opt{tempunit}, $warn_threshold{$index}{min};
report('chassis', $msg, $E_WARNING, $index);
}
elsif ($status ne 'Ok' and $max_crit ne '[N/A]' and $reading > $max_crit) {
- my $msg = sprintf 'Temperature Probe %d [%s] is critically high at %d C',
- $index, $location, $reading;
+ my $msg = sprintf 'Temperature Probe %d [%s] is critically high at %s %s',
+ $index, $location, $reading, $opt{tempunit};
my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
report('chassis', $msg, $err, $index);
}
elsif ($status ne 'Ok' and $max_warn ne '[N/A]' and $reading > $max_warn) {
- my $msg = sprintf 'Temperature Probe %d [%s] is too high at %d C',
- $index, $location, $reading;
+ my $msg = sprintf 'Temperature Probe %d [%s] is too high at %s %s',
+ $index, $location, $reading, $opt{tempunit};
my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
report('chassis', $msg, $err, $index);
}
elsif ($status ne 'Ok' and $min_crit ne '[N/A]' and $reading < $min_crit) {
- my $msg = sprintf 'Temperature Probe %d [%s] is critically low at %d C',
- $index, $location, $reading;
+ my $msg = sprintf 'Temperature Probe %d [%s] is critically low at %s %s',
+ $index, $location, $reading, $opt{tempunit};
my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
report('chassis', $msg, $err, $index);
}
elsif ($status ne 'Ok' and $min_warn ne '[N/A]' and $reading < $min_warn) {
- my $msg = sprintf 'Temperature Probe %d [%s] is too low at %d C',
- $index, $location, $reading;
+ my $msg = sprintf 'Temperature Probe %d [%s] is too low at %s %s',
+ $index, $location, $reading, $opt{tempunit};
my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
report('chassis', $msg, $err, $index);
}
# Ok
else {
- my $msg = sprintf 'Temperature Probe %d [%s] reads %d C',
- $index, $location, $reading;
+ my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s',
+ $index, $location, $reading, $opt{tempunit};
if ($min_warn eq '[N/A]' and $min_crit eq '[N/A]') {
$msg .= sprintf ' (max=%s/%s)', $max_warn, $max_crit;
}
# Collect performance data
if (defined $opt{perfdata}) {
- my $pname = lc $location;
+ my $pname = $location;
$pname =~ s{\s}{_}gxms;
- $pname =~ s{_temp\z}{}xms;
+ $pname =~ s{_temp\z}{}ixms;
$pname =~ s{proc_}{cpu#}xms;
push @perfdata, {
- label => "temp_${index}_${pname}",
- mini => "t$index",
- value => $reading,
- warn => $max_warn,
- crit => $max_crit,
+ type => 'T',
+ id => $index,
+ unit => $opt{tempunit},
+ label => $pname,
+ legacy => lc "temp_${index}_${pname}",
+ mini => "t$index",
+ value => $reading,
+ warn => $max_warn,
+ crit => $max_crit,
};
}
}
# CHASSIS: Check processors
#-----------------------------------------
sub check_processors {
- return if blacklisted('cpu', 'all');
-
my $index = undef;
my $status = undef;
my $state = undef;
$speed = get_nonempty_string('Current Speed', $out, undef);
}
- next CPU if blacklisted('cpu', $index);
-
# Ignore unoccupied CPU slots (omreport)
next CPU if (defined $out->{'Processor Manufacturer'}
and $out->{'Processor Manufacturer'} eq '[Not Occupied]')
}
$count{cpu}++;
+ next CPU if blacklisted('cpu', $index);
if (defined $brand) {
$brand =~ s{\s\s+}{ }gxms;
# CHASSIS: Check voltage probes
#-----------------------------------------
sub check_volts {
- return if blacklisted('volt', 'all');
-
my $index = undef;
my $status = undef;
my $reading = undef;
my $location = undef;
+ my $max_crit = undef;
+ my $max_warn = undef;
my @output = ();
if ($snmp) {
$status = get_snmp_probestatus($out->{voltageProbeStatus});
$reading = defined $out->{voltageProbeReading}
? sprintf('%.3f V', $out->{voltageProbeReading}/1000)
- : get_hashval($out->{voltageProbeDiscreteReading}, \%volt_discrete_reading);
+ : (get_hashval($out->{voltageProbeDiscreteReading}, \%volt_discrete_reading) || 'Unknown reading');
$location = $out->{voltageProbeLocationName} || 'Unknown location';
+ $max_crit = $out->{voltageProbeUpperCriticalThreshold} || 0;
+ $max_warn = $out->{voltageProbeUpperNonCriticalThreshold} || 0;
}
else {
$index = get_nonempty_string('Index', $out, 9999);
$status = get_nonempty_string('Status', $out, 'Unknown');
$reading = get_nonempty_string('Reading', $out, 'Unknown reading');
$location = get_nonempty_string('Probe Name', $out, 'Unknown location');
+ $max_crit = get_nonempty_string('Maximum Failure Threshold', $out, 0);
+ $max_warn = get_nonempty_string('Maximum Warning Threshold', $out, 0);
+
+ $max_crit = 0 if $max_crit eq '[N/A]';
+ $max_warn = 0 if $max_warn eq '[N/A]';
}
- next VOLT if blacklisted('volt', $index);
$count{volt}++;
+ next VOLT if blacklisted('volt', $index);
my $msg = sprintf 'Voltage sensor %d [%s] is %s',
$index, $location, $reading;
my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
report('chassis', $msg, $err, $index);
+
+ # Collect performance data
+ if (defined $opt{perfdata} and !$opt{legacy_perfdata}) {
+ $reading =~ s{\s+V\z}{}xms; # remove unit
+ $reading =~ s{\.000\z}{}xms; # if integer
+ next VOLT if $reading !~ m{\A \d+(\.\d+)? \z}xms; # discrete reading (not number)
+ my $label = join q{_}, $location;
+ $label =~ s{\s}{_}gxms;
+ push @perfdata, {
+ type => 'V',
+ id => $index,
+ unit => 'V',
+ label => $label,
+ value => $reading,
+ warn => 0,
+ crit => 0,
+ };
+ }
}
return;
}
# CHASSIS: Check batteries
#-----------------------------------------
sub check_batteries {
- return if blacklisted('bp', 'all');
-
my $index = undef;
my $status = undef;
my $reading = undef;
$location = get_nonempty_string('Probe Name', $out, 'Unknown location');
}
- next BATTERY if blacklisted('bp', $index);
$count{bat}++;
+ next BATTERY if blacklisted('bp', $index);
my $msg = sprintf 'Battery probe %d [%s] is %s',
$index, $location, $reading;
# CHASSIS: Check amperage probes (power monitoring)
#-----------------------------------------
sub check_pwrmonitoring {
- return if blacklisted('amp', 'all');
-
my $index = undef;
my $status = undef;
my $reading = undef;
$max_crit =~ s{\A (\d+.*?)\s+[a-zA-Z]+ \s*\z}{$1}xms;
}
- next AMP if blacklisted('amp', $index);
next AMP if $index !~ m{\A \d+ \z}xms;
# Special case: Probe is present but unknown. This happens via
# disabled due to non-redundant and/or non-instrumented power
# supplies.
# E.g. R410 with newer BMC firmware and 1 power supply
- if ($snmp && $status eq 'Unknown' && $reading eq '[N/A]') {
+ if ($snmp && $status eq 'Unknown' && $reading == 0) {
next AMP;
}
$count{amp}++;
+ next AMP if blacklisted('amp', $index);
# Special case: Discrete reading
if (defined $type and $type eq 'amperageProbeTypeIsDiscrete') {
my $msg = sprintf 'Amperage probe %d [%s] is %s',
$index, $location, $reading;
- report('chassis', $msg, $status2nagios{$status}, $index);
+ my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
+ report('chassis', $msg, $err, $index);
}
# Default
else {
my $msg = sprintf 'Amperage probe %d [%s] reads %s %s',
$index, $location, $reading, $unit;
- report('chassis', $msg, $status2nagios{$status}, $index);
+ my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
+ report('chassis', $msg, $err, $index);
}
# Collect performance data
if (defined $opt{perfdata}) {
next AMP if $reading !~ m{\A \d+(\.\d+)? \z}xms; # discrete reading (not number)
- my $label = join q{_}, 'pwr_mon', $index, lc $location;
+ my $label = join q{_}, $location;
$label =~ s{\s}{_}gxms;
push @perfdata, {
- label => $label,
- mini => "p${index}" . lc $unit,
- value => $reading,
- warn => $max_warn,
- crit => $max_crit,
+ type => $unit,
+ id => $index,
+ unit => $unit,
+ label => $label,
+ legacy => (join q{_}, 'pwr_mon', $index, lc $label),
+ mini => "p${index}" . lc $unit,
+ value => $reading,
+ warn => $max_warn,
+ crit => $max_crit,
};
}
}
# find used indexes
foreach (@perfdata) {
- if ($_->{label} =~ m/\A pwr_mon_(\d+)/xms) {
+ if ($_->{label} =~ m/\A [WA](\d+)/xms) {
$used{$1} = 1;
}
}
AMP2:
foreach my $line (@{ run_command("$omreport $omopt_chassis pwrmonitoring -fmt ssv") }) {
chop $line;
- if ($line eq 'Location;Reading') {
+ if ($line eq 'Location;Reading' or $line eq 'Amperage') {
$found = 1;
next AMP2;
}
$found = 0;
next AMP2;
}
- if ($found and $line =~ m/\A ([^;]+?) ; (\d*\.\d+) \s [AW] \z/xms) {
- my $aname = lc $1;
- my $aval = $2;
+ if ($found and $line =~ m/\A ([^;]+?) ; (\d*\.\d+) \s ([AW]) \z/xms) {
+ my $aname = $1;
+ my $aval = $2;
+ my $aunit = $3;
$aname =~ s{\s}{_}gxms;
# don't use an existing index
while (exists $used{$index}) { ++$index; }
push @perfdata, {
- label => "pwr_mon_${index}_${aname}",
- mini => "p${index}a",
- value => $aval,
- warn => 0,
- crit => 0,
+ type => $aunit,
+ id => $index,
+ unit => $aunit,
+ label => $aname,
+ legacy => "pwr_mon_${index}_${aname}",
+ mini => "p${index}a",
+ value => $aval,
+ warn => 0,
+ crit => 0,
};
++$index;
}
# CHASSIS: Check intrusion
#-----------------------------------------
sub check_intrusion {
- return if blacklisted('intr', 'all');
-
my $index = undef;
my $status = undef;
my $reading = undef;
$reading = get_nonempty_string('State', $out, 'Unknown reading');
}
- next INTRUSION if blacklisted('intr', $index);
$count{intr}++;
+ next INTRUSION if blacklisted('intr', $index);
if ($status ne 'Ok') {
my $msg = sprintf 'Chassis intrusion %d detected: %s',
# CHASSIS: Check SD Card Device
#-----------------------------------------
sub check_sdcard {
- return if blacklisted('sdcard', 'all');
-
my $index = undef;
my $status = undef;
my $state = undef;
$capacity =~ s{\[Not Available\]}{Unknown Size};
}
- next SDCARD if blacklisted('sd', $index);
$count{sd}++ if $state ne 'Absent';
+ next SDCARD if blacklisted('sd', $index);
if ($status ne 'Ok') {
my $msg = sprintf 'SD Card %d needs attention: %s',
# Prefix with service tag if specified with option '-i|--info'
if ($opt{info}) {
if (defined $opt{htmlinfo}) {
- $msg = '[<a href="' . warranty_url($sysinfo{serial})
+ $msg = '[<a target="_blank" href="' . warranty_url($sysinfo{serial})
. "\">$sysinfo{serial}</a>] " . $msg;
}
else {
);
print $okmsg{$opt{only}};
+
+ # show blacklisted components
+ if ($opt{show_blacklist} and %blacklist) {
+ my @blstr = ();
+ foreach (keys %blacklist) {
+ push @blstr, "$_=" . join ',', @{ $blacklist{$_} };
+ }
+ print $linebreak;
+ print "----- BLACKLISTED: " . join '/', @blstr;
+ }
}
elsif ($exit_code == $E_OK && !$opt{debug}) {
if (defined $opt{htmlinfo}) {
- printf q{OK - System: '<a href="%s">%s%s</a>', SN: '<a href="%s">%s</a>'},
+ printf q{OK - System: '<a target="_blank" href="%s">%s%s</a>', SN: '<a target="_blank" href="%s">%s</a>'},
documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
warranty_url($sysinfo{serial}), $sysinfo{serial};
}
print ', not checking storage';
}
+ # show blacklisted components
+ if ($opt{show_blacklist} and %blacklist) {
+ my @blstr = ();
+ foreach (keys %blacklist) {
+ push @blstr, "$_=" . join ',', @{ $blacklist{$_} };
+ }
+ print $linebreak;
+ print "----- BLACKLISTED: " . join '/', @blstr;
+ }
+
if ($opt{okinfo} >= 1) {
print $linebreak;
printf q{----- BIOS='%s %s'}, $sysinfo{bios}, $sysinfo{biosdate};
if ($opt{extinfo}) {
print $linebreak;
if (defined $opt{htmlinfo}) {
- printf '------ SYSTEM: <a href="%s">%s%s</a>, SN: <a href="%s">%s</a>',
+ printf '------ SYSTEM: <a target="_blank" href="%s">%s%s</a>, SN: <a target="_blank" href="%s">%s</a>',
documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
warranty_url($sysinfo{serial}), $sysinfo{serial};
}
# Sort routine for performance data
sub perfsort {
+ my %order = ( 'T' => 0, 'W' => 1, 'A' => 2, 'V' => 3, 'F' => 4, 'E' => 5, );
+
+ # sort in this order:
+ # 1. the type according to the hash "order" above
+ # 2. the id (index) numerically
+ # 3. the id (index) alphabetically
+ # 4. the label
+ return $order{$a->{type}} cmp $order{$b->{type}} ||
+ ($a->{id} =~ m{\A\d+\z}xms and $a->{id} <=> $b->{id}) ||
+ ($a->{id} !~ m{\A\d+\z}xms and $a->{id} cmp $b->{id}) ||
+ $a->{label} cmp $b->{label};
+ }
+
+ # LEGACY sort routine for performance data
+ sub perfsort_legacy {
my %order = ( fan => 0, pwr => 1, tem => 2, enc => 3, );
- return ($order{(substr $a->{label}, 0, 3)} cmp $order{(substr $b->{label}, 0, 3)}) ||
- $a->{label} cmp $b->{label};
+ return ($order{(substr $a->{legacy}, 0, 3)} cmp $order{(substr $b->{legacy}, 0, 3)}) ||
+ $a->{legacy} cmp $b->{legacy};
}
# Print performance data sorted
- my $type = $opt{perfdata} eq 'minimal' ? 'mini' : 'label';
- print join $lb, map { "$_->{$type}=$_->{value};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+ if ($opt{legacy_perfdata}) {
+ my $type = $opt{perfdata} eq 'minimal' ? 'mini' : 'legacy';
+ print join $lb, map { "$_->{$type}=$_->{value};$_->{warn};$_->{crit}" } sort perfsort_legacy @perfdata;
+ }
+ else {
+ if ($opt{perfdata} eq 'minimal') {
+ print join $lb, map { "$_->{type}$_->{id}=$_->{value}$_->{unit};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+ }
+ else {
+ print join $lb, map { "$_->{type}$_->{id}_$_->{label}=$_->{value}$_->{unit};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+ }
+ }
}
-# Print a linebreak at the end
-print "\n" if !$opt{debug};
+# Wrapping up and finishing
+if ($opt{debug}) {
+ # Exit with value 3 (unknown) if debug
+ exit $E_UNKNOWN;
+}
+else {
+ # Print a linebreak at the end if we have a TTY
+ isatty(*STDOUT) && print "\n";
-# Exit with proper exit code
-exit $exit_code;
+ # Exit with proper exit code
+ exit $exit_code;
+}