Rev 52 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 52 | Rev 53 | ||
---|---|---|---|
1 | <?php /* <ViaThinkSoftSignature> |
1 | <?php /* <ViaThinkSoftSignature> |
2 | wvt5JYOFKaJBLyUvgpwn2+bDeUf+WHsqBRn7PiRv1GfwB1OBVVJvLNeVYYsfX8yAC |
2 | FjPoJmd4Q5+yJRzZt4FvBkVzDOwgeHFuKiqEvpXwJ5MHmkZH2YMsSFb7qKCJRus5Z |
3 | EnvtdEO42wmpGEuegwcgvthOmc9ltwc3XADjReEZtDBtRJqWO9ZyszaH4/Z8cGbJP |
3 | 8PDQ8fm6MhDtXJ7N6hiI/v2tEe2zxr13q0e5ATcg6hDtZrvxks6QNwxa2Qb14q4en |
4 | 5qlQuIsw3LNkJbJIq+DZl8AoaQmYMkSB7TxDgl8QkQNbkJyynRNYSOq6i3pSkEas5 |
4 | tYShvmESYxJAO0IJkZglEFVRyovxH2zm6YgkNbMhf9IReupg2A2TvWdxvyAYXtn4e |
5 | Vr4vkFQrer9+XeHPF5tdGtw+hLSbu1Gq7x4jMIpaY0H32F0FrTUgS4UWkxO2jfzPW |
5 | /L18YW84bH2BaF6e7csex4U66yVbciMZERor6aDDQTtw32Dy1f+4X75jqkcEuYsy+ |
6 | fNkcwGQgBWDpLvno0iE52XSEMlrvpIOQiTCX96QXvBM6hNk3+uwmHG7fhhSUYoagX |
6 | rgmsAhJFOAeghSRRtbA87y26wpP8l/ima9PmmIMc7zsVJ8iuuNd5Px169m23KohpW |
7 | Ol5jeiMyQxHG9Rq3eOL07/1IR/zOI6AHENGsdfb8t3Q2/BDoEAu+B2hFsdZ1U86og |
7 | 8WKX8CuIhaaVNfa3UQM2yuM/Kj6cvYCNldouvMtGUpyXyX5ZIOM2b8aaEoDHXAtbC |
8 | AoaYXlMgfcB9CAaPgaq1sEV3ZOn+XNHblAKiV7tt5LVkp22TQpgCIbdTJButAl+J7 |
8 | SzSGeTMCDXWFsAoygwQ97fYAoXvzPXnYylIbMpLCZ5EoUyb7raF3x/6asPU7uVIWj |
9 | 1uHYUlHwxNFotjKR1JXQD/JVD+bTOrDLbuDQcUYdbgNE+PkLsqchbQCcfFPjGGUhS |
9 | y8kXL9VoBb1Dbr04drAmMzqTrH/37/+aymJ/KN7XbPwKtLbayDoBcQ/0Kt+5zVLFC |
10 | BiSi4Kica72NHF+t7dgJ5ltT+zjkQBcJdJpdgUMw7HobHNWxVhkrycVIwTN6BWan6 |
10 | Afe7r9IAKPLb76upMFxzwc4NE2IKe08a/Vis925gKki++Z55XuJtmz1UbBb0NqFdb |
11 | KsdGJHYLKoMUSnvfFFV0AJZz4v8S+KwrOVwLnGBMHPvnpf9I8qbu42nCcyKnIdXHk |
11 | MtxlFje7sAUHBjw+w5vvfWrKP18vkJlmQU7humm731fzwkqgr/LpFQpTCw6MD3CzW |
12 | UNmprr9vnuxb2Dii6tJw8ZW3uvfkv1hFPwiVvazM2Md6nCMaJwnw4iEOwqum6DaEj |
12 | iZtVsLre1Pw4AYe5QkM33u0b1RioOI/KsRKYk6FZodK/nDU1v/EKE5Ixa0JcvEDUw |
13 | YmW5F2jwx4mSqUZipp+RNxqTGfHLAO+L0x1n//RqIK+ByfVAC0QIaCIY3BtLiOdDB |
13 | /vPt9Vx3gPF8XUcM5mt5oqzr6R+HnozBbl5mLTCZCAtXExTxpSNhc0JLMfZKLWxwt |
14 | G0zHY0uiDUirMbsjK/Vs6bfcCsVZmTrDLPJGHDaHQqfHkGCteEfsAS3KdrGF5t21E |
14 | lHqQrlNBVMXf9KjcI0yRreh3Ir4VTbXjWvkD+8owA+I3edNfj9ZNiT1cC5lwFM35W |
15 | q6SY+p5lJQOAls9GFwGKfAnSViYH/4CqSNms1o+DbkhcW7sh6/2ljjqxPxl8iVs5v |
15 | o0jpqa0nV02pyM+p/anlQtQ8mlPppv4kPv0yCuOL+WbJu7ilqPusyFYmKdVBYN91L |
16 | HLx6EvKlk2ZMotSFhXBpTVYDb0V+yyIitm19M/vk/v010gkg78GbcxLi0belHX9pJ |
16 | zqBHyrddZI0uzf1Ki22GibIrfXSWx24COQFPY9ZtkuHYg6Tuh5yISfOwb2fh6A0zl |
17 | p359eqFMbtqyX5Eiyhml+IFTBqnaFBVGVo40cAPLBjZWrPjvSbmXH5cJekSn7Zlwj |
17 | Aw7J5xDU0ChQh1AWO+sly+ytIG0/dhAqXmyN0IdRnj/GsZddMm9iczdzXM6SAUFI9 |
18 | wRi1Dnmt2WKfB8mxnAPx4SrSEHQRoRvL+6NaGiZsqbGp0ptyHtAJyA6jgSw3kkttd |
18 | roosg36lsk2J1Xrl1feRsuPdYdhkJexYhJybAf3Qs0IvbPXbb1UQ9PW8vi1DXXh9G |
19 | i0+tn9KD1lXt3mMkI3SfRTtzd3u10fn6X2OP0+zYXhikLsWV4BQKPB+if72c4HLj+ |
19 | gL7aG6YqLnzTxeSW6uah/tHoc4GfAxWNq2M6OEPte8KWS6hJI3YURLaeKbc7X5zt6 |
20 | 4FF2gccV71qzCdQeMFllc0SLmeK1nXd3dMXL7jRuPDAjls1bfqJIwM6gJA2DnKqSN |
20 | 5s1JuuwWeLqF76jjaDy2Gq857qT8fBNqx7p1b3X4DbxpNcFdMQiJrXBB8BdygFKEL |
21 | 8nT4vtZ906bEkKkwDIRO4wDctSxkjvTXPg5hFWa7pgkdmpbjcm5AzM5FfrVKdZYeX |
21 | AcRnNZKmjc7+XBo4HoElAnXc3H9xflbq+F5Y5360R52b9uw17hp4TdelAzut10uOK |
22 | WbX0s6oima0/lyv2LTr5NDe0+YRMLMB8uPCEqZJKKVcrAhB2zr11GBRpy3/ERels0 |
22 | FFGGSHEVYDau3FAn3iq2dlL4AwDWcSt/myudVuaFNeoVFSpKxMwiBpb+EhFGBRoj4 |
23 | g== |
23 | w== |
24 | </ViaThinkSoftSignature> */ ?> |
24 | </ViaThinkSoftSignature> */ ?> |
25 | <?php |
25 | <?php |
26 | 26 | ||
27 | /* |
27 | /* |
28 | * VNag - Nagios Framework for PHP |
28 | * VNag - Nagios Framework for PHP |
29 | * Developed by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com> |
29 | * Developed by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com> |
30 | * Licensed under the terms of the Apache 2.0 license |
30 | * Licensed under the terms of the Apache 2.0 license |
31 | * |
31 | * |
32 | * Revision 2022-05-11 |
32 | * Revision 2022-05-11 |
33 | */ |
33 | */ |
34 | 34 | ||
35 | declare(ticks=1); |
35 | declare(ticks=1); |
36 | 36 | ||
37 | class SmartCheck extends VNag { |
37 | class SmartCheck extends VNag { |
38 | protected $argType = null; |
38 | protected $argType = null; |
39 | 39 | ||
40 | public function __construct() { |
40 | public function __construct() { |
41 | parent::__construct(); |
41 | parent::__construct(); |
42 | 42 | ||
43 | if ($this->is_http_mode()) { |
43 | if ($this->is_http_mode()) { |
44 | // Don't allow the standard arguments via $_REQUEST |
44 | // Don't allow the standard arguments via $_REQUEST |
45 | $this->registerExpectedStandardArguments(''); |
45 | $this->registerExpectedStandardArguments(''); |
46 | } else { |
46 | } else { |
47 | $this->registerExpectedStandardArguments('Vhtv'); |
47 | $this->registerExpectedStandardArguments('Vhtv'); |
48 | } |
48 | } |
49 | 49 | ||
50 | $this->getHelpManager()->setPluginName('vnag_smart'); |
50 | $this->getHelpManager()->setPluginName('vnag_smart'); |
51 | $this->getHelpManager()->setVersion('1.0'); |
51 | $this->getHelpManager()->setVersion('1.0'); |
52 | $this->getHelpManager()->setShortDescription('This plugin checks the contents of the SMART data and warns when a harddisk has failed.'); |
52 | $this->getHelpManager()->setShortDescription('This plugin checks the contents of the SMART data and warns when a harddisk has failed.'); |
53 | $this->getHelpManager()->setCopyright('Copyright (C) 2011-$CURYEAR$ Daniel Marschall, ViaThinkSoft.'); |
53 | $this->getHelpManager()->setCopyright('Copyright (C) 2011-$CURYEAR$ Daniel Marschall, ViaThinkSoft.'); |
54 | $this->getHelpManager()->setSyntax('$SCRIPTNAME$ [-T <type>]'); |
54 | $this->getHelpManager()->setSyntax('$SCRIPTNAME$ [-T <type>]'); |
55 | $this->getHelpManager()->setFootNotes('If you encounter bugs, please contact ViaThinkSoft at www.viathinksoft.com'); |
55 | $this->getHelpManager()->setFootNotes('If you encounter bugs, please contact ViaThinkSoft at www.viathinksoft.com'); |
56 | 56 | ||
57 | // TODO: also add a command to check a single drive [ -d /dev/sda,/dev/sdb ] |
57 | // TODO: also add a command to check a single drive [ -d /dev/sda,/dev/sdb ] |
58 | // Individual (non-standard) arguments: |
58 | // Individual (non-standard) arguments: |
59 | $this->addExpectedArgument($this->argType = new VNagArgument('T', 'type', VNagArgument::VALUE_REQUIRED, 'type', 'Explicit drive type e.g. for RAID devices "sat+cciss,0" for drive 0.')); |
59 | $this->addExpectedArgument($this->argType = new VNagArgument('T', 'type', VNagArgument::VALUE_REQUIRED, 'type', 'Explicit drive type e.g. for RAID devices "sat+cciss,0" for drive 0.')); |
60 | } |
60 | } |
61 | 61 | ||
62 | private function check_smart($dev) { |
62 | private function check_smart($dev) { |
63 | if (!`which which`) { |
63 | if (!`which which`) { |
64 | throw new VNagException("Program 'which' is not installed on your system"); |
64 | throw new VNagException("Program 'which' is not installed on your system"); |
65 | } |
65 | } |
66 | 66 | ||
67 | if (!`which smartctl`) { |
67 | if (!`which smartctl`) { |
68 | throw new VNagException("Program 'smartctl' (usually included in package smartmontools) is not installed on your system"); |
68 | throw new VNagException("Program 'smartctl' (usually included in package smartmontools) is not installed on your system"); |
69 | } |
69 | } |
70 | 70 | ||
71 | $code = 0; |
71 | $code = 0; |
72 | $out = array(); |
72 | $out = array(); |
73 | 73 | ||
74 | // TODO: For some reason, it does not work if "sudo" is added to the command section in icinga2.conf! |
- | |
75 | if ($this->argType->getValue() != '') { |
74 | if ($this->argType->getValue() != '') { |
- | 75 | // Note: Requires root |
|
76 | exec('sudo smartctl --all '.escapeshellarg($dev).' -d '.escapeshellarg($this->argType->getValue()), $out, $code); |
76 | exec('smartctl --all '.escapeshellarg($dev).' -d '.escapeshellarg($this->argType->getValue()), $out, $code); |
77 | } else { |
77 | } else { |
- | 78 | // Note: Requires root |
|
78 | exec('sudo smartctl --all '.escapeshellarg($dev), $out, $code); |
79 | exec('smartctl --all '.escapeshellarg($dev), $out, $code); |
79 | } |
80 | } |
80 | $cont = implode("\n", $out); |
81 | $cont = implode("\n", $out); |
81 | 82 | ||
82 | $msg = array(); |
83 | $msg = array(); |
83 | $status = -1; |
84 | $status = -1; |
84 | 85 | ||
85 | if (stripos($cont, 'device lacks SMART capability') !== false) { |
86 | if (stripos($cont, 'device lacks SMART capability') !== false) { |
86 | // At my system (Debian 9), I get exit code 4 (which is not fully accurate) |
87 | // At my system (Debian 9), I get exit code 4 (which is not fully accurate) |
87 | $msg[] = 'Device lacks SMART capability'; |
88 | $msg[] = 'Device lacks SMART capability'; |
88 | #$status = VNag::STATUS_UNKNOWN; |
89 | #$status = VNag::STATUS_UNKNOWN; |
89 | } else if ($code == 0) { |
90 | } else if ($code == 0) { |
90 | $status = VNag::STATUS_OK; |
91 | $status = VNag::STATUS_OK; |
91 | } else { |
92 | } else { |
92 | if ($code & 1) { |
93 | if ($code & 1) { |
93 | throw new Exception("smartctl reports 'command line did not parse' (code $code)."); |
94 | throw new Exception("smartctl reports 'command line did not parse' (code $code)."); |
94 | } |
95 | } |
95 | if ($code & 2) { |
96 | if ($code & 2) { |
96 | $msg[] = "Device open failed. It is either completely defective, or in low-power mode."; |
97 | $msg[] = "Device open failed. It is either completely defective, or in low-power mode."; |
97 | $status = max($status, VNag::STATUS_CRITICAL); |
98 | $status = max($status, VNag::STATUS_CRITICAL); |
98 | } |
99 | } |
99 | if ($code & 4) { |
100 | if ($code & 4) { |
100 | $msg[] = "SMART command failed or checksum is wrong."; |
101 | $msg[] = "SMART command failed or checksum is wrong."; |
101 | $status = max($status, VNag::STATUS_WARNING); |
102 | $status = max($status, VNag::STATUS_WARNING); |
102 | } |
103 | } |
103 | if ($code & 8) { |
104 | if ($code & 8) { |
104 | $msg[] = "SMART status returns 'DISK FAILING'"; |
105 | $msg[] = "SMART status returns 'DISK FAILING'"; |
105 | $status = max($status, VNag::STATUS_CRITICAL); |
106 | $status = max($status, VNag::STATUS_CRITICAL); |
106 | } |
107 | } |
107 | if ($code & 16) { |
108 | if ($code & 16) { |
108 | $msg[] = "SMART found prefail attributes below threshold"; |
109 | $msg[] = "SMART found prefail attributes below threshold"; |
109 | $status = max($status, VNag::STATUS_WARNING); |
110 | $status = max($status, VNag::STATUS_WARNING); |
110 | } |
111 | } |
111 | if ($code & 32) { |
112 | if ($code & 32) { |
112 | $msg[] = "SMART status is 'OK' but usage/prefail attributes have been below threshold in the past."; |
113 | $msg[] = "SMART status is 'OK' but usage/prefail attributes have been below threshold in the past."; |
113 | $status = max($status, VNag::STATUS_WARNING); |
114 | $status = max($status, VNag::STATUS_WARNING); |
114 | } |
115 | } |
115 | if ($code & 64) { |
116 | if ($code & 64) { |
116 | $msg[] = "The device error log contains records of errors."; |
117 | $msg[] = "The device error log contains records of errors."; |
117 | $status = max($status, VNag::STATUS_WARNING); |
118 | $status = max($status, VNag::STATUS_WARNING); |
118 | } |
119 | } |
119 | if ($code & 128) { |
120 | if ($code & 128) { |
120 | $msg[] = "The self-test logs contains records of errors."; |
121 | $msg[] = "The self-test logs contains records of errors."; |
121 | $status = max($status, VNag::STATUS_WARNING); |
122 | $status = max($status, VNag::STATUS_WARNING); |
122 | } |
123 | } |
123 | } |
124 | } |
124 | 125 | ||
125 | $messages = implode(", ", $msg); |
126 | $messages = implode(", ", $msg); |
126 | if ($messages != '') $messages = ": $messages"; |
127 | if ($messages != '') $messages = ": $messages"; |
127 | 128 | ||
128 | if ($status == VNag::STATUS_CRITICAL) { |
129 | if ($status == VNag::STATUS_CRITICAL) { |
129 | $this->addVerboseMessage("$dev (Critical)$messages", VNag::VERBOSITY_SUMMARY); |
130 | $this->addVerboseMessage("$dev (Critical)$messages", VNag::VERBOSITY_SUMMARY); |
130 | } else if ($status == VNag::STATUS_WARNING) { |
131 | } else if ($status == VNag::STATUS_WARNING) { |
131 | $this->addVerboseMessage("$dev (Warning)$messages", VNag::VERBOSITY_SUMMARY); |
132 | $this->addVerboseMessage("$dev (Warning)$messages", VNag::VERBOSITY_SUMMARY); |
132 | } else if ($status == VNag::STATUS_OK) { |
133 | } else if ($status == VNag::STATUS_OK) { |
133 | $this->addVerboseMessage("$dev (OK)$messages", VNag::VERBOSITY_ADDITIONAL_INFORMATION); |
134 | $this->addVerboseMessage("$dev (OK)$messages", VNag::VERBOSITY_ADDITIONAL_INFORMATION); |
134 | } else { |
135 | } else { |
135 | $status = VNag::STATUS_UNKNOWN; |
136 | $status = VNag::STATUS_UNKNOWN; |
136 | $this->addVerboseMessage("$dev (Unknown)$messages", VNag::VERBOSITY_SUMMARY); |
137 | $this->addVerboseMessage("$dev (Unknown)$messages", VNag::VERBOSITY_SUMMARY); |
137 | } |
138 | } |
138 | $this->setStatus($status); |
139 | $this->setStatus($status); |
139 | return $status; |
140 | return $status; |
140 | } |
141 | } |
141 | 142 | ||
142 | protected function cbRun() { |
143 | protected function cbRun() { |
143 | $devices = array(); |
144 | $devices = array(); |
144 | $devices = array_merge($devices, glob('/dev/sd?')); |
145 | $devices = array_merge($devices, glob('/dev/sd?')); |
145 | $devices = array_merge($devices, glob('/dev/hd?')); |
146 | $devices = array_merge($devices, glob('/dev/hd?')); |
146 | 147 | ||
147 | if (count($devices) == 0) { |
148 | if (count($devices) == 0) { |
148 | throw new Exception("No SDx or HDx drives found"); |
149 | throw new Exception("No SDx or HDx drives found"); |
149 | } |
150 | } |
150 | 151 | ||
151 | if (strpos($this->argType->getValue(),'cciss') !== false) { |
152 | if (strpos($this->argType->getValue(),'cciss') !== false) { |
152 | $devices = array($devices[0]); // we just need a "fake" drive; the drive number is given as parameter to cciss |
153 | $devices = array($devices[0]); // we just need a "fake" drive; the drive number is given as parameter to cciss |
153 | } |
154 | } |
154 | 155 | ||
155 | $count_total = 0; |
156 | $count_total = 0; |
156 | $count_ok = 0; |
157 | $count_ok = 0; |
157 | $count_warning = 0; |
158 | $count_warning = 0; |
158 | $count_critical = 0; |
159 | $count_critical = 0; |
159 | $count_unknown = 0; |
160 | $count_unknown = 0; |
160 | foreach ($devices as $dev) { |
161 | foreach ($devices as $dev) { |
161 | $count_total++; |
162 | $count_total++; |
162 | switch ($this->check_smart($dev)) { |
163 | switch ($this->check_smart($dev)) { |
163 | case VNag::STATUS_OK: |
164 | case VNag::STATUS_OK: |
164 | $count_ok++; |
165 | $count_ok++; |
165 | break; |
166 | break; |
166 | case VNag::STATUS_WARNING: |
167 | case VNag::STATUS_WARNING: |
167 | $count_warning++; |
168 | $count_warning++; |
168 | break; |
169 | break; |
169 | case VNag::STATUS_CRITICAL: |
170 | case VNag::STATUS_CRITICAL: |
170 | $count_critical++; |
171 | $count_critical++; |
171 | break; |
172 | break; |
172 | case VNag::STATUS_UNKNOWN: |
173 | case VNag::STATUS_UNKNOWN: |
173 | $count_unknown++; |
174 | $count_unknown++; |
174 | break; |
175 | break; |
175 | } |
176 | } |
176 | } |
177 | } |
177 | 178 | ||
178 | $this->setHeadline(sprintf('Checked %d drives (%d OK, %d warning, %d critical, %d unknown)', $count_total, $count_ok, $count_warning, $count_critical, $count_unknown)); |
179 | $this->setHeadline(sprintf('Checked %d drives (%d OK, %d warning, %d critical, %d unknown)', $count_total, $count_ok, $count_warning, $count_critical, $count_unknown)); |
179 | } |
180 | } |
180 | } |
181 | } |
181 | 182 |