#!/usr/bin/perl ############################################################################# # Copyright (C) 2003-2010 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 . ############################################################################# # # ganglia_ipmi_sensors.pl # # Author: # # Albert Chu # # Description: # # This script can be used to monitor IPMI sensors in ganglia via # FreeIPMI's ipmi-sensors. # # By default, this tool will monitor the sensor state (Nominal, # Warning, or Critical) of each sensor as determined by libfreeipmi's # interpret library and the sensor readings of temperature, fan and # voltage sensors. 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) # -r - specify search and replace substitution expressions (separated by a colon) to # modify a hostname before being passed to gmetric. This is useful if # the IPMI hostname differs from the desired hostname to input to gmetric. # For example "ipmi:my" would turn "ipmihost4" into "myhost4". Not specifying # a colon results in a degenerate string removal. For example, # "-ipmi" would turn "host4-ipmi" into "host4". # -S - specify an alternate ipmi-sensors location # -s - specify additional ipmi-sensors arguments # -G - specify an alternate gmetric location # -g - specify additional gmetric arguments # -d - print debug info # -D - do not send sensor data to ganglia (useful during debugging) # -H - output help # # Environment Variables: # # IPMI_HOSTS - specify hostname(s) to remotely access (don't specify for inband) # IPMI_HOSTS_SUBST - specify search and replace substitution # expressions (separated by a colon) to modify a # hostname before being passed to gmetric. This is # useful if the IPMI hostname differs from the # desired hostname to input to gmetric. # IPMI_SENSORS_PATH - specify an alternate ipmi-sensors location # IPMI_SENSORS_ARGS - specify additional ipmi-sensors arguments # GMETRIC_PATH - specify an alternate gmetric location # GMETRIC_ARGS - specify additional gmetric 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 ipmi-sensors. So you # may specify anything the ipmi-sensors 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". # # If stored in a non-default location the -S option or # IPMI_SENSORS_PATH environment variable must be specified to # determine the ipmi-sensors location. # # If stored in a non-default location the -G option or GMETRIC_PATH # environment variable must be specified to determine the gmetric # location. # # In order to specify non-defaults for ipmi-sensors 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 # (-r option). # # In order to specify non-defaults for gmetric, use the -g argument # or GMETRIC_ARGS environment variable. Typically, this option is # necessary for non-default gmond.conf paths (i.e. -c # /myspecial/gmond.conf). # # Most users will want to set this script to execute in cron(8). # Using cron you may monitor at whatever interval you wish. The # recommended interval should be atleast longer than 20 seconds, since # that is the default session timeout length. # # Help: # # Report bugs to freeipmi-users@gnu.org or freeipmi-devel@gnu.org. # ############################################################################# use strict; use Getopt::Std; use Socket; my $no_sensor_state = 0; my $no_sensor_readings = 0; my $debug = 0; my $no_ganglia = 0; my $IPMI_HOSTS = undef; my $IPMI_HOSTS_SUBST = undef; my $IPMI_SENSORS_PATH = "/usr/sbin/ipmi-sensors"; my $IPMI_SENSORS_ARGS = ""; my $GMETRIC_PATH = "/usr/bin/gmetric"; my $GMETRIC_ARGS = ""; my $IPMI_SENSORS_EXTRA_ARGS = ""; my $IPMI_SENSORS_OUTPUT; my @IPMI_SENSORS_OUTPUT_LINES; my $line; my $cmd; my @subst; sub usage { my $prog = $0; print "Usage: $prog [-h ] [-r ] [-S ] [-s ] [-G ] [-g ] [-T] [-t] [-d] [-H]\n"; print " -h specify hostname(s) to remotely access\n"; print " -r specify search and replace substitution expressions on the hostname (e.g. 'ipmi:host')\n"; print " -S specify an alternate ipmi-sensors path\n"; print " -s specify additional ipmi-sensors arguments\n"; print " -G specify an alternate gmetric path\n"; print " -g specify additional gmetric arguments\n"; print " -T do not monitor sensor state\n"; print " -t do not monitor sensor readings\n"; print " -d print debug info\n"; print " -D do not send sensor data to ganglia (useful during debugging)\n"; print " -H output help\n"; exit 0; } if (!getopts("h:r:S:s:G:g:TtdDH")) { usage(); } if (defined($main::opt_H)) { usage(); } if (defined($main::opt_h)) { $IPMI_HOSTS = $main::opt_h; } if (defined($main::opt_r)) { $IPMI_HOSTS_SUBST = $main::opt_r; } 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_G)) { $GMETRIC_PATH = $main::opt_G; } if (defined($main::opt_g)) { $GMETRIC_ARGS = $main::opt_g; } if (defined($main::opt_T)) { $no_sensor_state = 1; } if (defined($main::opt_t)) { $no_sensor_readings = 1; } if (defined($main::opt_d)) { $debug = 1; } if (defined($main::opt_D)) { $no_ganglia = 1; } if ($ENV{"IPMI_HOSTS"}) { $IPMI_HOSTS = $ENV{"IPMI_HOSTS"}; } if ($ENV{"IPMI_HOSTS_SUBST"}) { $IPMI_HOSTS_SUBST = $ENV{"IPMI_HOSTS_SUBST"}; } 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 ($ENV{"GMETRIC_PATH"}) { $GMETRIC_PATH = $ENV{"GMETRIC_PATH"}; } if ($ENV{"GMETRIC_ARGS"}) { $GMETRIC_ARGS = $ENV{"GMETRIC_ARGS"}; } if ($debug) { print "IPMI_HOSTS=$IPMI_HOSTS\n"; print "IPMI_HOSTS_SUBST=$IPMI_HOSTS_SUBST\n"; print "IPMI_SENSORS_PATH=$IPMI_SENSORS_PATH\n"; print "IPMI_SENSORS_ARGS=$IPMI_SENSORS_ARGS\n"; print "GMETRIC_PATH=$GMETRIC_PATH\n"; print "GMETRIC_ARGS=$GMETRIC_ARGS\n"; } if (!(-x $IPMI_SENSORS_PATH)) { print "$IPMI_SENSORS_PATH cannot be executed\n"; exit(1); } if (!$no_ganglia) { if (!(-x $GMETRIC_PATH)) { print "$GMETRIC_PATH cannot be executed\n"; exit(1); } } if ($no_sensor_state && $no_sensor_readings) { print "Must monitor atleast sensor state or sensor readings\n"; exit(1); } 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 $ip_address; my $cmd_state; my $cmd_reading; 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"; next; } # make name better, convert spaces and slashes into underscores $id_string =~ s/ /_/g; $id_string =~ s/\//_/g; if ($IPMI_HOSTS_SUBST) { @subst = split(/:/, $IPMI_HOSTS_SUBST); $hostname =~ s/$subst[0]/$subst[1]/; } if ($hostname ne "localhost" && $hostname ne "127.0.0.1") { my $packet_ip = gethostbyname($hostname); if (defined($packet_ip)) { $ip_address = inet_ntoa($packet_ip); } else { print "Cannot resolve ip: $hostname\n"; next; } } if (!$no_sensor_state) { if ($state ne "N/A") { $id_string_state = $id_string . "_State"; if ($hostname ne "localhost" && $hostname ne "127.0.0.1") { $cmd_state = "$GMETRIC_PATH $GMETRIC_ARGS -n $id_string_state -v $state -t string -S $ip_address:$hostname"; } else { $cmd_state = "$GMETRIC_PATH $GMETRIC_ARGS -n $id_string_state -v $state -t string"; } } } if (!$no_sensor_readings) { if ((($type eq "Temperature" && ($units eq "C" || $units eq "F")) || ($type eq "Voltage" && $units eq "V") || ($type eq "Fan" && $units eq "RPM")) && $reading ne "N/A") { if ($hostname ne "localhost" && $hostname ne "127.0.0.1") { $cmd_reading = "$GMETRIC_PATH $GMETRIC_ARGS -n $id_string -v $reading -t double -u $units -S $ip_address:$hostname"; } else { $cmd_reading = "$GMETRIC_PATH $GMETRIC_ARGS -n $id_string -v $reading -t double -u $units"; } } } if ($debug) { if ($cmd_state) { print "gmetric command = $cmd_state\n"; } if ($cmd_reading) { print "gmetric command = $cmd_reading\n"; } } if (!$no_ganglia) { if ($cmd_state) { `$cmd_state`; if ($? != 0) { print "\"$cmd_state\": failed\n"; exit(1); } } if ($cmd_reading) { `$cmd_reading`; if ($? != 0) { print "\"$cmd_reading\": failed\n"; exit(1); } } } }