Files
webgui/emhttp/plugins/dynamix/scripts/statuscheck
ljm42 a7b1a6c12f Fix Docker notifications
and improve consistency in related files
2024-03-14 14:12:30 -07:00

187 lines
7.9 KiB
PHP
Executable File

#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Wrappers.php";
$var = (array)@parse_ini_file("/var/local/emhttp/var.ini");
$disks = (array)@parse_ini_file("/var/local/emhttp/disks.ini",true);
require_once "$docroot/webGui/include/CustomMerge.php";
$script = "$docroot/webGui/scripts/notify";
// this command will set the $notify array
extract(parse_plugin_cfg("dynamix",true));
$output = _var($notify,'report');
$server = strtoupper(_var($var,'NAME','tower'));
$data = [];
$parity = $pools = false;
$error0 = $error1 = $error2 = $error3 = 0;
function plus($val, $word, $last) {
return $val>0 ? (($val || $last) ? ($val.' '.$word.($val!=1?'s':'').($last ?'':', ')) : '') : '';
}
function my_temp($value) {
global $display;
if ($value=='*') return ' - standby';
$unit = _var($display,'unit','C');
return ' - active '.($unit=='F' ? fahrenheit($value) : str_replace('.',_var($display,'number','.,')[0], $value)).' '.$unit;
}
function my_disk($name) {
return ucfirst(preg_replace('/(\d+)$/',' $1',$name));
}
function my_scale($value, &$unit, $precision = NULL) {
global $display;
$scale = _var($display,'scale',-1);
$number = _var($display,'number','.,');
$units = ['B','KB','MB','GB','TB','PB'];
if ($scale==0 && $precision===NULL) {
$unit = '';
return number_format($value, 0, $number[0], ($value>=10000 ? $number[1] : ''));
} else {
$base = $value ? floor(log($value, 1000)) : 0;
if ($scale>0 && $base>$scale) $base = $scale;
$value = round($value/pow(1000, $base), $precision===NULL ? 2 : $precision);
if ($value>=1000 && $scale<0) { $value = 1; $base++; }
$unit = $units[$base];
return number_format($value, $precision===NULL ? (($value-intval($value)==0 || $value>=100) ? 0 : ($value>=10 ? 1 : 2)) : $precision, $number[0], ($value>=10000 ? $number[1] : ''));
}
}
function my_check($time,$speed) {
if (!$time) return 'unavailable (no parity-check entries logged)';
$days = floor($time/86400);
$hmss = $time-$days*86400;
$hour = floor($hmss/3600);
$mins = floor($hmss/60)%60;
$secs = $hmss%60;
return plus($days,'day',($hour|$mins|$secs)==0).plus($hour,'hour',($mins|$secs)==0).plus($mins,'minute',$secs==0).plus($secs,'second',true).". Average speed: $speed";
}
function my_time($time) {
global $display;
$date = my_date(_var($display,'date').(_var($display,'date')!='%c' ? ", "._var($display,'time') : ""), $time);
$now = new DateTime("@".intval(time()/86400)*86400);
$last = new DateTime("@".intval($time/86400)*86400);
$days = date_diff($last,$now)->format('%a');
switch (true) {
case ($days<0):
return $date;
case ($days==0):
return "$date (today)";
case ($days==1):
return "$date (yesterday)";
default:
return "$date ($days days ago)";
}
}
function my_clock($time) {
if (!$time) return 'less than a minute';
$days = floor($time/1440);
$hour = floor($time/60)%24;
$mins = $time%60;
return plus($days,'day',($hour|$mins)==0).plus($hour,'hour',$mins==0).plus($mins,'minute',true);
}
function my_array(&$disk) {
global $data,$display,$error0,$error1,$error2,$error3;
$name = _var($disk,'name');
[$hotNVME,$maxNVME] = _var($disk,'transport')=='nvme' ? get_nvme_info(_var($disk,'device'),'temp') : [-1,-1];
$hot = _var($disk,'hotTemp',-1)>=0 ? $disk['hotTemp'] : ($hotNVME>=0 ? $hotNVME : (_var($disk,'rotational',1)==0 && $display['hotssd']>=0 ? $display['hotssd'] : $display['hot']));
$max = _var($disk,'maxTemp',-1)>=0 ? $disk['maxTemp'] : ($maxNVME>=0 ? $maxNVME : (_var($disk,'rotational',1)==0 && $display['maxssd']>=0 ? $display['maxssd'] : $display['max']));
if (strpos(_var($disk,'status'),'_NP')!==false) return false;
$temp = _var($disk,'temp');
if ($max>0 && $temp>=$max) {
$fail = ' (disk is overheated';
$error0++;
} elseif ($hot>0 && $temp>=$hot) {
$fail = ' (disk is hot';
$error1++;
} else {
$fail = '';
}
if (_var($disk,'numErrors',0)>0) {
if ($fail) $fail .= ', '; else $fail = ' (';
$fail .= 'disk has read errors';
$error2++;
}
if ($fail) $fail .= ')';
$status = $fail ? ' [NOK]' : ' [OK]';
$color = strtok(_var($disk,'color'),'-');
if ($color=='red'||$color=='yellow') {$error3++; $status = ' ['.str_replace(['NP_','_'],['',' '],_var($disk,'status')).']';}
$info = _var($disk,'id')." ("._var($disk,'device').")";
if ($info==" ()") $info = 'No device identification present';
$data[] = my_disk($name)." - $info".my_temp($temp).$fail.$status;
return true;
}
// generate report of array devices
foreach ($disks as $disk) if (_var($disk,'type')=='Parity') $parity |= my_array($disk);
foreach ($disks as $disk) if (_var($disk,'type')=='Data') my_array($disk);
foreach ($disks as $disk) if (_var($disk,'type')=='Cache') $pools |= my_array($disk);
$size = count($data);
// generate parity report
$data[] = '';
$mdResync = _var($var,'mdResync',0);
$action = preg_split('/\s+/',_var($var,'mdResyncAction'));
if ($mdResync>0) {
$mdResyncPos = _var($var,'mdResyncPos',0);
$mdResyncDb = _var($var,'mdResyncDb',0);
$mdResyncDt = _var($var,'mdResyncDt',0);
switch ($action[0]) {
case "recon": $mode = $action[1]=='P' ? 'Parity-Sync' : 'Data-Rebuild'; break;
case "check": $mode = count($action)>1 ? 'Parity-Check' : 'Read-Check'; break;
case "clear": $mode = 'Disk-Clear'; break;
default : $mode = 'Unknown'; break;
}
$data[] = $mode." in progress.";
$data[] = "Total size: ".my_scale($mdResync*1024, $unit)." $unit";
$data[] = "Elapsed time: ".my_clock(floor((time()-_var($var,'sbUpdated',0))/60));
$data[] = "Current position: ".my_scale($mdResyncPos*1024, $unit)." $unit (".number_format(($mdResyncPos/($mdResync/100+1)),1,$unraid['display']['number'][0],'')." %)";
$data[] = "Estimated speed: ".my_scale($mdResyncDb/$mdResyncDt*1024, $unit, 1)." $unit/sec";
$data[] = "Estimated finish: ".my_clock(round(((($mdResyncDt*(($mdResync-$mdResyncPos)/($mdResyncDb/100+1)))/100)/60),0));
$data[] = "Sync errors ".(_var($var,'mdResyncCorr',0)==0 ? 'detected: ' : 'corrected: ')._var($var,'sbSyncErrs',0);
} else {
$sbSynced = _var($var,'sbSynced',0);
$sbSynced2 = _var($var,'sbSynced2',0);
$sbSyncErrs = _var($var,'sbSyncErrs',0);
if (_var($var,'sbSyncExit',0)!=0) {
$data[] = "Last check incomplete on ".my_time($sbSynced2).", finding $sbSyncErrs error".($sbSyncErrs==1?'.':'s.');
$data[] = "Error code: ".$var['sbSyncExit'];
} elseif ($sbSynced==0) {
$data[] = "Parity has not been checked yet";
} elseif ($sbSynced2>0) {
if ($action[0]=='recon') {
$data[] = $action[1]=='P' ? 'Parity is invalid' : 'Data-Rebuild is invalid';
} else {
$data[] = 'Parity is valid';
}
$duration = Max($sbSynced2-$sbSynced,1);
$speed = my_scale(_var($var,'mdResyncSize',0)*1024/$duration,$unit,1)." $unit/s";
$data[] = "Last checked on ".my_time($sbSynced2).", finding $sbSyncErrs error".($sbSyncErrs==1?'.':'s.');
$data[] = "Duration: ".my_check($duration,$speed);
}
}
$word = $size==1 ? "" : "including ";
$warn = ($error0 || $error3) ? "alert" : (($error1 || $error2) ? "warning" : "normal");
$stat = $warn=="normal" ? "[PASS]" : "[FAIL]";
$info = "Array has $size disk".($size==1 ? "" : "s").($parity ? " ({$word}parity".($pools ? " & pools)" : ")") : ($pools ? " ({$word}pools)" : ""));
$message = implode('\n', $data);
$subject = "Notice [$server] - array health report $stat";
exec("$script -s ".escapeshellarg($subject)." -d ".escapeshellarg("$info")." -m ".escapeshellarg("$message")." -i ".escapeshellarg("$warn $output")." -l '/Main'");
exit(0);
?>