Subversion Repositories vnag

Rev

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
}