Rev 4 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4 | daniel-mar | 1 | <?php /* <ViaThinkSoftSignature> |
74 | daniel-mar | 2 | qStbKDX2e/Jt/CiiM7OOBUeIBb3lmSyEcJTQGXQP+duOcAVFzc9PAg65UgEqtVDR/ |
3 | CQaFy8TRJByRXi1TFaxur9x8qXMk3hupOIADduj3uqb9CwT0Ugz81fnaWHBmn4tKn |
||
4 | LN+sXmbzQThyQAsk30w2I/fbk+AEryfGgbvDL8+qR5P0gbrqvzEqdiOnzvsTFttka |
||
5 | LTOC2b6cW6UZSlRe0q+jlaHh2IpB74tHVRQDojcRLFbA2MkETWegRPe783/UUD/Ll |
||
6 | tJ3AFs4x9eJIbZCcZhn4nmskixRw9U/TTsB8USn46w8F/zkL977ZhztTj2Iy2f2ob |
||
7 | 4BNsZdzpqcQapl1QX2L2bw+38/de1lukp+ZoqFmNMvo3e2ZgM63sQg9Gaq7yPJDZo |
||
8 | MuH8XCt3Q02YVe88zGjzNcTrSt0c783UBoFyPzOYO1TU3FycHtUNZgI+YXbeo6vTI |
||
9 | duikThxyBtMa7uRwNzHZ4wZiETJQR2lxojBbzmzisA3yl3qNJApbWrc7HUmuI4TXb |
||
10 | TlS1pZELB+g0rTZtXx1zIzOvauFeu6nJsnSSxxejv/kumROvFsp6CHOMEY4jmTBOg |
||
11 | a0HI2soPozNwnj6fl0SqGfiPKlVP9PUP/o0HQpGHxE5IR/PYCYvrvg9lXMMb8WuOB |
||
12 | pKzTuw2t5HA4em2AUUx10Txpu1XhI3yAgxnMKsppPZoYzWV78m9fEBHH47WVQ2iBN |
||
13 | lSyyts3wTR8eHZJkbODGXy5eue0D1zwGddXizaqd/1jN2mzBApKDBLajJzLAxQaLk |
||
14 | 7pr3gNySRPw37j2Ilgr8pqJ64CKvADU9KNLm/BKR8EfHUgtAd5JoDRevok0Assl0e |
||
15 | ulcrnviRsnWQRDEO1971YKF8nUejI87j617ElPGB/tu+eicfZA0AtiOLdRrsEQp+I |
||
16 | vllga1Z/2cEF8Eq+Vx2rfQlsxIVJyVOAWx9PciNJpPxgzCTAG8T0y3cYGOzRx4e3p |
||
17 | r0I9tS7v/mhmy0OSjTtskZTRTH6v5TUc3R/T6Ik2rclQqoojTv8XuSKuMKSdtIvLn |
||
18 | uWC4ZKamRJNvyXpfNBtjpxGK1CSyABAix1lqWvs/VHxgkazbKj/TszzwcVTTICjD8 |
||
19 | z+RoFHDgaavdTogAoQ8Miz7h0XrKiuKNpneWpmFEHgAZCWdV//8tibFBmqSdHF2Pu |
||
20 | vAlY9mkZ5hWscQkp7IhQqQBjmIKsyTirxPty/7XnmfiGOtf+tyY+HMYQVlJpw4O2l |
||
21 | 30xxvia2w22FNOO5gMuOKgawZR/HMg0lOYz36+RLhGu1xhvKcyk6zcBZKLAUSBAtz |
||
22 | Ix/Gfbf0wee26ZDdhuw5wZ5ZfoQKGGoxDzbIDi+NsZv9KwLGDiTXoyVMPo6oDFMQQ |
||
4 | daniel-mar | 23 | Q== |
24 | </ViaThinkSoftSignature> */ ?> |
||
2 | daniel-mar | 25 | <?php |
26 | |||
27 | /* |
||
28 | * VNag - Nagios Framework for PHP |
||
29 | * Developed by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com> |
||
30 | * Licensed under the terms of the Apache 2.0 license |
||
31 | * |
||
32 | * Revision 2018-11-04 |
||
33 | */ |
||
34 | |||
35 | declare(ticks=1); |
||
36 | |||
37 | class MdStatCheck extends VNag { |
||
38 | public function __construct() { |
||
39 | parent::__construct(); |
||
40 | |||
41 | if ($this->is_http_mode()) { |
||
42 | // Don't allow the standard arguments via $_REQUEST |
||
43 | $this->registerExpectedStandardArguments(''); |
||
44 | } else { |
||
45 | $this->registerExpectedStandardArguments('Vhtv'); |
||
46 | } |
||
47 | |||
48 | $this->getHelpManager()->setPluginName('vnag_mdstat'); |
||
49 | $this->getHelpManager()->setVersion('2.0'); |
||
50 | $this->getHelpManager()->setShortDescription('This plugin checks the contents of /proc/mdstat and warns when a harddisk has failed.'); |
||
51 | $this->getHelpManager()->setCopyright('Copyright (C) 2011-$CURYEAR$ Daniel Marschall, ViaThinkSoft.'); |
||
52 | $this->getHelpManager()->setSyntax('$SCRIPTNAME$ (no additional arguments expected)'); |
||
53 | $this->getHelpManager()->setFootNotes('If you encounter bugs, please contact ViaThinkSoft at www.viathinksoft.com'); |
||
54 | } |
||
55 | |||
56 | private function getDisks($device) { |
||
57 | $disks = glob("/sys/block/$device/md/dev-*"); |
||
58 | foreach ($disks as &$disk) { |
||
59 | $ary = explode('/', $disk); |
||
60 | $disk = substr(array_pop($ary), 4); |
||
61 | } |
||
62 | return $disks; |
||
63 | } |
||
64 | |||
65 | private function raidLevel($device) { |
||
66 | $level_file = "/sys/block/$device/md/level"; |
||
67 | if (!file_exists($level_file)) { |
||
68 | throw new VNagException("Kernel too old to fetch RAID level of array $device"); |
||
69 | } |
||
70 | $level = file_exists($level_file) ? trim(file_get_contents($level_file)) : 'RAID?'; |
||
71 | return $level; |
||
72 | } |
||
73 | |||
74 | private function raidState($device) { |
||
74 | daniel-mar | 75 | // mdadm outputs "clean, degraded", but /sys/block/md0/md/array_state only outputs "clean" |
76 | $output = []; |
||
77 | exec("mdadm --detail /dev/".escapeshellarg($device)." | grep -e '^\s*State : '", $output, $ec); |
||
78 | if ($ec == 0) { |
||
79 | $state = trim(implode("\n", $output)); |
||
80 | $state = trim(explode(':', $state)[1]); |
||
81 | return $state; |
||
82 | } |
||
83 | |||
84 | // Fallback |
||
2 | daniel-mar | 85 | $state_file = "/sys/block/$device/md/array_state"; |
86 | if (!file_exists($state_file)) { |
||
87 | throw new VNagException("Kernel too old to fetch state of array $device"); |
||
88 | } |
||
89 | $state = trim(file_get_contents($state_file)); |
||
90 | return $state; |
||
91 | } |
||
92 | |||
93 | private function check_disk_state($array, $disk) { |
||
94 | $disk_state_file = "/sys/block/$array/md/dev-$disk/state"; |
||
95 | if (!file_exists($disk_state_file)) { |
||
96 | throw new VNagException("Kernel too old to fetch state of disk $array:$disk"); |
||
97 | } |
||
98 | $disk_states = trim(file_get_contents($disk_state_file)); |
||
99 | $disk_state_ary = explode(',', $disk_states); |
||
100 | $disk_state_ary = array_map('trim', $disk_state_ary); |
||
101 | |||
102 | $status = VNag::STATUS_OK; |
||
103 | $verbosity = VNag::VERBOSITY_ADDITIONAL_INFORMATION; |
||
104 | |||
105 | foreach ($disk_state_ary as $disk_state) { |
||
106 | // https://www.kernel.org/doc/html/v4.15/admin-guide/md.html |
||
107 | // CRIT faulty: device has been kicked from active use due to a detected fault, or it has unacknowledged bad blocks |
||
108 | // OK in_sync: device is a fully in-sync member of the array |
||
109 | // OK writemostly: device will only be subject to read requests if there are no other options. This applies only to raid1 arrays. |
||
110 | // CRIT blocked: device has failed, and the failure hasn.t been acknowledged yet by the metadata handler. Writes that would write to this device if it were not faulty are blocked. |
||
111 | // WARN spare: device is working, but not a full member. This includes spares that are in the process of being recovered to |
||
112 | // WARN write_error: device has ever seen a write error. |
||
113 | // WARN want_replacement: device is (mostly) working but probably should be replaced, either due to errors or due to user request. |
||
114 | // OK replacement: device is a replacement for another active device with same raid_disk. |
||
115 | |||
116 | if (($disk_state == 'faulty') || ($disk_state == 'blocked')) { |
||
117 | $status = max($status, VNag::STATUS_CRITICAL); |
||
118 | $verbosity = min($verbosity, VNag::VERBOSITY_SUMMARY); |
||
119 | } |
||
120 | if (($disk_state == 'spare') || ($disk_state == 'write_error') || ($disk_state == 'want_replacement')) { |
||
121 | $status = max($status, VNag::STATUS_WARNING); |
||
122 | $verbosity = min($verbosity, VNag::VERBOSITY_SUMMARY); |
||
123 | } |
||
124 | } |
||
125 | |||
126 | return array($status, $verbosity, $disk_states); |
||
127 | } |
||
128 | |||
129 | private function get_raid_arrays() { |
||
130 | $arrays = array(); |
||
131 | $devices = glob('/dev/md/*'); |
||
132 | foreach ($devices as $device) { |
||
133 | $ary = explode('/', $device); |
||
134 | $arrays[] = 'md'.array_pop($ary); |
||
135 | } |
||
136 | return $arrays; |
||
137 | } |
||
138 | |||
139 | protected function cbRun() { |
||
140 | $disks_total = 0; |
||
141 | $disks_critical = 0; |
||
142 | $disks_warning = 0; |
||
143 | |||
144 | $arrays = $this->get_raid_arrays(); |
||
145 | foreach ($arrays as $array) { |
||
146 | $level = $this->raidLevel($array); |
||
147 | $state = $this->raidState($array); |
||
148 | |||
74 | daniel-mar | 149 | if (strpos($state, 'degraded') !== false) $this->setStatus(VNag::STATUS_CRITICAL); |
150 | |||
2 | daniel-mar | 151 | $disk_texts = array(); |
152 | $verbosity = VNag::VERBOSITY_ADDITIONAL_INFORMATION; |
||
153 | $disks = $this->getDisks($array); |
||
154 | foreach ($disks as $disk) { |
||
155 | $disks_total++; |
||
156 | list($status, $verbosity_, $disk_states) = $this->check_disk_state($array, $disk); |
||
157 | $verbosity = min($verbosity, $verbosity_); |
||
158 | $this->setStatus($status); |
||
159 | if ($status == VNag::STATUS_WARNING) $disks_warning++; |
||
160 | if ($status == VNag::STATUS_CRITICAL) $disks_critical++; |
||
161 | $status_text = VNagLang::status($status, VNag::STATUSMODEL_SERVICE); |
||
162 | $disk_texts[] = "$disk ($status_text: $disk_states)"; |
||
163 | } |
||
164 | |||
165 | # Example output: |
||
166 | # Array md0 (raid1, degraded): sda1 (Warning: faulty, blocked), sdb1 (OK: in_sync) |
||
167 | $this->addVerboseMessage("Array $array ($level, $state): ".implode(', ', $disk_texts), $verbosity); |
||
168 | } |
||
169 | |||
170 | $this->setHeadline(sprintf('%s disks in %s arrays (%s warnings, %s critical)', $disks_total, count($arrays), $disks_warning, $disks_critical)); |
||
171 | } |
||
172 | } |