Subversion Repositories vnag

Rev

Rev 75 | 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>
77 daniel-mar 2
AhLH0uzYSC5/Au2X92QY2namTtPWujFr9iWDdPhrgAQq1MW3Z53fKr6eIt+kxjb5R
3
qMOZzG5gnnhp9nUKZgYDaK+Ic/5yumhv2ekVVZsbW6FSogpfDUTlXbJSqUby+TyYk
4
OSXj09oHiudrshLdI4Lx5ns75g/tzdR+9DPfNbWxEBFV1kVOtUM0MFnW31u56pHwm
5
D3oZcWXplxNDt+5sm6K1AdWXAswslMzKwaGIrKHFJdRt1mFmAp2uYBRVz6DQ0MeyN
6
zR9dMzrO7dgUrwRsxLPp3+hK9veENwcMwRXhKqVtJ6izTIgDP04hTsWeIaluUdMoX
7
UXX72/y1fh4F3jCDeWJ2iXVFLU4W6Uf7L5S3FR41+uR/pw9/6BALuuDLrA14NDiv5
8
Q7dqRtD9cJT270Ppj/6oCbdv2FtsUogSFWpd+Ca3v2IHQ9Vhsz55OJ8mlqtAkJ+TL
9
GXc46tbwi2OYHk/Iqq+A0pIgW9/1aKAeLobK0y9lgHg8zg0YXkBt3fF8ZwZvI4cnf
10
qUhnzvJ9F8kB/23hiSZVZFovYRn/kDTTX6JGdHQWCXWSU7EI6/lIc6dKBNJF3JZnJ
11
4MkKqcyLoPxnQlpG8U71bOQfgPRwpmgaTI7b9Ay9X4Y4dLah84LRxpMLGg0EuQxZL
12
F/NVKqf7wwgGclyUG4oGI+dyCed8IIvEvq8C8aKdHVtZB8pvPv6UfhHj26LCk+UeP
13
aViNRuif6TrlkYUiEzbKbfpSrQcKvWavd3QsTZfbnivflxLayrahVVebEPNOhdGDR
14
fyporIb5EhtU5CuPxqCYDhPNjNFOj0C/JJlyf6a/WiGr6TNYjkYp/jdJhBrvDk6b/
15
d7Y+TdUQaotgtLr3usqTSqoEHZrdqkcdUldB7hUHXzvYogZVYVKtuqlKRn96Yc2sc
16
3KR2ZAi+Pl3W52pMVzPlZ6zy8UZgmiuDxXuGEJ8hwcVijcTE7WV6P/fAZ7bu0LCKl
17
HsBFfSRA1ke3hZWtWRisKGpsHhXPTM8ShAHwo6nr56gJnc5Lb1scqfhJRC41V/AtG
18
4UfvpOTBJhL7wqqM8iIlZxHvGuTOH8b2NgVdkhTEmYxj69ZRZEescAB9znklUn4lF
19
XD9uW9ZvKwZXhdQ6lTEGcxI/CxGAEo3AcsFTsebK3BP1ugGcg+mkG4gU3/XKB6Hvx
20
x/3KogBF7tu2lWwPfHiV7F5cUXPpx3H8UykwFdNdQAsTKTWl58LDP/efpvStP8TZ0
21
kLOMxXXxhdVeIelQQMSsGUQ0Lz/7T4u4G7X9KdsaUrNw/1Btbr9vPRQ7ZkuXMVOzV
22
VbcCJsanRk7isRkob0574FyPyvMitdTZKC9lDOLAqbYPeaUQMsvoNyFXsvLlfJPRS
23
A==
4 daniel-mar 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
 *
77 daniel-mar 32
 * Revision 2023-10-13
2 daniel-mar 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
                }
77 daniel-mar 70
                $cont = @file_get_contents($level_file);
71
                if ($cont === false) {
72
                        throw new VNagException("Cannot read $level_file");
73
                }
74
                $level = file_exists($level_file) ? trim($cont) : 'RAID?';
2 daniel-mar 75
                return $level;
76
        }
77
 
78
        private function raidState($device) {
74 daniel-mar 79
                // mdadm outputs "clean, degraded", but /sys/block/md0/md/array_state only outputs "clean"
80
                $output = [];
81
                exec("mdadm --detail /dev/".escapeshellarg($device)." | grep -e '^\s*State : '", $output, $ec);
82
                if ($ec == 0) {
83
                        $state = trim(implode("\n", $output));
84
                        $state = trim(explode(':', $state)[1]);
85
                        return $state;
86
                }
87
 
88
                // Fallback
2 daniel-mar 89
                $state_file = "/sys/block/$device/md/array_state";
90
                if (!file_exists($state_file)) {
91
                        throw new VNagException("Kernel too old to fetch state of array $device");
92
                }
77 daniel-mar 93
                $cont = @file_get_contents($state_file);
94
                if ($cont === false) {
95
                        throw new VNagException("Cannot read $state_file");
96
                }
97
                $state = trim($cont);
2 daniel-mar 98
                return $state;
99
        }
