it'll try to auto discover sensors available using IPMI and smartctltags/zabbix-agent-addons-0.2.20-1
parent
b2cc891890
commit
e7c34c6e58
1 changed files with 211 additions and 0 deletions
@ -0,0 +1,211 @@ |
||||
#!/usr/bin/perl -w |
||||
|
||||
use strict; |
||||
use warnings; |
||||
use Config::Simple '-strict'; |
||||
use Getopt::Long; |
||||
use File::Basename; |
||||
|
||||
# Output file |
||||
my $output = undef; |
||||
# When a threshold can be automatically detected, |
||||
# you may want to be notified before it's reached, so you can |
||||
# set a margin which will be substracted from the real threshold |
||||
my $temp_margin = '10'; |
||||
#This value will be substracted from the higher threshold to define the low one |
||||
#so you can have hysteresis to prevent flip-flop |
||||
my $temp_hyst = '10'; |
||||
|
||||
GetOptions( |
||||
"output=s" => \$output, |
||||
"temp-margin=i" => \$temp_margin, |
||||
"temp-hyst=i" => \$temp_hyst |
||||
); |
||||
|
||||
sub usage(){ |
||||
print<<"_EOF"; |
||||
Usage: $0 --output=/etc/zabbix/sensors.ini |
||||
_EOF |
||||
} |
||||
|
||||
unless ($output){ |
||||
usage(); |
||||
exit 1; |
||||
} |
||||
|
||||
# Path |
||||
my $ipmitool = '/usr/bin/ipmitool'; |
||||
my $smartctl = '/usr/sbin/smartctl'; |
||||
|
||||
# Default threshold if not detected |
||||
my $def_temp_thres_high = '50'; |
||||
|
||||
my $def_fan_thres_high = '1000'; |
||||
my $def_fan_thres_low = '700'; |
||||
|
||||
my $cfg = new Config::Simple(syntax => 'ini'); |
||||
|
||||
my $sensors = {}; |
||||
|
||||
# Try to detect IPMI sensors |
||||
if (-x $ipmitool){ |
||||
# First check for temperature sensors |
||||
my @lines = qx($ipmitool sdr type Temperature); |
||||
SENSOR: foreach my $l (@lines){ |
||||
chomp $l; |
||||
# Looks like |
||||
# Inlet Temp | 04h | ok | 7.1 | 25 degrees C |
||||
if ($l !~ m/^(\w+[\s\w]+?\w+)\s*\|.*\|\s*([\w\.\s]+)\s*\|.*\|\s*([\-\w\.\s]+)$/){ |
||||
next SENSOR; |
||||
} |
||||
my $name = $1; |
||||
my $sensor = {}; |
||||
|
||||
my @details = qx($ipmitool sdr get '$name'); |
||||
foreach my $d (@details){ |
||||
chomp $d; |
||||
if ($d =~ m/^\s*Sensor\sReading\s*:\s*(\w+)/){ |
||||
my $val = $1; |
||||
if ($val !~ m/^\d+$/){ |
||||
print "Skipping sensor $name, couldn't parse its value: $val\n"; |
||||
next SENSOR; |
||||
} |
||||
} |
||||
elsif ($d =~ m/^\s*Upper\scritical\s*:\s*(\d+(\.\d+))/){ |
||||
$sensor->{threshold_high} = $1-$temp_margin; |
||||
} |
||||
elsif ($d =~ m/^\s*Upper\snon\-critical\s*:\s*(\d+(\.\d+))/){ |
||||
$sensor->{threshold_low} = $1-$temp_margin; |
||||
} |
||||
} |
||||
$sensor->{threshold_high} ||= $def_temp_thres_high; |
||||
$sensor->{threshold_low} ||= $def_temp_thres_high-$temp_hyst; |
||||
$sensor->{threshold_high} =~ s/\.0+$//; |
||||
$sensor->{threshold_low} =~ s/\.0+$//; |
||||
$sensor->{description} = $name; |
||||
$sensor->{type} = 'temp'; |
||||
$sensor->{unit} = '°C'; |
||||
$sensor->{cmd} = "$ipmitool sdr get '$name' | grep 'Sensor Reading' | awk '{print \$4}'"; |
||||
my $id = lc $name; |
||||
$id =~ s/\s/_/g; |
||||
$sensors->{$id} = $sensor; |
||||
print "Found a temperature sensor using IPMI: $name\n"; |
||||
} |
||||
# Now check for Fan, nearly the same as Temp, but |
||||
# * We try to detect the unit |
||||
# * threshold handling is not the same |
||||
@lines = qx($ipmitool sdr type Fan); |
||||
SENSOR: foreach my $l (@lines){ |
||||
chomp $l; |
||||
$l =~ m/^(\w+[\s\w]+?\w+)\s*\|.*\|\s*([\w\.\s]+)\s*\|.*\|\s*([\-\w\.\s]+)$/; |
||||
my $name = $1; |
||||
my $val = $3; |
||||
my $sensor = {}; |
||||
|
||||
my @details = qx($ipmitool sdr get '$name'); |
||||
foreach my $d (@details){ |
||||
chomp $d; |
||||
if ($d =~ m/^\s*Sensor\sReading\s*:\s*(\w+)/){ |
||||
my $val = $1; |
||||
if ($val !~ m/^\d+$/){ |
||||
print "Skipping sensor $name, couldn't parse its value: $val\n"; |
||||
next SENSOR; |
||||
} |
||||
} |
||||
elsif ($d =~ m/^\s*Lower\scritical\s*:\s*(\d+(\.\d+))/){ |
||||
$sensor->{threshold_low} = $1-$temp_margin; |
||||
} |
||||
elsif ($d =~ m/^\s*Lower\snon\-critical\s*:\s*(\d+(\.\d+))/){ |
||||
$sensor->{threshold_high} = $1-$temp_margin; |
||||
} |
||||
} |
||||
$sensor->{threshold_high} ||= $def_fan_thres_high; |
||||
$sensor->{threshold_low} ||= $def_fan_thres_high-$temp_hyst; |
||||
$sensor->{threshold_high} =~ s/\.0+$//; |
||||
$sensor->{threshold_low} =~ s/\.0+$//; |
||||
$sensor->{description} = $name; |
||||
$sensor->{type} = 'fan'; |
||||
$sensor->{unit} = ($val =~ m/percent|%/) ? '%' : 'rpm'; |
||||
$sensor->{cmd} = "$ipmitool sdr get '$name' | grep 'Sensor Reading' | awk '{print \$4}'"; |
||||
my $id = lc $name; |
||||
$id =~ s/\s/_/g; |
||||
$sensors->{$id} = $sensor; |
||||
print "Found a fan sensor using IPMI: $name\n"; |
||||
} |
||||
} |
||||
|
||||
# Now, try to detect smart capable HDD |
||||
if (-x $smartctl){ |
||||
# This is copied from disco_smart_sudo, I should create a module to |
||||
# consolidate this |
||||
opendir(my $dh, "/sys/block") or die "Couldn't open /sys/block: $!"; |
||||
my @blocks = grep { $_ !~ m/^\./ } readdir($dh); |
||||
closedir($dh); |
||||
foreach my $block (@blocks){ |
||||
my $removable = 0; |
||||
my $size = 1; |
||||
# Skip block we already know they won't support SMART |
||||
next if ($block =~ m/^(ram|loop|md|dm\-)\d+/); |
||||
if ( -e "/sys/block/$block/removable"){ |
||||
open REMOVABLE, "/sys/block/$block/removable"; |
||||
$removable = join "", <REMOVABLE>; |
||||
close REMOVABLE; |
||||
chomp($removable); |
||||
next if ($removable eq '1'); |
||||
} |
||||
if ( -e "/sys/block/$block/size"){ |
||||
open SIZE, "/sys/block/$block/size"; |
||||
$size = join "", <SIZE>; |
||||
close SIZE; |
||||
chomp($size); |
||||
next if ($size eq '0'); |
||||
} |
||||
my @lines = qx($smartctl -A /dev/$block); |
||||
next if ($? != 0); |
||||
foreach my $l (@lines){ |
||||
if ($l =~ /Temperature_Celsius/){ |
||||
my $sensor = { |
||||
description => "$block temperature", |
||||
threshold_low => $def_temp_thres_high-$temp_hyst, |
||||
threshold_high => $def_temp_thres_high, |
||||
type => 'temp', |
||||
unit => '°C', |
||||
cmd => "$smartctl -A /dev/$block | grep Temperature_Celsius | awk '{print \$10}'" |
||||
}; |
||||
$sensors->{$block} = $sensor; |
||||
print "Found a temperature sensor using smartctl: $block\n"; |
||||
last; |
||||
} |
||||
} |
||||
} |
||||
# Some LSI based hardware RAID controller can report HDD temp |
||||
if (-e '/dev/megaraid_sas_ioctl_node'){ |
||||
# Only check for the firsts 26 drives |
||||
foreach my $i (0..25){ |
||||
my @res = qx($smartctl -d megaraid,$i -A /dev/sda); |
||||
next if ($? != 0); |
||||
foreach my $l (@res){ |
||||
if ($l =~ m/Drive\sTrip\sTemperature:\s+(\d+)\s/){ |
||||
my $sensor = { |
||||
description => "Temperature for disk No $i on sda", |
||||
type => 'temp', |
||||
threshold_high => $1-$temp_margin, |
||||
threshold_low => $1-$temp_margin-$temp_hyst, |
||||
unit => '°C', |
||||
cmd => "$smartctl -A -d megaraid,$i /dev/sda | grep 'Current Drive Temperature' | awk '{print \$4}'" |
||||
}; |
||||
$sensors->{'sda-' . $i} = $sensor; |
||||
print "Found a temperature sensor using smartctl (megaraid): sda-$i\n"; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
# TODO: add support for lm sensors, but its ouput is harder to parse |
||||
|
||||
foreach my $s (keys %$sensors){ |
||||
$cfg->set_block($s, $sensors->{$s}); |
||||
} |
||||
|
||||
$cfg->write($output); |
Loading…
Reference in new issue