diff --git a/doc/Support/Install Validation.md b/doc/Support/Install Validation.md index ba90879dea..2ed6a2ce03 100644 --- a/doc/Support/Install Validation.md +++ b/doc/Support/Install Validation.md @@ -17,7 +17,9 @@ So, to try and help with some of the general issues people come across we've put Optionally you can also pass -m and a module name for that to be tested. Current modules are: - - mail. This will validate your mail transport configuration. + - mail - This will validate your mail transport configuration. + - dist-poller - This will test your distributed poller configuration. + - rrdcheck - This will test your rrd files to see if they are unreadable or corrupted (source of broken graphs). Output, this is color coded to try and make things a little easier: diff --git a/includes/functions.php b/includes/functions.php index e399a10ae5..e547100548 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -1366,3 +1366,70 @@ function dnslookup($device,$type=false,$return=false) { $record = dns_get_record($device['hostname'],$type); return $record[0][$return]; }//end dnslookup + + +/** + * Reursive Filter Iterator to iterate directories and locate .rrd files. + * + * @method boolean isDir() + * +**/ + +class RRDRecursiveFilterIterator extends \RecursiveFilterIterator { + + public function accept() { + $filename = $this->current()->getFilename(); + if ($filename[0] === '.') { + // Ignore hidden files and directories + return false; + } + if ($this->isDir()) { + // We want to search into directories + return true; + } + // Matches files with .rrd in the filename. + // We are only searching rrd folder, but there could be other files and we don't want to cause a stink. + return strpos($filename, '.rrd') !== false; + } +} + +/** + * Run rrdtool info on a file path + * + * @param string $path Path to pass to rrdtool info + * @param string $stdOutput Variable to recieve the output of STDOUT + * @param string $stdError Variable to recieve the output of STDERR + * + * @return int exit code + * +**/ + +function rrdtest($path, &$stdOutput, &$stdError) { + global $config; + //rrdtool info + $command = $config['rrdtool'].' info '.escapeshellarg($path); + $process = proc_open( + $command, + array ( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w'), + ), + $pipes + ); + + if (!is_resource($process)) { + throw new \RuntimeException('Could not create a valid process'); + } + + $status = proc_get_status($process); + while($status['running']) { + usleep(2000); // Sleep 2000 microseconds or 2 milliseconds + $status = proc_get_status($process); + } + + $stdOutput = stream_get_contents($pipes[1]); + $stdError = stream_get_contents($pipes[2]); + proc_close($process); + return $status['exitcode']; +} diff --git a/validate.php b/validate.php index 13db33efd6..f2fe619e32 100755 --- a/validate.php +++ b/validate.php @@ -24,6 +24,7 @@ if (isset($options['h'])) { -m Any sub modules you want to run, comma separated: - mail: this will test your email settings (uses default_mail option even if default_only is not set). - dist-poller: this will test for the install running as a distributed poller. + - rrdcheck: this will check to see if your rrd files are corrupt Example: ./validate.php -m mail. @@ -267,6 +268,46 @@ foreach ($modules as $module) { } } } + break; + case 'rrdcheck': + + // Loop through the rrd_dir + $rrd_directory = new RecursiveDirectoryIterator($config['rrd_dir']); + // Filter out any non rrd files + $rrd_directory_filter = new RRDRecursiveFilterIterator($rrd_directory); + $rrd_iterator = new RecursiveIteratorIterator($rrd_directory_filter); + $rrd_total = iterator_count($rrd_iterator); + $rrd_iterator->rewind(); // Rewind iterator in case iterator_count left iterator in unknown state + + echo "\nScanning ".$rrd_total." rrd files in ".$config['rrd_dir']."...\n"; + + // Count loops so we can push status to the user + $loopcount = 0; + $screenpad = 0; + + foreach ($rrd_iterator as $filename => $file) { + + $rrd_test_result = rrdtest($filename, $output, $error); + + $loopcount++; + if (($loopcount % 50) == 0 ) { + //This lets us update the previous status update without spamming in most consoles + echo "\033[".$screenpad."D"; + $test_status = 'Status: '.$loopcount.'/'.$rrd_total; + echo $test_status; + $screenpad = strlen($test_status); + } + + // A non zero result means there was some kind of error + if ($rrd_test_result > 0) { + echo "\033[".$screenpad."D"; + print_fail('Error parsing "'.$filename.'" RRD '.trim($error)); + $screenpad = 0; + } + } + echo "\033[".$screenpad."D"; + echo "Status: ".$loopcount."/".$rrd_total." - Complete\n"; + break; }//end switch }//end foreach