-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDiskSmartCheck.php
171 lines (153 loc) · 4.77 KB
/
DiskSmartCheck.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<?php
/**
* parse S.M.A.R.T. info for the disks found by smartctl
*
* @author Stefan Konig <[email protected]>
* @package seoSepa\PHP-ZFSHealthCheck
*/
class DiskSmartCheck
{
/**
* @var $smartCtlPath string
*/
protected $smartCtlPath = '/usr/local/sbin/smartctl';
/**
* @var $reallocatedSectorThreshold int
*/
protected $reallocatedSectorThreshold = 0; // if defects are greater then this value
/**
* @var $disks array
*/
protected $disks = array();
/**
* Perform smartctl check for all disks
*/
public function run()
{
$this->debugLog('>> Starting DiskSmartCheck');
if (!$this->smartMonToolsInstalled()) {
$this->sendFail('smartctl is not installed on this server',
'smartctl is not installed on this server, using path: ' . $this->smartCtlPath);
return;
}
$this->debugLog('smartctl is installed at ' . $this->smartCtlPath);
if (!$this->getDisks()) {
$this->sendFail(
'unable to find disks to smart check',
'smartctl did find any disks or exited not properly'
);
return;
}
foreach ($this->disks as $disk) {
$this->smartCheckDisk($disk);
}
$this->debugLog('Finished DiskSmartCheck');
}
/**
* send message to failHandler
*
* @param string $message
* @param string $verboseMessage
*/
protected function sendFail($message, $verboseMessage)
{
$failureHandler = new FailHandler();
$failureHandler->sendNotice($message, $verboseMessage);
}
/**
* send debugLog to central log function in FailHandler
*
* @param string $log
*/
protected function debugLog($log)
{
$failureHandler = new FailHandler();
$failureHandler->debugLog($log);
}
/**
* Make sure SmartMonTools are installed on this server
*
* @return boolean
*/
protected function smartMonToolsInstalled()
{
exec($this->smartCtlPath . ' --version', $output, $returnCode);
if ($returnCode !== 0) {
$this->debugLog('smartctl output: ' . implode(' ', $output));
return false;
}
return true;
}
/**
* Use proc_open in case the command zpool status hangs.
*
* @return boolean
*/
protected function getDisks()
{
$disks = array();
// get disks in zpools
$this->debugLog('smartctl scanning for devices');
exec($this->smartCtlPath . ' --scan', $output, $exitcode);
if ($exitcode !== 0) {
$this->debugLog('smartctl died :(');
return false;
}
foreach ($output as $disk) {
if (preg_match('/\/dev\/\w{4}/', $disk, $matches)) {
$disks[] = $matches[0];
$this->debugLog('disk found: ' . $matches[0]);
continue;
}
}
if (count($disks) == 0) {
$this->debugLog('no disks found, smartctl output: ' . print_r($output,true));
return false;
}
$this->disks = $disks;
return true;
}
/**
* parse the zpool status output
*
* @param string $disk
*/
protected function smartCheckDisk($disk)
{
$this->debugLog('checking: ' . $disk);
exec($this->smartCtlPath . ' -H -A ' . $disk, $output, $exitcode);
if ($exitcode !== 0) {
$this->sendFail(
"Disk {$disk} does not support smart",
'smartctl output:' . print_r($output, true)
);
return;
}
foreach ($output as $line) {
if (preg_match('/SMART overall-health self-assessment test result: (\w+)/', $line, $overall)) {
if ($overall[1] != "PASSED") {
$this->sendFail(
"Disk {$disk} health status is now: " . $overall[1],
'smartctl output:' . print_r($output, true)
);
break;
}
}
preg_match('/Reallocated_Sector_Ct .+ (\d+)$/', $line, $sectors);
if (count($sectors) > 0 && intval($sectors[1]) > $this->reallocatedSectorThreshold) {
$this->sendFail(
"Disk {$disk} has a reallocated sector count of: " . $overall[1],
'smartctl output:' . print_r($output, true)
);
break;
}
}
$this->debugLog($disk . ' PASSED');
}
}
// if wrapperClass does not exist, assume this script is run standalone
if (!class_exists('CheckAllWrapper')) {
require_once('FailHandler.php');
$diskSmartCheck = new DiskSmartCheck();
$diskSmartCheck->run();
}