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
 - or -
  scan: resilver in progress since Fri Aug  7 14:07:30 2020
	451G scanned at 2.17G/s, 2.13M issued at 10.5K/s, 19.6T total
	0B resilvered, 0.00% done, no estimated completion time
 - or -
  scan: resilver in progress since Fri Aug  7 14:07:30 2020
	855G scanned at 188M/s, 227G issued at 49.9M/s, 19.6T total
	228G resilvered, 1.13% done, 4 days 17:00:28 to go

=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+(.+)$/) or 
              (/^\s*scan:\s+resilver\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+(\d+)h(\d+)m\s+to\s+go\s*$/) or
              (/^\s*\S+\s+resilvered.*,\s+(\d+)h(\d+)m\s+to\s+go\s*$/)
            ){
        $togo = $1*60 +$2;
        $howlong = $oldhowlong;
      }
      elsif ( (/^\s*\S+\s+scanned.*,\s+(\d+)\s+days\s+(\d+):(\d+):(\d+)\s+to\s+go\s*$/) or
              (/^\s*\S+\s+resilvered.*,\s+(\d+)\s+days\s+(\d+):(\d+):(\d+)\s+to\s+go\s*$/)
            ){
        $togo = ($1*24 + $2)*60 +$3;
        $howlong = $oldhowlong;
      }
      elsif ( (/^\s*(\d+)\s+repaired,/) or
              (/^\s*(\d+)\s+resilvered,/)
            ){
        $repaired = $1;
      }
    }
    return {
      "when"       => [$when, "i"],
      "howlong"    => [$howlong,  "i"],
      "togo"       => [$togo, "i"],
      "repaired"   => [$repaired,  "i"],
      "errors"     => [$errors,  "i"],
      "canceled"   => [$canceled,  "i"],
    }
}

1;