diff --git a/lib/Site/ZFSSnapshot.pm b/lib/Site/ZFSSnapshot.pm new file mode 100644 index 0000000000000000000000000000000000000000..ff77bea50d06354e2c05451c3c48016943d76c3e --- /dev/null +++ b/lib/Site/ZFSSnapshot.pm @@ -0,0 +1,80 @@ +package Site::ZFSSnapshot; + +use strict; +use warnings; + +use base 'Resmon::Module'; + +use Resmon::ExtComm qw(run_command); + +=pod + +=head1 NAME + +Site::ZFSSNapshot - check existing of fresh zfs snapshot + +=head1 SYNOPSIS + + Site::ZFSSNapshot { + <zfsdataset>: noop + } + +=head1 DESCRIPTION + +This module gives time since last snapshot created for the given zfs dataset + +=head1 CONFIGURATION + +=over + +=item check_name + +The check name is the name of zfs dataset, which snapshots are checked + +=back + +=head1 METRICS + +=over + +=item <age> + +time in seconds since last snapshot was taken + +=item <line> + +line of zfs list output, which script tried to parse + +=back + +=cut +my $DATE='/usr/gnu/bin/date'; +if (! -x $DATE){$DATE='/usr/bin/date'}; +sub handler { + my $self = shift; + my $config = $self->{config}; # All configuration is in here + my $zfs = $self->{check_name}; + my ($when,$age) = (0,`date '+%s'`); + chomp $age; $age -= $when; + my $line = ''; + my $LIST = "/usr/sbin/zfs list -H -p -o creation -S creation -d 1 -t snapshot $zfs 2>&1"; + open (my $list, "-|", $LIST)or die "can't run $LIST: $!"; + while (<$list>) { +=pod +1469459040 +=cut + chomp; + $line = $_ if $_; + if (/^(\d+)$/){ + $when = $1; + $age = `$DATE '+%s'` - $when; + last; + } + } + return { + "age" => [$age, "i"], + "line" => [$line, "s"] + } +} + +1; diff --git a/lib/Site/ZpoolScrub.pm b/lib/Site/ZpoolScrub.pm new file mode 100644 index 0000000000000000000000000000000000000000..1d1d75a7122ce0ae5f9b6b327ddc13d03d381f98 --- /dev/null +++ b/lib/Site/ZpoolScrub.pm @@ -0,0 +1,155 @@ +package Site::ZpoolScrub; + +use strict; +use warnings; + +use base 'Resmon::Module'; + +use Resmon::ExtComm qw(run_command); + +=pod + +=head1 NAME + +Site::ZpoolScrub - return scrub statistics + +=head1 SYNOPSIS + + Site::ZpoolScrub { + <zpoolname>: noop + } + +or + Site::ZpoolScrub { + <spoolname>: <scrub_times_hash_file> +} + +=head1 DESCRIPTION + +This module gives statistics of scrupb of zpool + +=head1 CONFIGURATION + +=over + +=item check_name + +The check name is the name of zpool for which statistics of scrub is checked. + +=item scrub_times_hash_file + +The full path of file to store time which last successful scrub command took. +Defaults to "/var/run/.resmon-status-${zpoolname}.howlong" + +=back + +=head1 METRICS + +=over + +=item <when> + +When last scrub ran + +=item <togo> + +Expected time to finish for current scrub + +=item <howlong> + +how long last scrub ran + +=item <repaired> + +how many errors last scrub repaired + +=item <errors> + +how many errors last scrub failed to repair + +=item <canceled> + +is '1' if last scrub was canceled and '0' if not + +=back + +=cut +my $DATE='/usr/gnu/bin/date'; +if (! -x $DATE){$DATE='/usr/bin/date'}; +my $ECHO='/usr/gnu/bin/echo'; +if (! -x $ECHO){$ECHO='/usr/bin/echo'}; +sub handler { + my $self = shift; + my $config = $self->{config}; # All configuration is in here + my $zpool = $self->{check_name}; + my $statusfile = $config->{scrub_times_hash_file} || "/var/run/.resmon-status-${zpool}.howlong"; + my $oldhowlong = ( ( -r $statusfile ) ? `cat $statusfile` : 0 ); + chomp $oldhowlong; + $oldhowlong = 0 unless $oldhowlong =~ /^[\d]+$/; +=pod + scan: scrub repaired 0 in 78h6m with 0 errors on Tue Mar 29 00:16:48 2016 + - or - + scan: scrub repaired 0B in 0 days 09:55:51 with 0 errors on Thu Mar 7 01:46:05 2019 + - or - + scan: scrub in progress since Tue Mar 29 19:09:47 2016 + 14.3G scanned out of 47.0G at 172M/s, 0h3m to go + 0 repaired, 30.42% done +=cut + my ($when,$days,$h,$m,$s,$howlong,$togo,$repaired,$errors,$canceled)=(0,0,0,0,0,0,0,0); + my $STATUSCMD = "/usr/sbin/zpool status $zpool"; + open (my $status, "-|", $STATUSCMD)or die "can't run $STATUSCMD: $!"; + while (<$status>) { + if (/^\s*scan:\s+scrub\s+canceled\s+on\s+(.+)$/){ + $when = $1; + $when = `$DATE '+%s'` - `$DATE '+%s' -d "$when"`; + $when = int(($when+30)/60); + $canceled = 1; + $howlong = $oldhowlong; + $togo = 0; + $repaired = 0; + $errors = 0; + $canceled = 1; + } + elsif (/^\s*scan:\s+scrub\s+repaired\s+(\d*)\D*\s+in\s+(\d*)\s+days\s+(\d*):(\d*):(\d*)\s+with\s+(\d*)\s+errors\s+on\s+(.+)$/){ + ($repaired,$days,$h,$m,$s,$errors,$when) = ($1,$2,$3,$4,$5,$6,$7); + $when = `$DATE '+%s'` - `$DATE '+%s' -d "$when"`; + $howlong = $m+60*($h+24*$days); + $when += 60*$howlong; + $repaired += $errors if $repaired < $errors; + } + elsif (/^\s*scan:\s+scrub\s+repaired\s+(\d*)\s+in\s+(\d*)h(\d*)m\s+with\s+(\d*)\s+errors\s+on\s+(.+)$/){ + ($repaired,$h,$m,$errors,$when) = ($1,$2,$3,$4,$5); + $when = `$DATE '+%s'` - `$DATE '+%s' -d "$when"`; + $howlong = 60*$h+$m; + $when += 60*$howlong; + $when = int(($when+30)/60); + $repaired += $errors if $repaired < $errors; + $togo = 0; + `$ECHO -n $howlong > $statusfile` unless $howlong == $oldhowlong && (-w $statusfile); + } + elsif (/^\s*scan:\s+scrub\s+in\s+progress\s+since\s+(.+)$/){ + $when = $1; + $when = `$DATE '+%s'` - `$DATE '+%s' -d "$when"`; + $when += 30; + $when /= 60; + $when = int($when); + } + elsif (/^\s*\S+\s+scanned\s+out\s+of\s+\S+\s+at\s+\S+,\s+(\d+)h(\d+)m\s+to\s+go\s*$/){ + $togo = $1*60 +$2; + $howlong = $oldhowlong; + } + elsif (/^\s*(\d+)\s+repaired,/){ + $repaired = $1; + } + } + return { + "when" => [$when, "i"], + "howlong" => [$howlong, "i"], + "togo" => [$togo, "i"], + "repaired" => [$repaired, "i"], + "errors" => [$errors, "i"], + "canceled" => [$canceled, "i"], + } +} + +1;