Следим за состоянием жёстких дисков с помощью smartctl и php

Жёсткие диски – это ничто иное, как расходник. По крайней мере, это безусловно так, когда ты имеешь дело с большими дисковыми массивами, да ещё и работающими под большой нагрузкой. В моём случае – это корзины без аппаратного RAID контроллера. И потому, я хочу рассказать о своей реализации простенького мониторинга “здоровья” дисков, которая помогает мне не упустить момент, когда будет необходимо заменить “уставший” элемент массива, до того, как начнёт разваливаться всё остальное. (а такое, кстати, у меня уже бывало).

Иногда мне совершенно лень искать готовые решения, когда нужно сделать что-то простое и понятное. В этом случае мне проще набросать своё. Во всяком случае, тогда я точно буду знать, кто виноват в том, что ничего не работает. ;))

Задача: сделать простую страничку с понятным отображением статуса всех жёстких дисков со всех подконтрольных хранилищ.

Нам понадобятся пакеты php5-cli, php5-curl и собственно smartmontools.

Теперь взглянем на скрипт для парсинга информации о HDD

#!/usr/bin/php
<?php

$sname = 'server_name';
exec("ls /dev/sd*|grep -v [0-9]", $out); #Ищем что-нибудь похожее на винты
foreach($out as $entry){
$arr[] = smart($entry);
}

$data = base64_encode(json_encode($arr)); # Тут, внезапно, мы отправляем данные, получение которых описано ниже.

# Дабы не просрать ничего, упаковываем всё в json и в base64

if( $curl = curl_init() ) {
curl_setopt($curl, CURLOPT_URL, 'http://192.168.10.10/hdd.php');
curl_setopt($curl, CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, "server=".$sname."&status=".$data."&s=".md5($data));
$out = curl_exec($curl);
echo $out;
curl_close($curl);
}

function smart($dev,$atr = true){ # непосредственно чтение и парсинг
$cmd = '/usr/sbin/smartctl -AHi '.$dev; # получаем данные об устройстве
exec($cmd, $out);

# обозначаем ячейки массива
$kw = 'Serial Number';
$serial = array_values(preg_grep("/{$kw}/i",$out));
$kw = 'SMART overall-health self-assessment test result';
$health = array_values(preg_grep("/{$kw}/i",$out));
$serial = substr(strrchr(str_replace(' ', '', $serial[0]),":"),1);
$health = substr(strrchr(str_replace(' ', '', $health[0]),":"),1);
$diag['DEV'] = str_replace('/dev/','',$dev);
$diag['SN'] = $serial;
$diag['HT'] = $health;
$kw = 'ATTRIBUTE_NAME';
$lstr = array_keys(preg_grep("/{$kw}/i",$out));
$table = explode(' ', preg_replace('/\s\s+/', ' ', ltrim($out[$lstr[0]])));
$i=0;

# чтение атрибутов smart
foreach($out as $string){
if($i > $lstr[0]){
$arr = explode(' ', preg_replace('/\s\s+/', ' ', ltrim($string)));
if(count($arr) == count ($table))
$attribs[] = array_combine($table,$arr);
}
$i++;
}
if($atr == true)
$diag['ATTR'] = $attribs;
return $diag;
}
?>

[quads id=2]

Как вы видите, скрипт собирает все данные о найденных блочных устройствах (без их разделов) и отправляет их на сервер, где будет стоять вторая часть, то есть скрипт-приёмник.

А вот и его содержимое

<?php
if($_POST['s'] == md5($_POST['status'])){
$body = "<table style='width:100%'><tr><td>".$_POST['server']." HDD monitor ( ".date('d.m.Y H:i:s')." )</td></tr><tr><td style='text-align: center'>";
$data = base64_decode($_POST['status']);
$data = json_decode($data);
foreach($data as $hdd){
if($hdd->HT == "PASSED"){
$color = 'green';
} else {
$color = 'red';
}
$info ='';
foreach($hdd->ATTR as $attrib){
$info .= $attrib->ATTRIBUTE_NAME.": ".$attrib->RAW_VALUE."\n";
}
$body .= "<div title='".$info."' style='text-align: center; color: white; font-size: 14px; font-weight: bold; margin: 5px; width: 160px; height: 30px; padding:8px; float:left; background-color:".$color."'>DEV: ".$hdd->DEV."<br />".$hdd->SN."</div>";

}
$body .= "</td></tr></table>";
file_put_contents("/var/www/status/".$_POST['server'].".html", $body);
}
?>

При запросе со стороны так называемого сенсора, приёмник создаёт странички в папке status с именами серверов, взятыми из самого запроса.

Добавляем скрипт “сенсор” в крон и радуемся. ВСЁ! :)