100
 
101
        private function check_disk_state($array, $disk) {
102
                $disk_state_file = "/sys/block/$array/md/dev-$disk/state";
103
                if (!file_exists($disk_state_file)) {
104
                        throw new VNagException("Kernel too old to fetch state of disk $array:$disk");
105
                }
77 daniel-mar 106
                $cont = @file_get_contents($disk_state_file);
107
                if ($cont === false) {
108
                        throw new VNagException("Cannot read $disk_state_file");
109
                }
110
                $disk_states = trim($cont);
2 daniel-mar 111
                $disk_state_ary = explode(',', $disk_states);
112
                $disk_state_ary = array_map('trim', $disk_state_ary);
113
 
114
                $status = VNag::STATUS_OK;
115
                $verbosity = VNag::VERBOSITY_ADDITIONAL_INFORMATION;
116
 
117
                foreach ($disk_state_ary as $disk_state) {
118
                        // https://www.kernel.org/doc/html/v4.15/admin-guide/md.html
119
                        // CRIT faulty: device has been kicked from active use due to a detected fault, or it has unacknowledged bad blocks
120
                        // OK   in_sync: device is a fully in-sync member of the array
121
                        // OK   writemostly: device will only be subject to read requests if there are no other options. This applies only to raid1 arrays.
122
                        // 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.
123
                        // WARN spare: device is working, but not a full member. This includes spares that are in the process of being recovered to
124
                        // WARN write_error: device has ever seen a write error.
125
                        // WARN want_replacement: device is (mostly) working but probably should be replaced, either due to errors or due to user request.
126
                        // OK   replacement: device is a replacement for another active device with same raid_disk.
127
 
128
                        if (($disk_state == 'faulty') || ($disk_state == 'blocked')) {
129
                                $status = max($status, VNag::STATUS_CRITICAL);
130
                                $verbosity = min($verbosity, VNag::VERBOSITY_SUMMARY);
131
                        }
132
                        if (($disk_state == 'spare') || ($disk_state == 'write_error') || ($disk_state == 'want_replacement')) {
133
                                $status = max($status, VNag::STATUS_WARNING);
134
                                $verbosity = min($verbosity, VNag::VERBOSITY_SUMMARY);
135
                        }
136
                }
137
 
138
                return array($status, $verbosity, $disk_states);
139
        }
140
 
141
        private function get_raid_arrays() {
142
                $arrays = array();
75 daniel-mar 143
                $devices = glob('/dev/md/'.'*');
2 daniel-mar 144
                foreach ($devices as $device) {
145
                        $ary = explode('/', $device);
146
                        $arrays[] = 'md'.array_pop($ary);
147
                }
148
                return $arrays;
149
        }
150
 
151
        protected function cbRun() {
152
                $disks_total = 0;
153
                $disks_critical = 0;
154
                $disks_warning = 0;
155
 
156
                $arrays = $this->get_raid_arrays();
157
                foreach ($arrays as $array) {
158
                        $level = $this->raidLevel($array);
159
                        $state = $this->raidState($array);
160
 
75 daniel-mar 161
                        // https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git/tree/Detail.c#n491
162
                        if (stripos($state, ', FAILED') !== false) $this->setStatus(VNag::STATUS_CRITICAL);
163
                        if (stripos($state, ', degraded') !== false) $this->setStatus(VNag::STATUS_CRITICAL);
74 daniel-mar 164
 
2 daniel-mar 165
                        $disk_texts = array();
166
                        $verbosity = VNag::VERBOSITY_ADDITIONAL_INFORMATION;
167
                        $disks = $this->getDisks($array);
168
                        foreach ($disks as $disk) {
169
                                $disks_total++;
170
                                list($status, $verbosity_, $disk_states) = $this->check_disk_state($array, $disk);
171
                                $verbosity = min($verbosity, $verbosity_);
172
                                $this->setStatus($status);
173
                                if ($status == VNag::STATUS_WARNING) $disks_warning++;
174
                                if ($status == VNag::STATUS_CRITICAL) $disks_critical++;
175
                                $status_text = VNagLang::status($status, VNag::STATUSMODEL_SERVICE);
176
                                $disk_texts[] = "$disk ($status_text: $disk_states)";
177
                        }
178
 
179
                        # Example output:
180
                        # Array md0 (raid1, degraded): sda1 (Warning: faulty, blocked), sdb1 (OK: in_sync)
181
                        $this->addVerboseMessage("Array $array ($level, $state): ".implode(', ', $disk_texts), $verbosity);
182
                }
183
 
184
                $this->setHeadline(sprintf('%s disks in %s arrays (%s warnings, %s critical)', $disks_total, count($arrays), $disks_warning, $disks_critical));
185
        }
186
}