Subversion Repositories vnag

Rev

Rev 74 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. <?php /* <ViaThinkSoftSignature>
  2. mtmvqpXTiEFshc+2P4dRVNT23IchwdqjV/wbN3l5+PK7mNjkWa9mhC4BvqzuTR0QW
  3. r1bm0NqyRmammvx1Cu+SFP6vLEbrXQti/UaGrawmdfcij1wXqpsbM7dUqIXvVmprl
  4. 1VA9DmSh/4+aFtf0TiyVDDJ2iET8ZS89/pCZIPZNiBSzxWsKKmqQnQUwb809A41Ji
  5. IBf8l75kwvkR9fd7u9cVVEVaJzFKFA0NsC+jVhnmgit1db4VB9pVKUWnueDBjNYy4
  6. ugVf88abnIWdlx1sDAISTs3N8b5kMCm5bWrG6AywdkaXq8y+4wo18HoP0NufnkFIf
  7. LMJR2jZoH91SMqlgkMYZpRuFhLBU9LUaW5G95IV/Fkmy3qx9FebrYLQckFAZ5tMfY
  8. w5JjBKM5xuBBYcds2CqSZoRUBH9EzlM6z2tFFM/+CspzMlDkvBRCeYSXpw3TW+GJP
  9. 1326HZCf82uJKySugzbHxSajtg2s9byWYS/Ttymyt9oeAmsBlL3npbYrIFQ0MVYuf
  10. db8UT3leZyYianWo9mAXW3eUTUnDUKI0X38re4EGR0M/kaKFaJn6FqeGhtOpn6yc9
  11. kQmFKuFTuf3ENID62wbwBmX1/wdVO/lF87B0li/LmJG+wBYevVwDJJkvj46s7QGcA
  12. VWPTnDIoUU8cZjVGFIAAxgzPQ59riep8zEWFQPEB+B6kzUhMWbJcRvBpldtJtCi7j
  13. AgqN+h78sAq1McvUXW6IgkseXe7QTyjQhw2l7QFuWD3txToUFu/istN+il3+cQ424
  14. +/Q/TkrOlJ+549pwsyztF7bAyK2WNlj5EAa/WX/MYSOEvVG6Cn/eoC1+OdKy8YHy3
  15. UWiMIef0TY0yWaL6uXLfD+dQYTH1nHuKueGl5Fjqnm6/mrxt7BsLRXBF01dRibzRq
  16. HAtes6iLt2t3pX2uFeIQBqsyaryCdFTIZ3hzb5jkLxJ0njqOBEQ7lbrqI6rY+ICul
  17. ZnrFzqlzMYhNGkG5+PO/iLbHeKmaR+cyFGZP8e/oGKGc/I/SEn4eOi3M/D/98Sgvp
  18. 1fpQxllbhq3V2o/off/io2Mhj7ohRG7/1efm9LnJrtiRo6L9/BJ6lXDq/0c9piM0t
  19. INo9x4Wiulq8BC6aZkpVn0QpKeFZH5PAeAx4IcRINREUIFvFxNQFTcz3aCkX3kWy6
  20. YZNjABPUzxTpVdPr/0c+Zakuqd7+gAID8RdPeBkct3dZKCnmJWgKmJFdYaXs9uYr7
  21. HcjBU3o8+dr1vUpI7RFMCNilqWO23dTzIotw4Dq1hBb6rm5jt6lr+M7SMDhsI8ivL
  22. gPgkwuVvsydi7dvIXZte4SwxPlOEVzpSKWx1pUvussHWNVJ80KbU+GtlMpRlFkpGK
  23. Q==
  24. </ViaThinkSoftSignature> */ ?>
  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 2023-10-02
  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) {
  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
  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.  
  149.                         // https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git/tree/Detail.c#n491
  150.                         if (stripos($state, ', FAILED') !== false) $this->setStatus(VNag::STATUS_CRITICAL);
  151.                         if (stripos($state, ', degraded') !== false) $this->setStatus(VNag::STATUS_CRITICAL);
  152.  
  153.                         $disk_texts = array();
  154.                         $verbosity = VNag::VERBOSITY_ADDITIONAL_INFORMATION;
  155.                         $disks = $this->getDisks($array);
  156.                         foreach ($disks as $disk) {
  157.                                 $disks_total++;
  158.                                 list($status, $verbosity_, $disk_states) = $this->check_disk_state($array, $disk);
  159.                                 $verbosity = min($verbosity, $verbosity_);
  160.                                 $this->setStatus($status);
  161.                                 if ($status == VNag::STATUS_WARNING) $disks_warning++;
  162.                                 if ($status == VNag::STATUS_CRITICAL) $disks_critical++;
  163.                                 $status_text = VNagLang::status($status, VNag::STATUSMODEL_SERVICE);
  164.                                 $disk_texts[] = "$disk ($status_text: $disk_states)";
  165.                         }
  166.  
  167.                         # Example output:
  168.                         # Array md0 (raid1, degraded): sda1 (Warning: faulty, blocked), sdb1 (OK: in_sync)
  169.                         $this->addVerboseMessage("Array $array ($level, $state): ".implode(', ', $disk_texts), $verbosity);
  170.                 }
  171.  
  172.                 $this->setHeadline(sprintf('%s disks in %s arrays (%s warnings, %s critical)', $disks_total, count($arrays), $disks_warning, $disks_critical));
  173.         }
  174. }
  175.