mirror of
https://github.com/munin-monitoring/contrib.git
synced 2025-07-23 06:35:42 +00:00
Added handling of parameter 190 (Airflow_Temperature), Seagate hard drives the next generation.
This commit is contained in:
parent
37c8fd9a77
commit
6dbfc42550
1 changed files with 249 additions and 247 deletions
|
@ -1,247 +1,249 @@
|
||||||
#!/usr/local/bin/perl -w
|
#!/usr/local/bin/perl -w
|
||||||
# -*- perl -*-
|
# -*- perl -*-
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
hddtemp_smartctl - Plugin to monitor harddrive temperatures through
|
hddtemp_smartctl - Plugin to monitor harddrive temperatures through
|
||||||
SMART
|
SMART
|
||||||
|
|
||||||
=head1 CONFIGURATION
|
=head1 CONFIGURATION
|
||||||
|
|
||||||
This plugin needs to run as root or some other user that has access to
|
This plugin needs to run as root or some other user that has access to
|
||||||
the harddrive devices.
|
the harddrive devices.
|
||||||
|
|
||||||
The following environment variables are used
|
The following environment variables are used
|
||||||
|
|
||||||
smartctl - path to smartctl executable
|
smartctl - path to smartctl executable
|
||||||
drives - List drives to monitor. E.g. "env.drives hda hdc".
|
drives - List drives to monitor. E.g. "env.drives hda hdc".
|
||||||
type_$dev - device type for one drive, e.g. "env.type_sda 3ware,0"
|
type_$dev - device type for one drive, e.g. "env.type_sda 3ware,0"
|
||||||
or more typically "env.type_sda ata" if sda is a SATA disk.
|
or more typically "env.type_sda ata" if sda is a SATA disk.
|
||||||
args_$dev - additional arguments to smartctl for one drive,
|
args_$dev - additional arguments to smartctl for one drive,
|
||||||
e.g. "env.args_hda -v 194,10xCelsius". Use this to make
|
e.g. "env.args_hda -v 194,10xCelsius". Use this to make
|
||||||
the plugin use the --all or -a option if your disk will
|
the plugin use the --all or -a option if your disk will
|
||||||
not return its temperature when only the -A option is
|
not return its temperature when only the -A option is
|
||||||
used.
|
used.
|
||||||
dev_$dev - monitoring device for one drive, e.g. twe0
|
dev_$dev - monitoring device for one drive, e.g. twe0
|
||||||
|
|
||||||
If the "smartctl" enviroment variable is not set the plugin will
|
If the "smartctl" enviroment variable is not set the plugin will
|
||||||
search your $PATH, /usr/bin, /usr/sbin, /usr/local/bin and
|
search your $PATH, /usr/bin, /usr/sbin, /usr/local/bin and
|
||||||
/usr/local/sbin for a file called "smartctl", and use that.
|
/usr/local/sbin for a file called "smartctl", and use that.
|
||||||
|
|
||||||
If the "drives" environment variable is not set, the plugin will
|
If the "drives" environment variable is not set, the plugin will
|
||||||
attempt to search for drives to probe.
|
attempt to search for drives to probe.
|
||||||
|
|
||||||
=head1 MAGIC MARKERS
|
=head1 MAGIC MARKERS
|
||||||
|
|
||||||
#%# family=auto
|
#%# family=auto
|
||||||
#%# capabilities=autoconf
|
#%# capabilities=autoconf
|
||||||
|
|
||||||
=head1 AUTHOR
|
=head1 AUTHOR
|
||||||
|
|
||||||
Copyright (c) 2005, Lutz Peter Christoph
|
Copyright (c) 2005, Lutz Peter Christoph
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
=head1 LICENSE
|
=head1 LICENSE
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions
|
modification, are permitted provided that the following conditions
|
||||||
are met:
|
are met:
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in
|
notice, this list of conditions and the following disclaimer in
|
||||||
the documentation and/or other materials provided with the
|
the documentation and/or other materials provided with the
|
||||||
distribution.
|
distribution.
|
||||||
|
|
||||||
* The name and aliases of Lutz Peter Christoph ("Lupe Christoph",
|
* The name and aliases of Lutz Peter Christoph ("Lupe Christoph",
|
||||||
"Lutz Christoph") may not be used to endorse or promote products
|
"Lutz Christoph") may not be used to endorse or promote products
|
||||||
derived from this software without specific prior written
|
derived from this software without specific prior written
|
||||||
permission.
|
permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
=head1 NOTES
|
=head1 NOTES
|
||||||
|
|
||||||
Note for users of RAID controllers (smartmontools currently only
|
Note for users of RAID controllers (smartmontools currently only
|
||||||
supports 3ware): you can specify the drives attached to your RAID
|
supports 3ware): you can specify the drives attached to your RAID
|
||||||
controller(s) as raiddev_num (e.g. sda_0). Then you must specify the
|
controller(s) as raiddev_num (e.g. sda_0). Then you must specify the
|
||||||
type like this: type_sda_0 3ware,0.
|
type like this: type_sda_0 3ware,0.
|
||||||
|
|
||||||
Recent versions of the kernel driver use a separate major device
|
Recent versions of the kernel driver use a separate major device
|
||||||
number for monitoring purposes, like /dev/twe<n> or /dev/twa<n>. This
|
number for monitoring purposes, like /dev/twe<n> or /dev/twa<n>. This
|
||||||
can be put in the e.g. dev_sda environment variable, to allow the user
|
can be put in the e.g. dev_sda environment variable, to allow the user
|
||||||
to keep sda as the name of the disk.
|
to keep sda as the name of the disk.
|
||||||
|
|
||||||
To avoid spinning up sleeping disks smartctl will use the --nocheck
|
To avoid spinning up sleeping disks smartctl will use the --nocheck
|
||||||
parameter. If this parameter isn't supported by your version of
|
parameter. If this parameter isn't supported by your version of
|
||||||
smartctl then hdparm will be used. Note that hdparm isn't available
|
smartctl then hdparm will be used. Note that hdparm isn't available
|
||||||
on all platforms.
|
on all platforms.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
my $DEBUG = $ENV{'MUNIN_DEBUG'} || 0;
|
my $DEBUG = $ENV{'MUNIN_DEBUG'} || 0;
|
||||||
|
|
||||||
my $smartctl = exists $ENV{smartctl} ? $ENV{smartctl} : '';
|
my $smartctl = exists $ENV{smartctl} ? $ENV{smartctl} : '';
|
||||||
|
|
||||||
# If the envvar is not set, look for smartctl
|
# If the envvar is not set, look for smartctl
|
||||||
if (!$smartctl) {
|
if (!$smartctl) {
|
||||||
# Still not found? Check obvious places
|
# Still not found? Check obvious places
|
||||||
my @dirs = split(':',$ENV{PATH});
|
my @dirs = split(':',$ENV{PATH});
|
||||||
push (@dirs, qw(/usr/bin /usr/sbin /usr/local/bin /usr/local/sbin) );
|
push (@dirs, qw(/usr/bin /usr/sbin /usr/local/bin /usr/local/sbin) );
|
||||||
|
|
||||||
until ($smartctl or @dirs == 0) {
|
until ($smartctl or @dirs == 0) {
|
||||||
my $dir = shift @dirs;
|
my $dir = shift @dirs;
|
||||||
my $path = $dir.'/smartctl';
|
my $path = $dir.'/smartctl';
|
||||||
$smartctl = $path if -x $path;
|
$smartctl = $path if -x $path;
|
||||||
}
|
}
|
||||||
} elsif (! -x $smartctl) {
|
} elsif (! -x $smartctl) {
|
||||||
# If it is set, verify it
|
# If it is set, verify it
|
||||||
warn "Predefined smartctl ($smartctl) is not a executable\n";
|
warn "Predefined smartctl ($smartctl) is not a executable\n";
|
||||||
undef $smartctl;
|
undef $smartctl;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check version of smartctl to determine --nocheck capabilities
|
# Check version of smartctl to determine --nocheck capabilities
|
||||||
my $use_nocheck = 0;
|
my $use_nocheck = 0;
|
||||||
if ($smartctl and `$smartctl --version` =~ / version (\d+\.\d+) /i) {
|
if ($smartctl and `$smartctl --version` =~ / version (\d+\.\d+) /i) {
|
||||||
$use_nocheck = $1 >= 5.37;
|
$use_nocheck = $1 >= 5.37;
|
||||||
warn "[DEBUG] Smartctl supports --nocheck\n" if $DEBUG;
|
warn "[DEBUG] Smartctl supports --nocheck\n" if $DEBUG;
|
||||||
}
|
}
|
||||||
|
|
||||||
# hdparm is used as a fallback
|
# hdparm is used as a fallback
|
||||||
my $hdparm = `which hdparm 2>/dev/null`;
|
my $hdparm = `which hdparm 2>/dev/null`;
|
||||||
chomp $hdparm;
|
chomp $hdparm;
|
||||||
|
|
||||||
my @drives;
|
my @drives;
|
||||||
|
|
||||||
# Try to get a default set of drives
|
# Try to get a default set of drives
|
||||||
if ($^O eq 'linux') {
|
if ($^O eq 'linux') {
|
||||||
# On Linux, we know how to enumerate ide drives. SCSI is not as easy
|
# On Linux, we know how to enumerate ide drives. SCSI is not as easy
|
||||||
if (-d '/proc/ide') {
|
if (-d '/proc/ide') {
|
||||||
opendir(IDE, '/proc/ide');
|
opendir(IDE, '/proc/ide');
|
||||||
@drives = grep /hd[a-z]/, readdir IDE;
|
@drives = grep /hd[a-z]/, readdir IDE;
|
||||||
closedir(IDE);
|
closedir(IDE);
|
||||||
}
|
}
|
||||||
# "SCSI disks" could be both SCSI or SATA - we can't know which
|
# "SCSI disks" could be both SCSI or SATA - we can't know which
|
||||||
# without probing them.
|
# without probing them.
|
||||||
} elsif ($^O eq 'freebsd') {
|
} elsif ($^O eq 'freebsd') {
|
||||||
opendir(DEV, '/dev');
|
opendir(DEV, '/dev');
|
||||||
@drives = grep /^ada*[0-9]+$/, readdir DEV;
|
@drives = grep /^ad[0-9]+$/, readdir DEV;
|
||||||
closedir(DEV);
|
closedir(DEV);
|
||||||
} elsif ($^O eq 'solaris') {
|
} elsif ($^O eq 'solaris') {
|
||||||
@drives = map { s@.*/@@ ; $_ } glob '/dev/rdsk/c*t*d*s2';
|
@drives = map { s@.*/@@ ; $_ } glob '/dev/rdsk/c*t*d*s2';
|
||||||
}
|
}
|
||||||
|
|
||||||
@drives = split ' ', $ENV{drives} if exists $ENV{drives};
|
@drives = split ' ', $ENV{drives} if exists $ENV{drives};
|
||||||
|
|
||||||
# Sort list of drives
|
# Sort list of drives
|
||||||
@drives = sort @drives;
|
@drives = sort @drives;
|
||||||
|
|
||||||
warn "[DEBUG] Drives: ",join(', ',@drives),"\n" if $DEBUG;
|
warn "[DEBUG] Drives: ",join(', ',@drives),"\n" if $DEBUG;
|
||||||
|
|
||||||
if (defined $ARGV[0]) {
|
if (defined $ARGV[0]) {
|
||||||
if ($ARGV[0] eq 'autoconf') {
|
if ($ARGV[0] eq 'autoconf') {
|
||||||
if ($smartctl and -x $smartctl) {
|
if ($smartctl and -x $smartctl) {
|
||||||
if (@drives) {
|
if (@drives) {
|
||||||
my $cmd = command_for_drive_device($drives[0],
|
my $cmd = command_for_drive_device($drives[0],
|
||||||
device_for_drive($drives[0]));
|
device_for_drive($drives[0]));
|
||||||
if (`$cmd` =~ /Temperature/) {
|
if (`$cmd` =~ /Temperature/) {
|
||||||
print "yes\n";
|
print "yes\n";
|
||||||
} else {
|
} else {
|
||||||
print "no (first drive not supported, configure the plugin)\n";
|
print "no (first drive not supported, configure the plugin)\n";
|
||||||
}
|
}
|
||||||
exit 0;
|
exit 0;
|
||||||
} else {
|
} else {
|
||||||
print "no (no drives known)\n";
|
print "no (no drives known)\n";
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print "no (smartctl not found)\n";
|
print "no (smartctl not found)\n";
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
} elsif ($ARGV[0] eq 'config') {
|
} elsif ($ARGV[0] eq 'config') {
|
||||||
print "graph_title HDD temperature\n";
|
print "graph_title HDD temperature\n";
|
||||||
print "graph_args --base 1000 -l 0\n";
|
print "graph_args --base 1000 -l 0\n";
|
||||||
print "graph_vlabel temp in °C\n";
|
print "graph_vlabel temp in ╟C\n";
|
||||||
print "graph_category sensors\n";
|
print "graph_category sensors\n";
|
||||||
print "graph_info This graph shows the temperature in degrees Celsius of the hard drives in the machine.\n";
|
print "graph_info This graph shows the temperature in degrees Celsius of the hard drives in the machine.\n";
|
||||||
print "$_.label $_\n" foreach @drives;
|
print "$_.label $_\n" foreach @drives;
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $drive (@drives) {
|
foreach my $drive (@drives) {
|
||||||
warn "[DEBUG] Processing $drive\n" if $DEBUG;
|
warn "[DEBUG] Processing $drive\n" if $DEBUG;
|
||||||
my $fulldev = device_for_drive($drive);
|
my $fulldev = device_for_drive($drive);
|
||||||
|
|
||||||
# Fall back to using hdparm for detecting disks in stand-by only if nocheck
|
# Fall back to using hdparm for detecting disks in stand-by only if nocheck
|
||||||
# isn't supported (hdparm isn't available on all platforms).
|
# isn't supported (hdparm isn't available on all platforms).
|
||||||
if (!$use_nocheck && $hdparm && $fulldev =~ /\/dev\/[sh]d?/) {
|
if (!$use_nocheck && $hdparm && $fulldev =~ /\/dev\/[sh]d?/) {
|
||||||
if (`$hdparm -C $fulldev 2>/dev/null` =~ /standby/) {
|
if (`$hdparm -C $fulldev 2>/dev/null` =~ /standby/) {
|
||||||
warn "[DEBUG] Drive $fulldev is in standby mode, not checking\n"
|
warn "[DEBUG] Drive $fulldev is in standby mode, not checking\n"
|
||||||
if $DEBUG;
|
if $DEBUG;
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $cmd = command_for_drive_device($drive, $fulldev, $use_nocheck);
|
my $cmd = command_for_drive_device($drive, $fulldev, $use_nocheck);
|
||||||
warn "[DEBUG] Command for $drive is % $cmd %\n" if $DEBUG;
|
warn "[DEBUG] Command for $drive is % $cmd %\n" if $DEBUG;
|
||||||
|
|
||||||
my $output = `$cmd`;
|
my $output = `$cmd`;
|
||||||
if ($? ne 0) {
|
if ($? ne 0) {
|
||||||
print "$drive.value U\n";
|
print "$drive.value U\n";
|
||||||
print "$drive.extinfo Command $cmd on drive $drive failed: $?. The plugin needs to have read permission on all monitored devices.\n";
|
print "$drive.extinfo Command $cmd on drive $drive failed: $?. The plugin needs to have read permission on all monitored devices.\n";
|
||||||
warn "[ERROR] Command $cmd on drive $drive failed: $?. The plugin needs to have read permission on all monitored devices.\n";
|
warn "[ERROR] Command $cmd on drive $drive failed: $?. The plugin needs to have read permission on all monitored devices.\n";
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
if ($output =~ /Current Drive Temperature:\s*(\d+)/) {
|
if ($output =~ /Current Drive Temperature:\s*(\d+)/) {
|
||||||
print "$drive.value $1\n";
|
print "$drive.value $1\n";
|
||||||
} elsif ($output =~ /^(194 Temperature_Celsius.*)/m) {
|
} elsif ($output =~ /^(194 Temperature_Celsius.*)/m) {
|
||||||
my @F = split /\s+/, $1;
|
my @F = split /\s+/, $1;
|
||||||
print "$drive.value $F[9]\n";
|
print "$drive.value $F[9]\n";
|
||||||
} elsif ($output =~ /^(231 Temperature_Celsius.*)/m) {
|
} elsif ($output =~ /^(231 Temperature_Celsius.*)/m) {
|
||||||
my @F = split ' ', $1;
|
my @F = split ' ', $1;
|
||||||
print "$drive.value $F[9]\n";
|
print "$drive.value $F[9]\n";
|
||||||
} else {
|
} elsif ($output =~ /^(190 Airflow_Temperature_Cel.*)/m) {
|
||||||
print "$drive.value U\n";
|
my @F = split ' ', $1;
|
||||||
print "$drive.extinfo Temperature not detected in smartctl output\n";
|
print "$drive.value $F[9]\n";
|
||||||
}
|
} else {
|
||||||
}
|
print "$drive.value U\n";
|
||||||
|
print "$drive.extinfo Temperature not detected in smartctl output\n";
|
||||||
|
}
|
||||||
sub device_for_drive {
|
}
|
||||||
my ($drive) = @_;
|
|
||||||
|
|
||||||
my $dev = $drive =~ /(.*)(?:_\d+)/ ? $1 : $drive;
|
sub device_for_drive {
|
||||||
|
my ($drive) = @_;
|
||||||
my $fulldev = '/dev/';
|
|
||||||
$fulldev .= 'rdsk/' if $^O eq 'solaris';
|
my $dev = $drive =~ /(.*)(?:_\d+)/ ? $1 : $drive;
|
||||||
$fulldev .= exists $ENV{'dev_'.$drive} ? $ENV{'dev_'.$drive} : $dev;
|
|
||||||
|
my $fulldev = '/dev/';
|
||||||
return $fulldev;
|
$fulldev .= 'rdsk/' if $^O eq 'solaris';
|
||||||
}
|
$fulldev .= exists $ENV{'dev_'.$drive} ? $ENV{'dev_'.$drive} : $dev;
|
||||||
|
|
||||||
sub command_for_drive_device {
|
return $fulldev;
|
||||||
my ($drive, $fulldev, $use_nocheck) = @_;
|
}
|
||||||
|
|
||||||
my $cmd = $smartctl.' -A ';
|
sub command_for_drive_device {
|
||||||
$cmd .= '--nocheck=standby ' if $use_nocheck;
|
my ($drive, $fulldev, $use_nocheck) = @_;
|
||||||
$cmd .= $ENV{'args_'.$drive}.' ' if exists $ENV{'args_'.$drive};
|
|
||||||
$cmd .= '-d '.$ENV{'type_'.$drive}.' ' if exists $ENV{'type_'.$drive};
|
my $cmd = $smartctl.' -A ';
|
||||||
$cmd .= $fulldev;
|
$cmd .= '--nocheck=standby ' if $use_nocheck;
|
||||||
|
$cmd .= $ENV{'args_'.$drive}.' ' if exists $ENV{'args_'.$drive};
|
||||||
}
|
$cmd .= '-d '.$ENV{'type_'.$drive}.' ' if exists $ENV{'type_'.$drive};
|
||||||
|
$cmd .= $fulldev;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue