You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1160 lines
40 KiB
1160 lines
40 KiB
#!/usr/bin/perl
|
|
# check_ipmi_sensor: Nagios/Icinga plugin to check IPMI sensors
|
|
#
|
|
# Copyright (C) 2009-2019 Thomas-Krenn.AG,
|
|
# additional contributors see changelog.txt
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify it under
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
# Foundation; either version 3 of the License, or (at your option) any later
|
|
# version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with
|
|
# this program; if not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
################################################################################
|
|
# The following guides provide helpful information if you want to extend this
|
|
# script:
|
|
# http://tldp.org/LDP/abs/html/ (Advanced Bash-Scripting Guide)
|
|
# http://www.gnu.org/software/gawk/manual/ (Gawk: Effective AWK Programming)
|
|
# http://de.wikibooks.org/wiki/Awk (awk Wikibook, in German)
|
|
# http://nagios.sourceforge.net/docs/3_0/customobjectvars.html (hints on
|
|
# custom object variables)
|
|
# http://nagiosplug.sourceforge.net/developer-guidelines.html (plug-in
|
|
# development guidelines)
|
|
# http://nagios.sourceforge.net/docs/3_0/pluginapi.html (plugin API)
|
|
################################################################################
|
|
use strict;
|
|
use warnings;
|
|
use Getopt::Long qw(:config no_ignore_case);
|
|
use IPC::Run qw( run ); #interact with processes
|
|
################################################################################
|
|
# set text variables
|
|
our $check_ipmi_sensor_version = "3.14";
|
|
|
|
sub get_version{
|
|
return <<EOT;
|
|
check_ipmi_sensor version $check_ipmi_sensor_version
|
|
Copyright (C) 2009-2019 Thomas-Krenn.AG
|
|
Current updates at https://github.com/thomas-krenn/check_ipmi_sensor_v3.git
|
|
EOT
|
|
}
|
|
|
|
sub get_usage{
|
|
return <<EOT;
|
|
Usage:
|
|
check_ipmi_sensor -H <hostname>
|
|
[-f <FreeIPMI config file> | -U <username> -P <password> -L <privilege level>]
|
|
[-O <FreeIPMI options>] [-b] [-T <sensor type(s)>] [-ST <SEL sensor type(s)>]
|
|
[-x <sensor id>] [-xT <sensor type(s)>] [-xST <SEL sensor type(s)]
|
|
[-i <sensor id>] [-o zenoss] [-D <protocol LAN version>] [-h] [-V]
|
|
[-fc <num_fans>] [--fru] [--assettag] [--board] [--nosel] [--selonly]
|
|
[--seltail <count>] [-sx|--selexclude <sel exclude file>]
|
|
[-xx|--sexclude <exclude file>] [-us|--unify-sensors <unify file>] [--nosudo]
|
|
[--nothresholds] [--nodcmi] [--noentityabsent]
|
|
[-s <ipmi-sensor output file>] [-h] [-V]
|
|
[-v|-vv|-vvv]
|
|
EOT
|
|
}
|
|
|
|
sub get_help{
|
|
return <<EOT;
|
|
[-H <hostname>]
|
|
hostname or IP of the IPMI interface.
|
|
For \"-H localhost\" or if no host is specified (local computer) the
|
|
Nagios/Icinga user must be allowed to run
|
|
ipmimonitoring/ipmi-sensors/ipmi-sel/[ipmi-fru] with root privileges
|
|
or via sudo (ipmimonitoring/ipmi-sensors/ipmi-sel/[ipmi-fru] must be
|
|
able to access the IPMI devices via the IPMI system interface).
|
|
[-f <FreeIPMI config file>]
|
|
path to the FreeIPMI configuration file.
|
|
Only neccessary for communication via network.
|
|
Not neccessary for access via IPMI system interface (\"-H localhost\").
|
|
It should contain IPMI username, IPMI password, and IPMI privilege-level,
|
|
for example:
|
|
username monitoring
|
|
password yourpassword
|
|
privilege-level user
|
|
As alternative you can use -U/-P/-L instead (see below).
|
|
[-U <username> -P <password> -L <privilege level>]
|
|
IPMI username, IPMI password and IPMI privilege level, provided as
|
|
parameters and not by a FreeIPMI configuration file. Useful for RHEL/
|
|
Centos 5.* with FreeIPMI 0.5.1 (this elder FreeIPMI version does not
|
|
support config files).
|
|
Warning: with this method the password is visible in the process list.
|
|
So whenever possible use a FreeIPMI confiugration file instead.
|
|
[-O <FreeIPMI options>]
|
|
additional options for FreeIPMI. Useful for RHEL/CentOS 5.* with
|
|
FreeIPMI 0.5.1 (this elder FreeIPMI version does not support config
|
|
files).
|
|
[--seloptions <FreeIPMI SEL options>]
|
|
additional options for FreeIPMI SEL command. Useful for passing extra
|
|
options to the ipmi-sel call, e.g. --assume-system-event-records:
|
|
--seloptions '--assume-system-event-records'
|
|
[-b]
|
|
backward compatibility mode for FreeIPMI 0.5.* (this omits the FreeIPMI
|
|
caching options --quiet-cache and --sdr-cache-recreate)
|
|
[-T <sensor type(s)>]
|
|
limit sensors to query based on IPMI sensor type.
|
|
Examples for IPMI sensor types are 'Fan', 'Temperature', 'Voltage', ...
|
|
See the output of the FreeIPMI command 'ipmi-sensors -L' and chapter
|
|
'42.2 Sensor Type Codes and Data' of the IPMI 2.0 spec for a full list
|
|
of possible sensor types. You can also find the full list of possible
|
|
sensor types at https://www.thomas-krenn.com/en/wiki/IPMI_Sensor_Types
|
|
The available types depend on your particular server and the available
|
|
sensors there.
|
|
Multiple sensor types can be specified as a comma-separated list.
|
|
[-ST <SEL sensor type(s)>]
|
|
limit SEL entries to specific types, run 'ipmi-sel -L' for a list of
|
|
types. All sensors are populated to the SEL and per default all sensor
|
|
types are monitored. E.g. to limit the sensor SEL types to Memory and
|
|
Processsor use -ST 'Memory,Processor'.
|
|
[-x <sensor id>]
|
|
exclude sensor matching <sensor id>. Useful for cases when unused
|
|
sensors cannot be deleted from SDR and are reported in a non-OK state.
|
|
Option can be specified multiple times. The <sensor id> is a numeric
|
|
value (sensor names are not used as some servers have multiple sensors
|
|
with the same name). Use -vvv option to query the <sensor ids>.
|
|
[-xT <sensor type(s)>]
|
|
exclude sensors based on IPMI sensor type.
|
|
Multiple sensor types can be specified as a comma-separated list.
|
|
[-xST <SEL sensor type(s)]
|
|
exclude SEL entries of specific sensor types.
|
|
Multiple sensor types can be specified as a comma-separated list.
|
|
[-i <sensor id>]
|
|
include only sensor matching <sensor id>. Useful for cases when only
|
|
specific sensors should be monitored. Be aware that only for the
|
|
specified sensor errors/warnings are generated. Use -vvv option to query
|
|
the <sensor ids>.
|
|
[-v|-vv|-vvv]
|
|
be verbose
|
|
(no -v) .. single line output
|
|
-v ..... single line output with additional details for warnings
|
|
-vv ..... multi line output, also with additional details for warnings
|
|
-vvv ..... debugging output, followed by normal multi line output
|
|
[-o]
|
|
change output format. Useful for using the plugin with other monitoring
|
|
software than Nagios or Icinga.
|
|
-o zenoss .. create ZENOSS compatible formatted output (output with
|
|
underscores instead of whitespaces and no single quotes)
|
|
[-D]
|
|
change the protocol LAN version. Normally LAN_2_0 is used as protocol
|
|
version if not overwritten with this option. Use 'default' here if you
|
|
don't want to use LAN_2_0.
|
|
[-fc <num fans>]
|
|
number of installed fans. If the number of current installed
|
|
fans reported by IPMI is not equal than <num fans> then a Warning state
|
|
is returned. Please use this option carefully as number of fans and
|
|
number of fan sensors can differ!
|
|
[--fru]
|
|
print the product serial number if it is available in the IPMI FRU data.
|
|
For this purpose the tool 'ipmi-fru' is used. E.g.:
|
|
IPMI Status: OK (9000096781)
|
|
[--assettag]
|
|
--fru is mandatory
|
|
print the assettag if it is available in the IPMI FRU data.
|
|
IPMI Status: OK (9000096781)
|
|
Asset Tag: 20200220
|
|
[--board]
|
|
--fru is mandatory
|
|
print additional motherboard informations if it is available in the IPMI FRU data.
|
|
IPMI Status: OK (9000096781)
|
|
Board Manufacturer: Supermicro
|
|
Board Product Name: X10DRW-iT
|
|
Board Serial Number: AB123456
|
|
[--nosel]
|
|
turn off system event log checking via ipmi-sel. If there are
|
|
unintentional entries in SEL, use 'ipmi-sel --clear' or the -sx or -xST
|
|
option.
|
|
[--selonly]
|
|
check only system event log checking via ipmi-sel. If there are
|
|
unintentional entries in SEL, use 'ipmi-sel --clear' or the -sx or -xST
|
|
option.
|
|
[--seltail <count>]
|
|
limit SEL output to specified count of last messages
|
|
[-sx|--selexclude <sel exclude file>]
|
|
use a sel exclude file to exclude entries from the system event log.
|
|
Specify name and type pipe delimitered in this file to exclude an entry,
|
|
for example: System Chassis Chassis Intru|Physical Security
|
|
To get valid names and types use the -vvv option and take a look at:
|
|
debug output for sel (-vvv is set). Don't use name and type from the
|
|
web interface as sensor descriptions are not complete there.
|
|
As with the '-xx' option if the first character of a line is '~' the
|
|
name is treated as a regular expression.
|
|
[-xx|--sexclude <exclude file>]
|
|
use an exclude file to exclude sensors, each line specifies an exclude.
|
|
Specify name and type pipe delimitered in this file to exclude a sensor,
|
|
for example: System Chassis Chassis Intru|Physical Security
|
|
If the first character of a line is '~' the name is treated as a regular
|
|
expression. E.g. to exclude all sensor names from CPU0 to CPU9:
|
|
~CPU[0-9] Temp|Temperature
|
|
To get valid names and types use the -vvv option.
|
|
[-us|--unify-sensors <unify file>]
|
|
use an unify file to unify sensor names. This is an easy way to rename
|
|
sensors with given patterns in the file. Once might use this option
|
|
to get the same sensor names accross different platforms, e.g. to only
|
|
have 'Mainboard Temperature' as sensor name and not 'MB1 Temperature' or 'System Temp'.
|
|
Rules in the file follow simple regex patterns e.g.:
|
|
^(MB1 Temperature|System Temp)\$/Mainboard Temperature
|
|
Temp\$/TEMP
|
|
[--nosudo]
|
|
turn off sudo usage on localhost or if ipmi host is ommited.
|
|
[--nothresholds]
|
|
turn off performance data thresholds from output-sensor-thresholds.
|
|
[--noentityabsent]
|
|
skip sensor checks for sensors that have 'noentityabsent' as event state
|
|
[--nodcmi]
|
|
turn off power statistics via ipmi-dcmi.
|
|
[-s <ipmi-sensor output file>]
|
|
simulation mode - test the plugin with an ipmi-sensor output redirected
|
|
to a file.
|
|
[-h]
|
|
show this help
|
|
[-V]
|
|
show version information
|
|
|
|
Examples:
|
|
\$ check_ipmi_sensor -H 192.0.2.1 -U monitor -P monitor -L user
|
|
IPMI Status: OK | 'System Temp'=30.00 'Peripheral Temp'=32.00
|
|
'FAN 1'=2775.00 [...]
|
|
\$ check_ipmi_sensor -H 192.0.2.1 -U monitor -P monitor -L user -x 205
|
|
IPMI Status: OK | 'System Temp'=30.00 'Peripheral Temp'=32.00
|
|
'FAN 2'=2775.00 [...]
|
|
\$ check_ipmi_sensor -H 192.0.2.1 -U monitor -P monitor -L user -i 4,71
|
|
IPMI Status: OK | 'System Temp'=30.00 'Peripheral Temp'=32.00
|
|
\$ check_ipmi_sensor -H 192.0.2.1 -U monitor -P monitor -L user -i 4 --fru
|
|
IPMI Status: OK (0000012345) | 'System Temp'=30.00
|
|
|
|
Further information about this plugin can be found at
|
|
http://www.thomas-krenn.com/en/wiki/IPMI_Sensor_Monitoring_Plugin
|
|
|
|
Use the github repo at https://github.com/thomas-krenn/check_ipmi_sensor_v3.git
|
|
to submit patches, suggest improvements or if you have questions regarding
|
|
use of this plugin.
|
|
|
|
Attention: the mailing list is no longer in use but an archive can be found at
|
|
http://lists.thomas-krenn.com/
|
|
EOT
|
|
}
|
|
|
|
sub usage{
|
|
my ($arg) = @_; #the list of inputs
|
|
my ($exitcode);
|
|
if ( defined $arg ){
|
|
if ( $arg =~ m/^\d+$/ ){
|
|
$exitcode = $arg;
|
|
}
|
|
else{
|
|
print STDOUT $arg, "\n";
|
|
$exitcode = 1;
|
|
}
|
|
}
|
|
print STDOUT get_usage();
|
|
exit($exitcode) if defined $exitcode;
|
|
}
|
|
################################################################################
|
|
# set ipmimonitoring path
|
|
our $MISSING_COMMAND_TEXT = '';
|
|
our $IPMICOMMAND ="";
|
|
if(-x "/usr/sbin/ipmimonitoring"){
|
|
$IPMICOMMAND = "/usr/sbin/ipmimonitoring";
|
|
}
|
|
elsif (-x "/usr/bin/ipmimonitoring"){
|
|
$IPMICOMMAND = "/usr/bin/ipmimonitoring";
|
|
}
|
|
elsif (-x "/usr/local/sbin/ipmimonitoring"){
|
|
$IPMICOMMAND = "/usr/local/sbin/ipmimonitoring";
|
|
}
|
|
elsif (-x "/usr/local/bin/ipmimonitoring"){
|
|
$IPMICOMMAND = "/usr/local/bin/ipmimonitoring";
|
|
}
|
|
else{
|
|
$MISSING_COMMAND_TEXT = " ipmimonitoring/ipmi-sensors command not found!\n";
|
|
}
|
|
|
|
# Identify the version of the ipmi-tool
|
|
sub get_ipmi_version{
|
|
my @ipmi_version_output = '';
|
|
my $ipmi_version = '';
|
|
@ipmi_version_output = `$IPMICOMMAND -V`;
|
|
$ipmi_version = shift(@ipmi_version_output);
|
|
$ipmi_version =~ /(\d+)\.(\d+)\.(\d+)/;
|
|
@ipmi_version_output = ();
|
|
push @ipmi_version_output,$1,$2,$3;
|
|
return @ipmi_version_output;
|
|
}
|
|
|
|
sub simulate{
|
|
my $output = '';
|
|
my $simul_file = $_[0];
|
|
if( !defined $simul_file || (-x '\"'.$simul_file.'\"')){
|
|
print "DEBUG: Using simulation file: $simul_file\n";
|
|
print "Error: Simulation file with ipmi output not found.\n";
|
|
exit(3);
|
|
}
|
|
return ($output = `cat $simul_file`);
|
|
}
|
|
|
|
sub get_fru{
|
|
my @frucmd = @{(shift)};
|
|
my $verbosity = shift;
|
|
my $fru;
|
|
if(-e '/usr/sbin/ipmi-fru'){
|
|
$fru = '/usr/sbin/ipmi-fru';
|
|
}
|
|
else{
|
|
chomp($fru = `which ipmi-fru`);
|
|
}
|
|
#if sudo is used the command is the second element
|
|
if($frucmd[0] eq 'sudo'){
|
|
$frucmd[1] = $fru;
|
|
}
|
|
else{
|
|
$frucmd[0] = $fru;
|
|
}
|
|
#skip checksum validation
|
|
push @frucmd,'-s';
|
|
my $fruoutput;
|
|
my $returncode;
|
|
run \@frucmd, '>&', \$fruoutput;
|
|
#the upper eight bits contain the error condition (exit code)
|
|
#see http://perldoc.perl.org/perlvar.html#Error-Variables
|
|
$returncode = $? >> 8;
|
|
if ( $returncode != 0 ){
|
|
print "$fruoutput\n";
|
|
print "-> Execution of $fru failed with return code $returncode.\n";
|
|
print "-> $fru was executed with the following parameters:\n";
|
|
print " ", join(' ', @frucmd), "\n";
|
|
exit(3);
|
|
}
|
|
if($verbosity == 3){
|
|
print "------------- debug output for fru (-vvv is set): ------------\n";
|
|
print " $fru was executed with the following parameters:\n";
|
|
print " ", join(' ', @frucmd), "\n";
|
|
print " output of FreeIPMI:\n";
|
|
print "$fruoutput";
|
|
}
|
|
return split('\n', $fruoutput);
|
|
}
|
|
|
|
sub get_sel{
|
|
my @selcmd = @{(shift)};
|
|
my $verbosity = shift;
|
|
my @sel_sensor_types = @{(shift)};
|
|
my @exclude_sel_sensor_types = @{(shift)};
|
|
my @sel_options = @{(shift)};
|
|
my $sel;
|
|
if(-e '/usr/sbin/ipmi-sel'){
|
|
$sel = '/usr/sbin/ipmi-sel';
|
|
}
|
|
else{
|
|
chomp($sel = `which ipmi-sel`);
|
|
}
|
|
#if sudo is used the command is the second element
|
|
if($selcmd[0] eq 'sudo'){
|
|
$selcmd[1] = $sel;
|
|
}
|
|
else{
|
|
$selcmd[0] = $sel;
|
|
}
|
|
push @selcmd, '--output-event-state', '--interpret-oem-data', '--entity-sensor-names';
|
|
push @selcmd, '--sensor-types=' . join(',', @sel_sensor_types);
|
|
if(@exclude_sel_sensor_types){
|
|
push @selcmd, '--exclude-sensor-types=' . join(',', @exclude_sel_sensor_types);
|
|
}
|
|
if(@sel_options){
|
|
push @selcmd, @sel_options;
|
|
}
|
|
my $seloutput;
|
|
my $returncode;
|
|
run \@selcmd, '>&', \$seloutput;
|
|
$returncode = $? >> 8;
|
|
if ( $returncode != 0 ){
|
|
print "$seloutput\n";
|
|
print "-> Execution of $sel failed with return code $returncode.\n";
|
|
print "-> $sel was executed with the following parameters:\n";
|
|
print " ", join(' ', @selcmd), "\n";
|
|
exit(3);
|
|
}
|
|
if($verbosity == 3){
|
|
print "------------- debug output for sel (-vvv is set): ------------\n";
|
|
print " $sel was executed with the following parameters:\n";
|
|
print " ", join(' ', @selcmd), "\n";
|
|
print " output of FreeIPMI:\n";
|
|
print "$seloutput";
|
|
}
|
|
return split('\n', $seloutput);
|
|
}
|
|
|
|
sub parse_sel{
|
|
my $selcmd = shift;
|
|
my $verbosity = shift;
|
|
my $sel_xfile = shift;
|
|
my $sel_sensor_types = shift;
|
|
my $exclude_sel_sensor_types = shift;
|
|
my $sel_options = shift;
|
|
my @seloutput = get_sel($selcmd, $verbosity, $sel_sensor_types, $exclude_sel_sensor_types, $sel_options);
|
|
# Remove unknown SEL records as they break output, in verbose mode these unknown records are kept as debug output
|
|
@seloutput = grep(!/Unknown SEL Record Type:/, @seloutput);
|
|
@seloutput = map { [ map { s/^\s*//; s/\s*$//; $_; } split(m/\|/, $_) ] } @seloutput;
|
|
my $header = shift(@seloutput);
|
|
|
|
my @sel_rows;
|
|
foreach my $row (@seloutput){
|
|
my %curr_row;
|
|
for(my $i = 0; $i < scalar(@{$header}); $i++){
|
|
my $key = lc $header->[$i];
|
|
$curr_row{$key} = $row->[$i];
|
|
}
|
|
if(!(exclude_with_file($sel_xfile, $curr_row{'name'}, $curr_row{'type'}))){
|
|
push @sel_rows, \%curr_row;
|
|
}
|
|
}
|
|
return \@sel_rows;
|
|
}
|
|
|
|
sub get_dcmi{
|
|
my @dcmicmd = @{(shift)};
|
|
my $verbosity = shift;
|
|
my $dcmi;
|
|
if(-e '/usr/sbin/ipmi-dcmi'){
|
|
$dcmi = '/usr/sbin/ipmi-dcmi';
|
|
}
|
|
else{
|
|
chomp($dcmi = `which ipmi-dcmi`);
|
|
}
|
|
#if sudo is used the command is the second element
|
|
if($dcmicmd[0] eq 'sudo'){
|
|
$dcmicmd[1] = $dcmi;
|
|
}
|
|
else{
|
|
$dcmicmd[0] = $dcmi;
|
|
}
|
|
push @dcmicmd, '--get-system-power-statistics';
|
|
|
|
my $dcmioutput;
|
|
my $returncode;
|
|
run \@dcmicmd, '>&', \$dcmioutput;
|
|
$returncode = $? >> 8;
|
|
if ( $returncode == 0 ){
|
|
return split('\n', $dcmioutput);
|
|
}
|
|
}
|
|
|
|
sub parse_dcmi{
|
|
my $dcmicmd = shift;
|
|
my $verbosity = shift;
|
|
my @dcmioutput = get_dcmi($dcmicmd, $verbosity);
|
|
if(@dcmioutput){
|
|
@dcmioutput = map { [ map { s/^\s*//; s/\s*$//; $_; } split(m/\:/, $_) ] } @dcmioutput;
|
|
my %current_power;
|
|
my $power_available = 0;
|
|
foreach my $power (@dcmioutput){
|
|
if(defined($power) && defined($power->[0]) && $power->[0] ne ''){
|
|
if($power->[0] eq 'Current Power'){
|
|
$power->[1] =~ m/^(\d+)/;
|
|
my $watts = $1;
|
|
$current_power{'Current Power'} = $watts;
|
|
}
|
|
if($power->[0] eq 'Power Measurement'){
|
|
if($power->[1] eq 'Active'){
|
|
$power_available = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if($power_available == 1){
|
|
return \%current_power;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Excludes a name and type pair if it is present in the given file, pipe
|
|
# delimitered.
|
|
# @return 1 if name should be skipped, 0 if not
|
|
sub exclude_with_file{
|
|
my $file_name = shift;
|
|
my $name = shift;
|
|
my $type = shift;
|
|
my @xlist;
|
|
my $skip = 0;
|
|
if($file_name){
|
|
if(!(open (FH, "< $file_name"))){
|
|
print "-> Reading exclude file $file_name failed with: $!.\n";
|
|
exit(3);
|
|
};
|
|
@xlist = <FH>;
|
|
}
|
|
foreach my $exclude (@xlist){
|
|
my @curr_exclude = map { s/^\s*//; s/\s*$//; $_; } split(/\|/,$exclude);
|
|
if(@curr_exclude && $curr_exclude[0] ne '' && $curr_exclude[1] ne ''){
|
|
#if the first char of the name in the exclude file is a '~' treat it as regex
|
|
if(substr($curr_exclude[0], 0, 1 ) eq '~'){
|
|
my $regex_curr_exclude = substr $curr_exclude[0], 1;
|
|
if($name =~ m/$regex_curr_exclude/ && $curr_exclude[1] eq $type){
|
|
$skip = 1;
|
|
}
|
|
}
|
|
elsif($curr_exclude[0] eq $name && $curr_exclude[1] eq $type){
|
|
$skip = 1;
|
|
}
|
|
}
|
|
}
|
|
close FH;
|
|
return $skip;
|
|
}
|
|
|
|
# Reads regular expressions from a file and applies the rules to sensor names.
|
|
# This unifies sensor names across different platforms.
|
|
# @return The sensor name with specified unify rules applied
|
|
sub unify_with_file{
|
|
my $file_name = shift;
|
|
my $name = shift;# given sensor name
|
|
my @ulist;# list of rules to apply
|
|
if($file_name){
|
|
if(!(open (FH, "< $file_name"))){
|
|
print "-> Reading unify file $file_name failed with: $!.\n";
|
|
exit(3);
|
|
};
|
|
@ulist = <FH>;
|
|
}
|
|
foreach my $unify_rule (@ulist){
|
|
#split at the only / that is not masked with a \,
|
|
#this is the separator in s/x/y/g to get x and y
|
|
my @curr_rule = map { s/^\s*//; s/\s*$//; $_; } split(/(?<!\\)\//,$unify_rule);
|
|
if(@curr_rule && $curr_rule[0] ne '' && $curr_rule[1] ne ''){
|
|
$name =~ s/$curr_rule[0]/$curr_rule[1]/g;
|
|
}
|
|
}
|
|
close FH;
|
|
return $name;
|
|
}
|
|
|
|
#define entire hashes
|
|
our %hdrmap = (
|
|
'Record_ID' => 'id', # FreeIPMI ...,0.7.x
|
|
'Record ID' => 'id', # FreeIPMI 0.8.x,... with --legacy-output
|
|
'ID' => 'id', # FreeIPMI 0.8.x
|
|
'Sensor Name' => 'name',
|
|
'Name' => 'name', # FreeIPMI 0.8.x
|
|
'Sensor Group' => 'type',
|
|
'Type' => 'type', # FreeIPMI 0.8.x
|
|
'Monitoring Status' => 'state',
|
|
'State' => 'state', # FreeIPMI 0.8.x
|
|
'Sensor Units' => 'units',
|
|
'Units' => 'units', # FreeIPMI 0.8.x
|
|
'Sensor Reading' => 'reading',
|
|
'Reading' => 'reading', # FreeIPMI 0.8.x
|
|
'Event' => 'event', # FreeIPMI 0.8.x
|
|
'Lower C' => 'lowerC',
|
|
'Lower NC' => 'lowerNC',
|
|
'Upper C' => 'upperC',
|
|
'Upper NC' => 'upperNC',
|
|
'Lower NR' => 'lowerNR',
|
|
'Upper NR' => 'upperNR',
|
|
);
|
|
|
|
our $verbosity = 0;
|
|
|
|
MAIN: {
|
|
$| = 1; #force a flush after every write or print
|
|
my @ARGV_SAVE = @ARGV;#keep args for verbose output
|
|
my ($show_help, $show_version);
|
|
my ($ipmi_host, $ipmi_user, $ipmi_password, $ipmi_privilege_level, $ipmi_config_file, $ipmi_outformat);
|
|
my (@freeipmi_options, $freeipmi_compat, @sel_options);
|
|
my (@ipmi_sensor_types, @ipmi_exclude_sensor_types, @ipmi_xlist, @ipmi_ilist);
|
|
my (@ipmi_version);
|
|
my $ipmi_sensors = 0;#states to use ipmi-sensors instead of ipmimonitoring
|
|
my $fan_count;#number of fans that should be installed in unit
|
|
my $lanVersion;#if desired use a different protocol version
|
|
my $abort_text = '';
|
|
my $zenoss = 0;
|
|
my @sel_sensor_types;
|
|
my @exclude_sel_sensor_types;
|
|
my $sel_issues_present = 0;
|
|
my $simulate = '';
|
|
my ($use_fru, $use_asset, $use_board, $no_sel, $sel_only, $sel_tail, $no_sudo, $use_thresholds, $no_thresholds, $sel_xfile, $s_xfile, $s_ufile, $no_entity_absent, $no_dcmi);
|
|
|
|
#read in command line arguments and init hash variables with the given values from argv
|
|
if ( !( GetOptions(
|
|
'H|host=s' => \$ipmi_host,
|
|
'f|config-file=s' => \$ipmi_config_file,
|
|
'U|user=s' => \$ipmi_user,
|
|
'P|password=s' => \$ipmi_password,
|
|
'L|privilege-level=s' => \$ipmi_privilege_level,
|
|
'O|options=s' => \@freeipmi_options,
|
|
'seloptions=s' => \@sel_options,
|
|
'b|compat' => \$freeipmi_compat,
|
|
'T|sensor-types=s' => \@ipmi_sensor_types,
|
|
'xT|exclude-sensor-types=s' => \@ipmi_exclude_sensor_types,
|
|
'ST|sel-sensor-types=s' => \@sel_sensor_types,
|
|
'xST|exclude-sel-sensor-types=s' => \@exclude_sel_sensor_types,
|
|
'fru' => \$use_fru,
|
|
'assettag' => \$use_asset,
|
|
'board' => \$use_board,
|
|
'nosel' => \$no_sel,
|
|
'selonly' => \$sel_only,
|
|
'seltail=s' => \$sel_tail,
|
|
'nosudo' => \$no_sudo,
|
|
'nothresholds' => \$no_thresholds,
|
|
'nodcmi' => \$no_dcmi,
|
|
'noentityabsent' => \$no_entity_absent,
|
|
'v|verbosity' => \$verbosity,
|
|
'vv' => sub{$verbosity=2},
|
|
'vvv' => sub{$verbosity=3},
|
|
'x|exclude=s' => \@ipmi_xlist,
|
|
'sx|selexclude=s' => \$sel_xfile,
|
|
'xx|sexclude=s' => \$s_xfile,
|
|
'us|unify-sensors=s'=> \$s_ufile,
|
|
'i|include=s' => \@ipmi_ilist,
|
|
'o|outformat=s' => \$ipmi_outformat,
|
|
'fc|fancount=i' => \$fan_count,
|
|
'D=s' => \$lanVersion,
|
|
's=s' => \$simulate,
|
|
'h|help' =>
|
|
sub{print STDOUT get_version();
|
|
print STDOUT "\n";
|
|
print STDOUT get_usage();
|
|
print STDOUT "\n";
|
|
print STDOUT get_help();
|
|
exit(0)
|
|
},
|
|
'V|version' =>
|
|
sub{
|
|
print STDOUT get_version();
|
|
exit(0);
|
|
},
|
|
'usage|?' =>
|
|
sub{print STDOUT get_usage();
|
|
exit(3);
|
|
}
|
|
) ) ){
|
|
usage(1);#call usage if GetOptions failed
|
|
}
|
|
usage(1) if @ARGV;#print usage if unknown arg list is left
|
|
|
|
################################################################################
|
|
# check for ipmimonitoring or ipmi-sensors. Since version > 0.8 ipmi-sensors is used
|
|
# if '--legacy-output' is given ipmi-sensors cannot be used
|
|
if( $MISSING_COMMAND_TEXT ne "" ){
|
|
print STDOUT "Error:$MISSING_COMMAND_TEXT";
|
|
exit(3);
|
|
}
|
|
else{
|
|
@ipmi_version = get_ipmi_version();
|
|
if( $ipmi_version[0] > 0 && (grep(/legacy\-output/,@freeipmi_options)) == 0){
|
|
$IPMICOMMAND =~ s/ipmimonitoring/ipmi-sensors/;
|
|
$ipmi_sensors = 1;
|
|
}
|
|
if( $ipmi_version[0] > 0 && (grep(/legacy\-output/,@freeipmi_options)) == 1){
|
|
print "Error: Cannot use ipmi-sensors with option \'--legacy-output\'. Remove it to work correctly.\n";
|
|
exit(3);
|
|
}
|
|
# check if output-sensor-thresholds can be used, this is supported
|
|
# since 1.2.1. Version 1.2.0 was not released, so skip the third minor
|
|
# version number
|
|
if($ipmi_version[0] > 1 || ($ipmi_version[0] == 1 && $ipmi_version[1] >= 2)){
|
|
$use_thresholds = 1;
|
|
}
|
|
else{
|
|
$use_thresholds = 0;
|
|
}
|
|
}
|
|
###############################################################################
|
|
# verify if all mandatory parameters are set and initialize various variables
|
|
#\s defines any whitespace characters
|
|
#first join the list, then split it at whitespace ' '
|
|
#also cf. http://perldoc.perl.org/Getopt/Long.html#Options-with-multiple-values
|
|
@freeipmi_options = split(/\s+/, join(' ', @freeipmi_options)); # a bit hack, shell word splitting should be implemented...
|
|
@ipmi_sensor_types = split(/,/, join(',', @ipmi_sensor_types));
|
|
@ipmi_exclude_sensor_types = split(/,/, join(',', @ipmi_exclude_sensor_types));
|
|
@sel_sensor_types = split(/,/, join(',', @sel_sensor_types));
|
|
@sel_options = split(/,/, join(',', @sel_options));
|
|
@exclude_sel_sensor_types = split(/,/, join(',', @exclude_sel_sensor_types));
|
|
@ipmi_xlist = split(/,/, join(',', @ipmi_xlist));
|
|
@ipmi_ilist = split(/,/, join(',', @ipmi_ilist));
|
|
|
|
#check for zenoss output
|
|
if(defined $ipmi_outformat && $ipmi_outformat eq "zenoss"){
|
|
$zenoss = 1;
|
|
}
|
|
|
|
# Per default monitor all sensor types, use -ST to specify your sensor types
|
|
if(!@sel_sensor_types){
|
|
@sel_sensor_types = ('all');
|
|
}
|
|
# If -xST has not been set, set this array to empty.
|
|
if(!@exclude_sel_sensor_types){
|
|
@exclude_sel_sensor_types = ();
|
|
}
|
|
if(!@sel_options){
|
|
@sel_options = ();
|
|
}
|
|
|
|
# Define basic ipmi command
|
|
my @basecmd = $IPMICOMMAND;
|
|
# If host is omitted localhost is assumed, if not turned off sudo is used
|
|
if(!(defined $ipmi_host) || ($ipmi_host eq 'localhost')){
|
|
if(!defined($no_sudo)){
|
|
# Only add sudo if not already root
|
|
@basecmd = ($> != 0 ? 'sudo' : (), $IPMICOMMAND);
|
|
}
|
|
}
|
|
# If we are not local, we need authentication credentials
|
|
else{
|
|
# Add the ipmi desired host
|
|
push @basecmd, '-h', $ipmi_host;
|
|
if(defined $ipmi_config_file){
|
|
push @basecmd, '--config-file', $ipmi_config_file;
|
|
}
|
|
elsif(defined $ipmi_user && defined $ipmi_password && defined $ipmi_privilege_level ){
|
|
push @basecmd, '-u', $ipmi_user, '-p', $ipmi_password, '-l', $ipmi_privilege_level;
|
|
}
|
|
else{
|
|
$abort_text = $abort_text . " -f <FreeIPMI config file> or -U <username> -P <password> -L <privilege level>";
|
|
}
|
|
if( $abort_text ne ""){
|
|
print STDOUT "Error: " . $abort_text . " missing.";
|
|
print STDOUT get_usage();
|
|
exit(3);
|
|
}
|
|
}
|
|
# copy command for fru usage
|
|
my @frucmd;
|
|
if($use_fru){
|
|
@frucmd = @basecmd
|
|
}
|
|
my @selcmd = @basecmd;
|
|
my @dcmicmd = @basecmd;
|
|
|
|
if(@ipmi_sensor_types){
|
|
# , is the seperator in the new string
|
|
# -g option is older name for ipmi-sensors -t or --sensor-types and
|
|
# compatible with both older and newer version of FreeIPMI
|
|
push @basecmd, '-g', join(',', @ipmi_sensor_types);
|
|
}
|
|
|
|
# add sensor types to exclude
|
|
if(@ipmi_exclude_sensor_types){
|
|
push @basecmd, '--exclude-sensor-types', join(',', @ipmi_exclude_sensor_types);
|
|
}
|
|
|
|
|
|
if(@freeipmi_options){
|
|
push @basecmd, @freeipmi_options;
|
|
}
|
|
|
|
#keep original basecmd for later usage
|
|
my @getstatus = @basecmd;
|
|
|
|
#if -b is not defined, caching options are used
|
|
if( !(defined $freeipmi_compat) ){
|
|
push @getstatus, '--quiet-cache', '--sdr-cache-recreate';
|
|
}
|
|
#since version 0.8 it is possible to interpret OEM data
|
|
if( ($ipmi_version[0] == 0 && $ipmi_version[1] > 7) ||
|
|
$ipmi_version[0] > 0){
|
|
push @getstatus, '--interpret-oem-data';
|
|
}
|
|
#since version 0.8 it is necessary to add the legacy option
|
|
if( ($ipmi_version[0] == 0 && $ipmi_version[1] > 7) && (grep(/legacy\-output/,@freeipmi_options) == 0)){
|
|
push @getstatus, '--legacy-output';
|
|
}
|
|
#if ipmi-sensors is used show the state of sensors and ignore N/A
|
|
if($ipmi_sensors){
|
|
push @getstatus, '--output-sensor-state', '--ignore-not-available-sensors';
|
|
}
|
|
#if not stated otherwise we use protocol lan version 2 per default
|
|
if(!defined($lanVersion)){
|
|
$lanVersion = 'LAN_2_0';
|
|
}
|
|
if($lanVersion ne 'default' && defined $ipmi_host && $ipmi_host ne 'localhost'){
|
|
push @getstatus, "--driver-type=$lanVersion";
|
|
if(!$no_sel){
|
|
push @selcmd, "--driver-type=$lanVersion";
|
|
}
|
|
if($use_fru){
|
|
push @frucmd, "--driver-type=$lanVersion";
|
|
}
|
|
}
|
|
if($use_thresholds && !$no_thresholds){
|
|
push @getstatus, '--output-sensor-thresholds';
|
|
}
|
|
if(defined($sel_tail)){
|
|
push @selcmd, "--tail=$sel_tail";
|
|
}
|
|
|
|
################################################################################
|
|
#execute status command and redirect stdout and stderr to ipmioutput
|
|
my $ipmioutput;
|
|
my $returncode;
|
|
if ($sel_only){
|
|
$returncode = 0;
|
|
}
|
|
elsif(!$simulate){
|
|
run \@getstatus, '>&', \$ipmioutput;
|
|
#the upper eight bits contain the error condition (exit code)
|
|
#see http://perldoc.perl.org/perlvar.html#Error-Variables
|
|
$returncode = $? >> 8;
|
|
}
|
|
else{
|
|
$ipmioutput = simulate($simulate);
|
|
print "DEBUG: Using simulation mode\n";
|
|
$returncode = 0;
|
|
}
|
|
my @fruoutput;
|
|
if($use_fru){
|
|
@fruoutput = get_fru(\@frucmd, $verbosity);
|
|
}
|
|
my $seloutput;
|
|
if(!$no_sel){
|
|
$seloutput = parse_sel(\@selcmd, $verbosity, $sel_xfile, \@sel_sensor_types, \@exclude_sel_sensor_types, \@sel_options);
|
|
}
|
|
my $dcmioutput;
|
|
if(!$no_dcmi){
|
|
$dcmioutput = parse_dcmi(\@dcmicmd, $verbosity);
|
|
}
|
|
################################################################################
|
|
# print debug output when verbosity is set to 3 (-vvv)
|
|
if ( $verbosity == 3 && !$sel_only ){
|
|
my $ipmicommandversion;
|
|
run [$IPMICOMMAND, '-V'], '2>&1', '|', ['head', '-n', 1], '&>', \$ipmicommandversion;
|
|
#remove trailing newline with chomp
|
|
chomp $ipmicommandversion;
|
|
print "------------- debug output for sensors (-vvv is set): ------------\n";
|
|
print " script was executed with the following parameters:\n";
|
|
print " $0 ", join(' ', @ARGV_SAVE), "\n";
|
|
print " check_ipmi_sensor version:\n";
|
|
print " $check_ipmi_sensor_version\n";
|
|
print " FreeIPMI version:\n";
|
|
print " $ipmicommandversion\n";
|
|
print " FreeIPMI was executed with the following parameters:\n";
|
|
print " ", join(' ', @getstatus), "\n";
|
|
print " FreeIPMI return code: $returncode\n";
|
|
print " output of FreeIPMI:\n";
|
|
print "$ipmioutput\n";
|
|
print "--------------------- end of debug output ---------------------\n";
|
|
}
|
|
|
|
################################################################################
|
|
# generate main output
|
|
if ( $returncode != 0 ){
|
|
print "$ipmioutput\n";
|
|
print "-> Execution of $IPMICOMMAND failed with return code $returncode.\n";
|
|
print "-> $IPMICOMMAND was executed with the following parameters:\n";
|
|
my $getstatusoutput = join(' ', @getstatus);
|
|
$getstatusoutput =~ s/$ipmi_password/[HIDDEN]/;
|
|
print " ", $getstatusoutput, "\n";
|
|
exit(3);
|
|
}
|
|
else{
|
|
my @outputRows;
|
|
if(defined($ipmioutput)){
|
|
@outputRows = split('\n', $ipmioutput);
|
|
}
|
|
if(!$sel_only && (!defined($ipmioutput) || scalar(@outputRows) == 1)){
|
|
print "-> Your server seems to be powered off.";
|
|
print " (Execution of FreeIPMI returned an empty output or only 1 header row!)\n";
|
|
print "-> $IPMICOMMAND was executed with the following parameters:\n";
|
|
my $getstatusoutput = join(' ', @getstatus);
|
|
$getstatusoutput =~ s/$ipmi_password/[HIDDEN]/;
|
|
print " ", $getstatusoutput, "\n";
|
|
exit(3);
|
|
}
|
|
#print desired filter types
|
|
if ( @ipmi_sensor_types ){
|
|
print "Sensor Type(s) ", join(', ', @ipmi_sensor_types), " Status: ";
|
|
}
|
|
elsif ($sel_only){
|
|
print "SEL Status: ";
|
|
}
|
|
else{
|
|
print "IPMI Status: ";
|
|
}
|
|
#start with main output
|
|
my $exit = 0;
|
|
my $w_sensors = '';#sensors with warnings
|
|
my $sel_w_sensors = '';#verbose output for sel entries with warnings
|
|
my $perf = '';#performance sensor
|
|
my $curr_fans = 0;
|
|
my @ipmioutput2;#filtered original ipmi output
|
|
|
|
#skip ipmi output, if only SEL queried
|
|
if (!$sel_only){
|
|
#split at newlines, fetch array with lines of output
|
|
my @ipmioutput = split('\n', $ipmioutput);
|
|
|
|
#remove sudo errors and warnings like they appear on dns resolving issues
|
|
@ipmioutput = map { /^sudo:/ ? () : $_ } @ipmioutput;
|
|
|
|
#remove leading and trailing whitespace characters, split at the pipe delimiter
|
|
@ipmioutput = map { [ map { s/^\s*//; s/\s*$//; $_; } split(m/\|/, $_) ] } @ipmioutput;
|
|
|
|
#shift out the header as it is the first line
|
|
my $header = shift @ipmioutput;
|
|
if(!defined($header)){
|
|
print "$ipmioutput\n";
|
|
print " FreeIPMI returned an empty header map (first line)";
|
|
if(@ipmi_sensor_types){
|
|
print " FreeIPMI could not find any sensors for the given sensor type (option '-T').\n";
|
|
}
|
|
exit(3);
|
|
}
|
|
my %header;
|
|
for(my $i = 0; $i < @$header; $i++)
|
|
{
|
|
#assigning %header with (key from hdrmap) => $i
|
|
#checking at which position in the header is which key
|
|
$header{$hdrmap{$header->[$i]}} = $i;
|
|
}
|
|
foreach my $row ( @ipmioutput ){
|
|
my %row;
|
|
#fetch keys from header and assign existent values to row
|
|
#this maps the values from row(ipmioutput) to the header values
|
|
while ( my ($key, $index) = each %header ){
|
|
#check if the option to unify sensor names is active
|
|
if($key eq 'name' && $s_ufile && $s_ufile ne ''){
|
|
$row{$key} = unify_with_file($s_ufile, $row->[$index]);
|
|
}
|
|
else{
|
|
$row{$key} = $row->[$index];
|
|
}
|
|
}
|
|
if(!(exclude_with_file($s_xfile, $row{'name'}, $row{'type'}))){
|
|
push @ipmioutput2, \%row;
|
|
}
|
|
}
|
|
#create hash with sensor name an 1
|
|
my %ipmi_xlist = map { ($_, 1) } @ipmi_xlist;
|
|
#filter out the desired sensor values
|
|
@ipmioutput2 = grep(!exists $ipmi_xlist{$_->{'id'}}, @ipmioutput2);
|
|
#check for an include list
|
|
if(@ipmi_ilist){
|
|
my %ipmi_ilist = map { ($_, 1) } @ipmi_ilist;
|
|
#only include sensors from include list
|
|
@ipmioutput2 = grep(exists $ipmi_ilist{$_->{'id'}}, @ipmioutput2);
|
|
}
|
|
foreach my $row ( @ipmioutput2 ){
|
|
if( $zenoss ){
|
|
$row->{'name'} =~ s/ /_/g;
|
|
}
|
|
my $check_sensor_state = 1;
|
|
if($no_entity_absent){
|
|
if(exists $row->{'event'} && ($row->{'event'} =~ /\'.*((Device|Entity) (Absent|Removed)).*\'/)){
|
|
$check_sensor_state = 0;
|
|
}
|
|
if(exists $row->{'reading'} && ($row->{'reading'} =~ /\'.*((Device|Entity) (Absent|Removed)).*\'/)){
|
|
$check_sensor_state = 0;
|
|
}
|
|
}
|
|
#check for warning sensors
|
|
if($check_sensor_state && ($row->{'state'} ne 'Nominal' && $row->{'state'} ne 'N/A')){
|
|
$exit = 1 if $exit < 1;
|
|
$exit = 2 if $exit < 2 && $row->{'state'} ne 'Warning';
|
|
#don't insert a , the first time
|
|
$w_sensors .= ", " unless $w_sensors eq '';
|
|
$w_sensors .= "$row->{'name'} = $row->{'state'}";
|
|
if( $verbosity ){
|
|
if( $row->{'reading'} ne 'N/A'){
|
|
$w_sensors .= " ($row->{'reading'})" ;
|
|
}
|
|
else{
|
|
$w_sensors .= " ($row->{'event'})";
|
|
}
|
|
}
|
|
}
|
|
if($check_sensor_state && ($row->{'units'} ne 'N/A')){
|
|
my $val = $row->{'reading'};
|
|
my $perf_data;
|
|
my $perf_thresholds;
|
|
if($zenoss){
|
|
$perf_data = $row->{'name'}."=".$val;
|
|
}
|
|
else{
|
|
$perf_data = "'".$row->{'name'}."'=".$val;
|
|
}
|
|
if($use_thresholds && !$no_thresholds){
|
|
if(($row->{'lowerNC'} ne 'N/A') && ($row->{'upperNC'} ne 'N/A')){
|
|
$perf_thresholds = $row->{'lowerNC'}.":".$row->{'upperNC'}.";";
|
|
}
|
|
elsif(($row->{'lowerNC'} ne 'N/A') && ($row->{'upperNC'} eq 'N/A')){
|
|
$perf_thresholds = $row->{'lowerNC'}.":;";
|
|
}
|
|
elsif(($row->{'lowerNC'} eq 'N/A') && ($row->{'upperNC'} ne 'N/A')){
|
|
$perf_thresholds = "~:".$row->{'upperNC'}.";";
|
|
}
|
|
elsif(($row->{'lowerNC'} eq 'N/A') && ($row->{'upperNC'} eq 'N/A')){
|
|
$perf_thresholds = ";";
|
|
}
|
|
if(($row->{'lowerC'} ne 'N/A') && ($row->{'upperC'} ne 'N/A')){
|
|
$perf_thresholds .= $row->{'lowerC'}.":".$row->{'upperC'};
|
|
}
|
|
elsif(($row->{'lowerC'} ne 'N/A') && ($row->{'upperC'} eq 'N/A')){
|
|
$perf_thresholds .= $row->{'lowerC'}.":";
|
|
}
|
|
elsif(($row->{'lowerC'} eq 'N/A') && ($row->{'upperC'} ne 'N/A')){
|
|
$perf_thresholds .= "~:".$row->{'upperC'};
|
|
}
|
|
# Add thresholds to performance data
|
|
if(($row->{'lowerNC'} ne 'N/A') || ($row->{'upperNC'} ne 'N/A') ||
|
|
($row->{'lowerC'} ne 'N/A') || ($row->{'upperC'} ne 'N/A')){
|
|
$perf_data .= ";".$perf_thresholds;
|
|
}
|
|
}
|
|
$perf .= $perf_data." ";
|
|
}
|
|
if( $row->{'type'} eq 'Fan' && $row->{'reading'} ne 'N/A' ){
|
|
$curr_fans++;
|
|
}
|
|
}
|
|
}
|
|
foreach my $row (@{$seloutput}){
|
|
if( $zenoss ){
|
|
$row->{'name'} =~ s/ /_/g;
|
|
}
|
|
if ($row->{'state'} ne 'Nominal'){
|
|
$sel_issues_present += 1;
|
|
$exit = 1 if $exit < 1;
|
|
$exit = 2 if $exit < 2 && $row->{'state'} ne 'Warning';
|
|
if( $verbosity ){
|
|
$sel_w_sensors .= ", " unless $sel_w_sensors eq '';
|
|
$sel_w_sensors .= "($row->{'name'} = $row->{'state'},";
|
|
$sel_w_sensors .= " $row->{'type'}," ;
|
|
$sel_w_sensors .= " $row->{'event'})" ;
|
|
}
|
|
}
|
|
}
|
|
if ( $sel_issues_present ){
|
|
$w_sensors .= ", " unless $w_sensors eq '';
|
|
if ( $sel_issues_present == 1 ){
|
|
$w_sensors .= "1 system event log (SEL) entry present";
|
|
}else{
|
|
$w_sensors .= $sel_issues_present." system event log (SEL) entries present";
|
|
}
|
|
if( $verbosity ){
|
|
$w_sensors .= " - details: ";
|
|
$w_sensors .= $sel_w_sensors;
|
|
$w_sensors .= " - fix the reported issues and clear your SEL";
|
|
$w_sensors .= " or exclude specific SEL entries using the -sx or -xST option";
|
|
}
|
|
}
|
|
#now check if num fans equals desired unit fans
|
|
if( $fan_count ){
|
|
if( $curr_fans < $fan_count ){
|
|
$exit = 1 if $exit < 1;
|
|
$w_sensors .= ", " unless $w_sensors eq '';
|
|
$w_sensors .= "Fan = Warning";
|
|
if( $verbosity ){
|
|
$w_sensors .= " ($curr_fans)" ;
|
|
}
|
|
}
|
|
}
|
|
#check for the FRU serial number, asset tag and board information
|
|
my @server_serial;
|
|
my $serial_number;
|
|
my @server_asset;
|
|
my $asset_tag;
|
|
my @server_board;
|
|
my $board_manufacturer;
|
|
my $board_product;
|
|
my $board_serial;
|
|
if( $use_fru ){
|
|
@server_serial = grep(/Product Serial Number/,@fruoutput);
|
|
if(@server_serial){
|
|
$server_serial[0] =~ m/\:\s+(.*)$/;
|
|
$serial_number = $1;
|
|
}
|
|
if ( $use_asset ){
|
|
@server_asset = grep(/Product Asset Tag/,@fruoutput);
|
|
if(@server_asset){
|
|
$server_asset[0] =~ m/\:\s+(.*)$/;
|
|
$asset_tag = $1;
|
|
}
|
|
}
|
|
if ( $use_board ){
|
|
@server_board = grep(/Board/,@fruoutput);
|
|
foreach ( @server_board) {
|
|
if ( $_ =~ /Board Manufacturer/ ){
|
|
$_ =~ m/Board Manufacturer\:\s+(.*)/;
|
|
$board_manufacturer = $1;
|
|
}
|
|
if ( $_ =~ /Board Product Name/ ){
|
|
$_ =~ m/Board Product Name\:\s+(.*)/;
|
|
$board_product = $1;
|
|
}
|
|
if ( $_ =~ /Board Serial Number/ ){
|
|
$_ =~ m/Board Serial Number\:\s+(.*)/;
|
|
$board_serial = $1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(defined($dcmioutput) && $dcmioutput ne ''){
|
|
my $power_perf = '';
|
|
if(exists $dcmioutput->{'Current Power'}){
|
|
my $power_key = 'Current Power';
|
|
if($s_ufile && $s_ufile ne ''){
|
|
$power_key = unify_with_file($s_ufile, $power_key);
|
|
}
|
|
if( $zenoss ){
|
|
$power_key =~ s/ /_/g;
|
|
}
|
|
$power_perf = "\'$power_key\'=" . $dcmioutput->{'Current Power'};
|
|
}
|
|
$perf = $power_perf . ' ' . $perf;
|
|
}
|
|
$perf = substr($perf, 0, -1);#cut off the last chars
|
|
if ( $exit == 0 ){
|
|
print "OK";
|
|
}
|
|
elsif ( $exit == 1 ){
|
|
print "Warning [$w_sensors]";
|
|
}
|
|
else{
|
|
print "Critical [$w_sensors]";
|
|
}
|
|
if( $use_fru && defined($serial_number)){
|
|
print " ($serial_number)";
|
|
if ($use_asset && defined($asset_tag)){
|
|
print "\nAsset Tag: $asset_tag";
|
|
}
|
|
if ( $use_board ){
|
|
if (defined($board_manufacturer)){
|
|
print "\nBoard Manufacturer: $board_manufacturer";
|
|
}
|
|
if (defined($board_product)){
|
|
print "\nBoard Product: $board_product";
|
|
}
|
|
if (defined($board_serial)){
|
|
print "\nBoard Serial: $board_serial";
|
|
}
|
|
}
|
|
}
|
|
print " | ", $perf if $perf ne '';
|
|
print "\n";
|
|
|
|
if ( $verbosity > 1 ){
|
|
foreach my $row (@ipmioutput2){
|
|
if( $row->{'state'} eq 'N/A'){
|
|
next;
|
|
}
|
|
elsif( $row->{'reading'} ne 'N/A'){
|
|
print "$row->{'name'} = $row->{'reading'} ";
|
|
}
|
|
elsif( $row->{'event'} ne 'N/A'){
|
|
print "$row->{'name'} = $row->{'event'} ";
|
|
}
|
|
else{
|
|
next;
|
|
}
|
|
print "(Status: $row->{'state'})\n";
|
|
}
|
|
}
|
|
exit $exit;
|
|
}
|
|
};
|