Merge pull request #226 from VVelox/smart-update

SMART monitoring update adding RAID support
This commit is contained in:
VVelox
2019-03-24 03:56:16 -05:00
committed by GitHub
+99 -82
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env perl
#Copyright (c) 2017, Zane C. Bowers-Hadley
#Copyright (c) 2019, Zane C. Bowers-Hadley
#All rights reserved.
#
#Redistribution and use in source and binary forms, with or without modification,
@@ -38,14 +38,17 @@ will be /etc/snmp/smart.config. Alternatively you can also specific a config via
Anything starting with a # is comment. The format for variables is $variable=$value. Empty
lines are ignored. Spaces and tabes at either the start or end of a line are ignored. Any
line with out a = or # are treated as a disk.
line with out a matched variable or # are treated as a disk.
#This is a comment
cache=/var/cache/smart
smartctl=/usr/local/sbin/smartctl
useSN=0
ada0
ada1
da5 /dev/da5 -d sat
twl0,0 /dev/twl0 -d 3ware,0
twl0,1 /dev/twl0 -d 3ware,1
twl0,2 /dev/twl0 -d 3ware,2
The variables are as below.
@@ -54,8 +57,13 @@ The variables are as below.
useSN = If set to 1, it will use the disks SN for reporting instead of the device name.
1 is the default. 0 will use the device name.
A disk line is can be as simple as just a disk name under /dev/. Such as in the config above
The line "ada0" would resolve to "/dev/ada0" and would be called with no special argument. If
a line has a space in it, everything before the space is treated as the disk name and is what
used for reporting and everything after that is used as the argument to be passed to smartctl.
If you want to guess at the configuration, call it with -g and it will print out what it thinks
it should be.
it should be.
=cut
@@ -73,10 +81,9 @@ my $useSN=1;
$Getopt::Std::STANDARD_HELP_VERSION = 1;
sub main::VERSION_MESSAGE {
print "SMART SNMP extend 0.0.0\n";
print "SMART SNMP extend 0.1.0\n";
};
sub main::HELP_MESSAGE {
print "\n".
"-u Update '".$cache."'\n".
@@ -108,75 +115,70 @@ if ( defined( $opts{g} ) ){
$cache='cache='.$cache."\n";
}
my %found_disks;
#check for drives named /dev/sd*
my @matches=glob('/dev/sd*');
@matches=grep(!/[0-9]/, @matches);
my $matches_int=0;
while ( defined( $matches[$matches_int] ) ){
my $device=$matches[$matches_int];
system( $smartctl.' -A '.$device.' > /dev/null' );
if ( $? == 0 ){
$device =~ s/\/dev\///;
$found_disks{$device}=1;
}
$matches_int++;
}
#check for drives named /dev/ada*
@matches=glob('/dev/ada*');
@matches=grep(!/[ps]/, @matches);
$matches_int=0;
while ( defined( $matches[$matches_int] ) ){
my $device=$matches[$matches_int];
system( $smartctl.' -A '.$device.' > /dev/null' );
if ( $? == 0 ){
$device =~ s/\/dev\///;
$found_disks{$device}=1;
}
$matches_int++;
}
#check for drives named /dev/da*
@matches=glob('/dev/da*');
@matches=grep(!/[ps]/, @matches);
$matches_int=0;
while ( defined( $matches[$matches_int] ) ){
my $device=$matches[$matches_int];
system( $smartctl.' -A '.$device.' > /dev/null' );
if ( $? == 0 ){
$device =~ s/\/dev\///;
$found_disks{$device}=1;
}
$matches_int++;
}
# used for checking if a disk has been found more than once
my %found_disks_names;
my @argumentsA;
#have smartctl scan and see if it finds anythings not get found
my $scan_output=`$smartctl --scan-open`;
my @scan_outputA=split(/\n/, $scan_output);
# remove non-SMART devices sometimes returned
@scan_outputA=grep(!/ses[0-9]/, @scan_outputA); # not a disk, but may or may not have SMART attributes
@scan_outputA=grep(!/pass[0-9]/, @scan_outputA); # very likely a duplicate and a disk under another name
$matches_int=0;
while ( defined( $scan_outputA[$matches_int] ) ){
my $device=$scan_outputA[$matches_int];
$device =~ s/ .*//;
system( $smartctl.' -A '.$device.' > /dev/null' );
if ( $? == 0 ){
$device =~ s/\/dev\///;
$found_disks{$device}=1;
}
$matches_int++;
@scan_outputA=grep(!/cd[0-9]/, @scan_outputA); # CD drive
if ( $^O eq 'freebsd' ){
@scan_outputA=grep(!/sa[0-9]/, @scan_outputA); # tape drive
@scan_outputA=grep(!/ctl[0-9]/, @scan_outputA); # CAM target layer
}elsif( $^O eq 'linux' ){
@scan_outputA=grep(!/st[0-9]/, @scan_outputA); # SCSI tape drive
@scan_outputA=grep(!/ht[0-9]/, @scan_outputA); # ATA tape drive
}
# make the first pass, figuring out what all we have and trimming comments
foreach my $arguments ( @scan_outputA ){
my $name = $arguments;
$arguments =~ s/ \#.*//; # trim the comment out of the argument
$name =~ s/ .*//;
$name =~ s/\/dev\///;
if (defined( $found_disks_names{$name} )){
$found_disks_names{$name}++;
}else{
$found_disks_names{$name}=0;
}
push( @argumentsA, $arguments );
}
# second pass, putting the lines together
my %current_disk;
my $drive_lines='';
foreach my $arguments ( @argumentsA ){
my $name = $arguments;
$name =~ s/ .*//;
$name =~ s/\/dev\///;
if ( $found_disks_names{$name} == 0 ){
# If no other devices, just name it after the base device.
$drive_lines=$drive_lines.$name." ".$arguments."\n";
}else{
# if more than one, start at zero and increment, apennding comma number to the base device name
if (defined( $current_disk{$name} )){
$current_disk{$name}++;
}else{
$current_disk{$name}=0;
}
$drive_lines=$drive_lines.$name.",".$current_disk{$name}." ".$arguments."\n";
}
}
print "useSN=0\n".'smartctl='.$smartctl."\n".
$cache.
join( "\n", keys(%found_disks) )."\n";
$cache.
$drive_lines;
exit 0;
}
@@ -200,27 +202,32 @@ my @configA=split(/\n/, $config_file);
my $configA_int=0;
while ( defined( $configA[$configA_int] ) ){
my $line=$configA[$configA_int];
chomp($line);
$line=~s/^[\t\s]+//;
$line=~s/[\t\s]+$//;
my ( $var, $val )=split(/=/, $line, 2);
my $matched;
if ( $var eq 'cache' ){
$cache=$val;
$matched=1;
}
if ( $var eq 'smartctl' ){
$smartctl=$val;
$matched=1;
}
if ( $var eq 'useSN' ){
$useSN=$val;
$matched=1;
}
if ( !defined( $val ) ){
push(@disks, $var);
push(@disks, $line);
}
$configA_int++;
}
@@ -244,11 +251,22 @@ if ( ! defined( $opts{u} ) ){
}
my $toReturn='';
my $int=0;
while ( defined($disks[$int]) ) {
my $disk=$disks[$int];
foreach my $line ( @disks ){
my $disk;
my $name;
if ( $line =~ /\ / ){
($name, $disk)=split(/\ /, $line, 2);
}else{
$disk=$line;
$name=$line;
}
my $disk_sn=$disk;
my $output=`$smartctl -A /dev/$disk`;
my $output;
if ( $disk =~ /\// ){
$output=`$smartctl -A $disk`;
}else{
$output=`$smartctl -A /dev/$disk`;
}
my %IDs=( '5'=>'null',
'10'=>'null',
@@ -267,7 +285,7 @@ while ( defined($disks[$int]) ) {
'231'=>'null',
'233'=>'null',
);
my @outputA=split( /\n/, $output );
my $outputAint=0;
while ( defined($outputA[$outputAint]) ) {
@@ -281,7 +299,7 @@ while ( defined($disks[$int]) ) {
my $id=$lineA[0];
# single int raw values
if (
if (
( $id == 5 ) ||
( $id == 10 ) ||
( $id == 173 ) ||
@@ -319,8 +337,8 @@ while ( defined($disks[$int]) ) {
) {
my ( $temp )=split(/\ /, $raw);
$IDs{$id}=$temp;
}
}
}
$outputAint++;
@@ -337,9 +355,9 @@ while ( defined($disks[$int]) ) {
my $short=scalar grep(/Short/, @outputA);
my $conveyance=scalar grep(/Conveyance/, @outputA);
my $selective=scalar grep(/Selective/, @outputA);
# get the drive serial number, if needed
my $disk_id=$disk;
my $disk_id=$name;
if ( $useSN ){
while (`$smartctl -i /dev/$disk` =~ /Serial Number:(.*)/g) {
$disk_id = $1;
@@ -351,7 +369,6 @@ while ( defined($disks[$int]) ) {
.','.$IDs{'190'} .','.$IDs{'194'}.','.$IDs{'196'}.','.$IDs{'197'}.','.$IDs{'198'}.','.$IDs{'199'}.','.$IDs{'231'}.','.$IDs{'233'}.','.
$completed.','.$interrupted.','.$read_failure.','.$unknown_failure.','.$extended.','.$short.','.$conveyance.','.$selective."\n";
$int++;
}
if ( ! $noWrite ){