#!/usr/bin/perl ############################################################################# # Copyright (C) 2003-2009 FreeIPMI Core Team # # 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, 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 . ############################################################################# # # nagios_ipmi_sensors.pl # # Author: # # Albert Chu # # Description: # # This script can be used to monitor IPMI sensors in nagios via # FreeIPMI's ipmi-sensors. # # This tool will monitor the sensor state (Nominal, Warning, or # Critical) of each sensor as determined by libfreeipmi's interpret # library. The Nominal, Warning, and Critical states of each sensor # will be collected and counted. The overall IPMI sensor status will # be mapped into a Nagios status of OK, Warning, or Critical. Details # will then be output for Nagios to read. See ipmi-sensors(8) for # more general info on ipmi-sensors and # freeipmi_interpret_sensors.conf(5) for more information on sensor # states. # # Options: # # -h - specify hostname(s) to remotely access (don't specify for inband) # -S - specify an alternate ipmi_sensors location # -s - specify additional ipmi_sensors arguments # -d - print debug info # -H - output help # # Environment Variables: # # IPMI_HOSTS - specify hostname(s) to remotely access (don't specify for inband) # IPMI_SENSORS_PATH - specify an alternate ipmi-ssensors location # IPMI_SENSORS_ARGS - specify additional ipmi-sensors arguments # # Setup Notes: # # Specify the remote hosts you wish to access IPMI information from # via the -h option or IPMI_HOSTS environment variable. If you wish # only to monitor the local node, do not specify an ipmi host. The # input to the -h option is passed directly to ipmimonitoring. So you # may specify anything the ipmimonitoring tool accepts including # hostranged (e.g. foo[0-127]) or comma separated # (e.g. foo0,foo1,foo2,foo3) inputs. If you wish to monitor both # remote and local system, remember to specify one of the hosts as # "localhost". Most will probably want to monitor just one host (get # the IPMI status for each individual machine being monitored), # however more than one host can be analyzed for a collective result. # # If stored in a non-default location the -S option or # IPMI_SENSORS_PATH environment variable must be specified to # determine the ipmimonitoring location. # # In order to specify non-defaults for ipmimonitoring use the -s # argument or IPMI_SENSORS_ARGS environment variable. Typically, # this option is necessary for non-default communication information # or authentication information (e.g. driver path, driver type, # username, password, etc.). Non-default communication information # can also be stored in the FreeIPMI configuration file. This is the # suggested method because passwords and other sensitive information # could show up in ps(1). If you wish to limit the sensors being # monitored, you can also specify which record-ids are to be monitored # (-s option). # # The setup for this can vary depending on your environment and nagios # setup, but most will need to set this up in nagios by defining a # command and then a service. # # define command { # command_name nagios_ipmi_sensors # command_line /path/nagios_ipmi_sensors.pl -h $ARG1$ # } # # define service { # host_name foohost # service_description ipmi # check_command nagios_ipmi_sensors!foohost # } # # The default session timeout length in ipmi-sensors is 20 seconds. # We would recommend that IPMI not be monitored more frequently than # that. # # Help: # # Report bugs to freeipmi-users@gnu.org or freeipmi-devel@gnu.org. # ############################################################################# use strict; use Getopt::Std; my $debug = 0; my $IPMI_HOSTS = undef; my $IPMI_SENSORS_PATH = "/usr/sbin/ipmi-sensors"; my $IPMI_SENSORS_ARGS = ""; my $IPMI_SENSORS_OUTPUT; my @IPMI_SENSORS_OUTPUT_LINES; my $line; my $cmd; my $num_output = 0; my $warning_num = 0; my $critical_num = 0; my $fatal_error = 0; sub usage { my $prog = $0; print "Usage: $prog [-h ] [-S ] [-s ] [-d] [-H]\n"; print " -h specify hostname(s) to remotely access\n"; print " -S specify an alternate ipmi-sensors path\n"; print " -s specify additional ipmi-sensors arguments\n"; print " -d print debug info\n"; print " -H output help\n"; exit 0; } if (!getopts("h:S:s:dH")) { usage(); } if (defined($main::opt_H)) { usage(); } if (defined($main::opt_h)) { $IPMI_HOSTS = $main::opt_h; } if (defined($main::opt_S)) { $IPMI_SENSORS_PATH = $main::opt_S; } if (defined($main::opt_s)) { $IPMI_SENSORS_ARGS = $main::opt_s; } if (defined($main::opt_d)) { $debug = 1; } if ($ENV{"IPMI_HOSTS"}) { $IPMI_HOSTS = $ENV{"IPMI_HOSTS"}; } if ($ENV{"IPMI_SENSORS_PATH"}) { $IPMI_SENSORS_PATH = $ENV{"IPMI_SENSORS_PATH"}; } if ($ENV{"IPMI_SENSORS_ARGS"}) { $IPMI_SENSORS_ARGS = $ENV{"IPMI_SENSORS_ARGS"}; } if ($debug) { print "IPMI_HOSTS=$IPMI_HOSTS\n"; print "IPMI_SENSORS_PATH=$IPMI_SENSORS_PATH\n"; print "IPMI_SENSORS_ARGS=$IPMI_SENSORS_ARGS\n"; } if (!(-x $IPMI_SENSORS_PATH)) { print "$IPMI_SENSORS_PATH cannot be executed\n"; exit(1); } # note, don't need --ignore-non-interpretable-sensors, legacy output handles it if ($IPMI_HOSTS) { $cmd = "$IPMI_SENSORS_PATH $IPMI_SENSORS_ARGS -h $IPMI_HOSTS --quiet-cache --sdr-cache-recreate --always-prefix --no-header-output --output-sensor-state"; } else { $cmd = "$IPMI_SENSORS_PATH $IPMI_SENSORS_ARGS --quiet-cache --sdr-cache-recreate --always-prefix --no-header-output --output-sensor-state" } if ($debug) { print "ipmi-sensors command: $cmd\n"; } $IPMI_SENSORS_OUTPUT = `$cmd`; if ($? != 0) { print "$IPMI_SENSORS_PATH: exited with error\n"; } @IPMI_SENSORS_OUTPUT_LINES = split(/\n/, $IPMI_SENSORS_OUTPUT); foreach $line (@IPMI_SENSORS_OUTPUT_LINES) { my $hostname; my $record_id; my $id_string; my $type; my $state; my $reading; my $units; my $event; my $id_string_state; my $output_str; if ($debug) { print "Parsing: $line\n"; } if ($line =~ /(.+)\: (\d+)(\s+)\| (.+)(\s+)\| (.+)(\s+)\| (.+)(\s+)\| (.+)(\s+)\| (.+)(\s+)\| (.+)/) { $hostname = $1; $record_id = $2; $id_string = $4; $type = $6; $state = $8; $reading = $10; $units = $12; $event = $14; # trim whitespace off end of string $record_id =~ s/\s+$//; $id_string =~ s/\s+$//; $type =~ s/\s+$//; $state =~ s/\s+$//; $reading =~ s/\s+$//; $units =~ s/\s+$//; } else { print "Line not parsable\n"; $fatal_error++; next; } # make name better, convert spaces and slashes into underscores $id_string =~ s/ /_/g; $id_string =~ s/\//_/g; if ($state eq "Nominal") { next; } if ($state eq "N/A") { next; } if ($state eq "Warning") { $warning_num++; $output_str = "WARNING"; } elsif ($state eq "Critical") { $critical_num++; $output_str = "CRITICAL"; } else { print "State not parsable\n"; $fatal_error++; next; } if ($num_output) { print "; "; } print "$id_string - $output_str"; $num_output++; } # Nagios Exit Codes # 0 = OK # 1 = WARNING # 2 = CRITICAL # 3 = UNKNOWN if ($fatal_error) { exit 3; } if ($critical_num) { exit 2; } if ($warning_num) { exit 1; } exit 0;