From 544fa567fd16c497823fd2ad6f3a3497525cc90b Mon Sep 17 00:00:00 2001 From: michael Date: Wed, 14 Jun 2023 12:56:19 -0400 Subject: [PATCH] Added NAS disk scripts --- perl/disk-temps.pl | 78 +++++++++++++++++++++++++++++++++++++++++++ perl/tempmon.pl | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 perl/disk-temps.pl create mode 100644 perl/tempmon.pl diff --git a/perl/disk-temps.pl b/perl/disk-temps.pl new file mode 100644 index 0000000..3a4a759 --- /dev/null +++ b/perl/disk-temps.pl @@ -0,0 +1,78 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Term::ANSIColor; + +my %temp = ('warn' => 38, 'bad' => 42); +my %color = ('good' => 'green', 'warn' => 'yellow', 'bad' => 'red'); +my $devdir='/dev'; +my $smartctl='/usr/sbin/smartctl'; +my $infinity=clean(`/usr/bin/echo \xE2\x88\x9E`); +my @udisks = (); +my @disks = (); + +# Needs to be manually updated +my %disklocs = ('HKT01QJ2'=>'Bay 2 Slot 1', + 'HKT01QJP'=>'Bay 2 Slot 2', + 'S2TVNX0K402024'=>'Bay 2 Slot 3', + 'S2TVNX0K400456'=>'Bay 2 Slot 4', + 'S2TVNX0K402163'=>'Bay 2 Slot 5', + 'S2TVNX0K301389'=>'Bay 2 Slot 6', + 'ZR53ZB2F'=>'Bay 1 Slot 1', + '3GJY8UKG'=>'Bay 1 Slot 2', + 'ZR58XJCF'=>'Bay 1 Slot 3', + '3FGBP6VV'=>'Bay 1 Slot 4', + 'ZR58LSCD'=>'Bay 1 Slot 5'); + +opendir my($DH), $devdir or die $!; +my @devicelist=readdir $DH; +closedir $DH; + +for(@devicelist) { + my $device =$_; + # Directory listing includes . and .. but these aren't disks! + if ($device eq "." or $device eq "..") {next;} + # We don't' care about partitions + if ($device =~ /sd[a-z][0-9]/) {next;} + if ($device =~ /sd[a-z]/) { + push(@udisks,$device); + } +} + +@disks=sort(@udisks); + +printf("\n%-9s %-13s %-6s %-15s %-5s %-5s %-10s %-10s\n","Disk","Runtime","Pwr On","Serial","Temp","Max","Speed","Location"); +printf("%-18s\n","---------+------------+------+---------------+-----+-----+----------+----------"); + +# https://stackoverflow.com/a/5047362 +sub clean {my $text = shift; $text=~s/\n//g; $text=~s/\r//g;return $text;} + +for (@disks) { + my %diskdata=("disk_name"=>"/dev/$_"); + # https://www.unix.com/shell-programming-and-scripting/133687-perl-looping-through-output-system-command.html + open my $cmd, '-|', "$smartctl -x $diskdata{'disk_name'}"; + while (my $line = <$cmd>) { + # EX: Page Offset Size Value Flags Description + # 0x01 0x010 4 37496 --- Power-on Hours + # x2 \s+ \d+ \s+ (\d+) [\s\-a-zA-Z0-9]+ + if ($line =~ /0x05\s+0x008\s+\d+\s+(\d+)/) {$diskdata{"current_temp"}=int($1);} + elsif ($line =~ /0x05\s+0x058\s+\d+\s+(\d+)/) {$diskdata{"maximum_temp"}=int($1);} + elsif ($line =~ /0x01\s+0x010\s+\d+\s+(\d+)/) {$diskdata{"power_hours"}=int($1);} + elsif ($line =~ /0x01\s+0x008\s+\d+\s+(\d+)/) {$diskdata{"power_cycles"}=int($1);} + #elsif ($line =~ /0x05\s+0x058\s+\d+\s+(\d+)/) {$diskdata{"maximum_temp"}=int($1);} + elsif ($line =~ /Serial Number:\s+([a-zA-Z0-9]+)/) {$diskdata{"serial"}="$1";} + elsif ($line =~ /Rotation Rate:\s+(Solid State Device|\d+\s*rpm)/) { + if ($line =~ /.*:\s+(\d+\s+rpm)/) {$diskdata{"rotation_rate"}="$1";} + else {$diskdata{"rotation_rate"}="SSD";} + #else {$diskdata{"rotation_rate"}="$infinity rpm ";} # Unicode is a pain in the butt to align + } + } + close $cmd; + my $cstr=""; + if ($diskdata{"current_temp"} > $temp{"bad"}) {$cstr=colored($diskdata{"current_temp"}, $color{"bad"});} + elsif($diskdata{"current_temp"} > $temp{"warn"}) {$cstr=colored($diskdata{"current_temp"}, $color{"warn"});} + else {$cstr=colored($diskdata{"current_temp"}, $color{"good"});} + # |---- padded due to color being interpreted as printable characters + # dev ser tmp V max rot loc + printf("%-9s %-13s %-6s %-15s %-5s %-5s %-10s %-10s\n","$diskdata{'disk_name'}","$diskdata{power_hours} hours","$diskdata{power_cycles}","$diskdata{serial}",clean($cstr),clean("$diskdata{'maximum_temp'}"),clean("$diskdata{'rotation_rate'}"), "$disklocs{$diskdata{serial}}"); +} diff --git a/perl/tempmon.pl b/perl/tempmon.pl new file mode 100644 index 0000000..248b549 --- /dev/null +++ b/perl/tempmon.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Term::ANSIColor; +use Getopt::Long; +use Time::localtime; + +my %temp = ('warn' => 38, 'bad' => 42); +my %color = ('good' => 'green', 'warn' => 'yellow', 'bad' => 'red'); +my $devdir='/dev'; +my $smartctl='/usr/sbin/smartctl'; +my @udisks = (); +my @disks = (); +my %rotobois=(); +my $CLEAR_LINE=`tput cub 40;tput el`; + + +# https://stackoverflow.com/a/5047362 +sub clean {my $text = shift; $text=~s/\n//g; $text=~s/\r//g;return $text;} +sub ptime {my $min = localtime->min < 10 ? "0".localtime->min : localtime->min; + my $hr = localtime->hour < 10 ? "0".localtime->hour : localtime->hour; + return "$hr:$min";} +# https://www.perl.com/article/37/2013/8/18/Catch-and-Handle-Signals-in-Perl/ +$SIG{INT} = sub {printf("%s",$CLEAR_LINE);printf("\n%s\n\n",clean(colored("Caught ctrl+c - exiting",'red')));exit 0;}; + +opendir my($DH), $devdir or die $!; +my @devicelist=readdir $DH; +closedir $DH; + +for(@devicelist) { + my $device =$_; + # Directory listing includes . and .. but these aren't disks! + if ($device eq "." or $device eq "..") {next;} + # We don't' care about partitions + if ($device =~ /sd[a-z][0-9]/) {next;} + if ($device =~ /sd[a-z]/) { + push(@udisks,$device); + } +} + +@disks=sort(@udisks); +GetOptions("interval|i=i" => \( my $INTERVAL=300 ),"header|h=i" => \( my $HEADER_REPEAT = 24 ),) or die "command line arguments error"; +#my $INTERVAL=300; +#my $HEADER_REPEAT=24; +printf("\n%s\n","Running script forever, press ctrl+c to exit.\nScript args:"); +printf("%s\n%s\n\n","- Interval: $INTERVAL seconds","- Re-Header: $HEADER_REPEAT rows"); + +sub diskheader { + my $rotoinv=keys %rotobois; if ($rotoinv > 0) { + printf("%-10s", "24hr"); for (@disks) {printf("%-5s",$rotobois{"/dev/$_"});} printf("\n");} + printf("%-10s", "Time"); for (@disks) {printf("%-5s",$_);} printf("\n"); +} +sub headerlines {printf("%-10s", "---------+"); for (@disks) {printf("%-5s","----+");} printf("\n");} +diskheader(); +headerlines(); +my $headertracker=0; +while (1) { + printf("%s",$CLEAR_LINE); + if ($headertracker >= $HEADER_REPEAT) {$headertracker=0;headerlines();diskheader();headerlines();} + printf("%5s%5s",ptime(),""); + for (@disks) { + my $diskname="/dev/$_"; + open my $cmd, '-|', "$smartctl -x $diskname"; + while (my $line = <$cmd>) { + if ($line =~ /0x05\s+0x008\s+\d+\s+(\d+)/) { + my $disktemp=int($1); + if ($disktemp > $temp{"bad"}) {printf(" %-5s ",clean(colored($disktemp, $color{"bad"})));} + elsif($disktemp > $temp{"warn"}) {printf(" %-5s ",clean(colored($disktemp, $color{"warn"})));} + else {printf(" %-5s ",clean(colored($disktemp, $color{"good"})));} + } + elsif ($line =~ /Rotation Rate:\s+(Solid State Device|\d+\s*rpm)/) { + if ($line =~ /.*:\s+(\d+)\s+rpm/) {$rotobois{"$diskname"}="$1";} + else {$rotobois{"$diskname"}="SSD";} + } + } + close $cmd; + } + printf("\n"); + printf("%s","Sleeping for $INTERVAL seconds..."); + $headertracker=$headertracker+1; + select()->flush(); # Heccin buffered I/O gets caulk blocked by the sleep. This forces a flush to STDIO + sleep($INTERVAL); +}