diff options
Diffstat (limited to 'library/Director/CheckPlugin')
-rw-r--r-- | library/Director/CheckPlugin/Check.php | 59 | ||||
-rw-r--r-- | library/Director/CheckPlugin/CheckResult.php | 31 | ||||
-rw-r--r-- | library/Director/CheckPlugin/CheckResults.php | 150 | ||||
-rw-r--r-- | library/Director/CheckPlugin/PluginState.php | 114 | ||||
-rw-r--r-- | library/Director/CheckPlugin/Range.php | 101 | ||||
-rw-r--r-- | library/Director/CheckPlugin/Threshold.php | 47 |
6 files changed, 502 insertions, 0 deletions
diff --git a/library/Director/CheckPlugin/Check.php b/library/Director/CheckPlugin/Check.php new file mode 100644 index 0000000..d05f5a7 --- /dev/null +++ b/library/Director/CheckPlugin/Check.php @@ -0,0 +1,59 @@ +<?php + +namespace Icinga\Module\Director\CheckPlugin; + +use Exception; + +class Check extends CheckResults +{ + public function call(callable $check, $errorState = 'CRITICAL') + { + try { + $check(); + } catch (Exception $e) { + $this->fail($e, $errorState); + } + + return $this; + } + + public function assertTrue($check, $message, $errorState = 'CRITICAL') + { + if ($this->makeBool($check, $message) === true) { + $this->succeed($message); + } else { + $this->fail($message, $errorState); + } + + return $this; + } + + public function assertFalse($check, $message, $errorState = 'CRITICAL') + { + if ($this->makeBool($check, $message) === false) { + $this->succeed($message); + } else { + $this->fail($message, $errorState); + } + + return $this; + } + + protected function makeBool($check, &$message) + { + if (is_callable($check)) { + try { + $check = $check(); + } catch (Exception $e) { + $message .= ': ' . $e->getMessage(); + return false; + } + } + + if (! is_bool($check)) { + return null; + } + + return $check; + } +} diff --git a/library/Director/CheckPlugin/CheckResult.php b/library/Director/CheckPlugin/CheckResult.php new file mode 100644 index 0000000..cdf9b0d --- /dev/null +++ b/library/Director/CheckPlugin/CheckResult.php @@ -0,0 +1,31 @@ +<?php + +namespace Icinga\Module\Director\CheckPlugin; + +class CheckResult +{ + protected $state; + + protected $output; + + public function __construct($output, $state = 0) + { + if ($state instanceof PluginState) { + $this->state = $state; + } else { + $this->state = new PluginState($state); + } + + $this->output = $output; + } + + public function getState() + { + return $this->state; + } + + public function getOutput() + { + return $this->output; + } +} diff --git a/library/Director/CheckPlugin/CheckResults.php b/library/Director/CheckPlugin/CheckResults.php new file mode 100644 index 0000000..7e20225 --- /dev/null +++ b/library/Director/CheckPlugin/CheckResults.php @@ -0,0 +1,150 @@ +<?php + +namespace Icinga\Module\Director\CheckPlugin; + +use Exception; + +class CheckResults +{ + /** @var string */ + protected $name; + + /** @var PluginState */ + protected $state; + + /** @var CheckResult[] */ + protected $results = []; + + protected $stateCounters = [ + 0 => 0, + 1 => 0, + 2 => 0, + 3 => 0, + ]; + + public function __construct($name) + { + $this->name = $name; + $this->state = new PluginState(0); + } + + public function getName() + { + return $this->name; + } + + public function add(CheckResult $result) + { + $this->results[] = $result; + $this->state->raise($result->getState()); + $this->stateCounters[$result->getState()->getNumeric()]++; + + return $this; + } + + public function getStateCounters() + { + return $this->stateCounters; + } + + public function getProblemSummary() + { + $summary = []; + for ($i = 1; $i <= 3; $i++) { + $count = $this->stateCounters[$i]; + if ($count === 0) { + continue; + } + $summary[PluginState::create($i)->getName()] = $count; + } + + return $summary; + } + + public function getStateSummaryString() + { + $summary = [sprintf( + '%d tests OK', + $this->stateCounters[0] + )]; + + for ($i = 1; $i <= 3; $i++) { + $count = $this->stateCounters[$i]; + if ($count === 0) { + continue; + } + $summary[] = sprintf( + '%dx %s', + $count, + PluginState::create($i)->getName() + ); + } + + return implode(', ', $summary); + } + + public function getOutput() + { + $output = sprintf( + "%s: %s\n", + $this->name, + $this->getStateSummaryString() + ); + + foreach ($this->results as $result) { + $output .= sprintf( + "[%s] %s\n", + $result->getState()->getName(), + $result->getOutput() + ); + } + + return $output; + } + + public function getResults() + { + return $this->results; + } + + public function getState() + { + return $this->state; + } + + public function hasProblems() + { + return $this->getState()->getNumeric() !== 0; + } + + public function hasErrors() + { + $state = $this->getState()->getNumeric(); + return $state !== 0 && $state !== 1; + } + + public function succeed($message) + { + $this->add(new CheckResult($message)); + + return $this; + } + + public function warn($message) + { + $this->add(new CheckResult($message, 1)); + + return $this; + } + + public function fail($message, $errorState = 'CRITICAL') + { + if ($message instanceof Exception) { + $message = $message->getMessage(); + } + + $this->add(new CheckResult($message, $errorState)); + + return $this; + } +} diff --git a/library/Director/CheckPlugin/PluginState.php b/library/Director/CheckPlugin/PluginState.php new file mode 100644 index 0000000..d68ec70 --- /dev/null +++ b/library/Director/CheckPlugin/PluginState.php @@ -0,0 +1,114 @@ +<?php + +namespace Icinga\Module\Director\CheckPlugin; + +use Icinga\Exception\ProgrammingError; + +class PluginState +{ + protected static $stateCodes = [ + 'UNKNOWN' => 3, + 'CRITICAL' => 2, + 'WARNING' => 1, + 'OK' => 0, + ]; + + protected static $stateNames = [ + 'OK', + 'WARNING', + 'CRITICAL', + 'UNKNOWN', + ]; + + protected static $sortSeverity = [0, 1, 3, 2]; + + /** @var int */ + protected $state; + + public function __construct($state) + { + $this->set($state); + } + + public function isProblem() + { + return $this->state > 0; + } + + public function set($state) + { + $this->state = $this->getNumericStateFor($state); + } + + public function getNumeric() + { + return $this->state; + } + + public function getSortSeverity() + { + return static::getSortSeverityFor($this->getNumeric()); + } + + public function getName() + { + return self::$stateNames[$this->getNumeric()]; + } + + public function raise(PluginState $state) + { + if ($this->getSortSeverity() < $state->getSortSeverity()) { + $this->state = $state->getNumeric(); + } + + return $this; + } + + public static function create($state) + { + return new static($state); + } + + public static function ok() + { + return new static(0); + } + + public static function warning() + { + return new static(1); + } + + public static function critical() + { + return new static(2); + } + + public static function unknown() + { + return new static(3); + } + + protected static function getNumericStateFor($state) + { + if ((is_int($state) || ctype_digit($state)) && $state >= 0 && $state <= 3) { + return (int) $state; + } elseif (is_string($state) && array_key_exists($state, self::$stateCodes)) { + return self::$stateCodes[$state]; + } else { + throw new ProgrammingError('Expected valid state, got: %s', $state); + } + } + + protected static function getSortSeverityFor($state) + { + if (array_key_exists($state, self::$sortSeverity)) { + return self::$sortSeverity[$state]; + } else { + throw new ProgrammingError( + 'Unable to retrieve sort severity for invalid state: %s', + $state + ); + } + } +} diff --git a/library/Director/CheckPlugin/Range.php b/library/Director/CheckPlugin/Range.php new file mode 100644 index 0000000..d7b582e --- /dev/null +++ b/library/Director/CheckPlugin/Range.php @@ -0,0 +1,101 @@ +<?php + +namespace Icinga\Module\Director\CheckPlugin; + +use Icinga\Exception\ConfigurationError; + +class Range +{ + /** @var float|null */ + protected $start = 0; + + /** @var float|null */ + protected $end = null; + + /** @var bool */ + protected $mustBeWithinRange = true; + + public function __construct($start = 0, $end = null, $mustBeWithinRange = true) + { + $this->start = $start; + $this->end = $end; + $this->mustBeWithinRange = $mustBeWithinRange; + } + + public function valueIsValid($value) + { + if ($this->valueIsWithinRange($value)) { + return $this->valueMustBeWithinRange(); + } else { + return ! $this->valueMustBeWithinRange(); + } + } + + public function valueIsWithinRange($value) + { + if ($this->start !== null && $value < $this->start) { + return false; + } + if ($this->end !== null && $value > $this->end) { + return false; + } + + return true; + } + + public function valueMustBeWithinRange() + { + return $this->mustBeWithinRange; + } + + /** + * @param $any + * @return static + */ + public static function wantRange($any) + { + if ($any instanceof static) { + return $any; + } else { + return static::parse($any); + } + } + + /** + * @param $string + * @return static + * @throws ConfigurationError + */ + public static function parse($string) + { + $string = str_replace(' ', '', $string); + $value = '[-+]?[\d\.]+'; + $valueRe = "$value(?:e$value)?"; + $regex = "/^(@)?($valueRe|~)(:$valueRe|~)?/"; + if (! preg_match($regex, $string, $match)) { + throw new ConfigurationError('Invalid range definition: %s', $string); + } + + $inside = $match[1] === '@'; + + if (strlen($match[3]) === 0) { + $start = 0; + $end = static::parseValue($match[2]); + } else { + $start = static::parseValue($match[2]); + $end = static::parseValue($match[3]); + } + $range = new static($start, $end, $inside); + + return $range; + } + + protected static function parseValue($value) + { + if ($value === '~') { + return null; + } else { + return $value; + } + } +} diff --git a/library/Director/CheckPlugin/Threshold.php b/library/Director/CheckPlugin/Threshold.php new file mode 100644 index 0000000..76aac4e --- /dev/null +++ b/library/Director/CheckPlugin/Threshold.php @@ -0,0 +1,47 @@ +<?php + +namespace Icinga\Module\Director\CheckPlugin; + +class Threshold +{ + /** @var Range */ + protected $warning; + + /** @var Range */ + protected $critical; + + public function __construct($warning = null, $critical = null) + { + if ($warning !== null) { + $this->warning = Range::wantRange($warning); + } + + if ($critical !== null) { + $this->critical = Range::wantRange($critical); + } + } + + public static function check($value, $message, $warning = null, $critical = null) + { + $threshold = new static($warning, $critical); + $state = $threshold->checkValue($value); + return new CheckResult($message, $state); + } + + public function checkValue($value) + { + if ($this->critical !== null) { + if (! $this->critical->valueIsValid($value)) { + return PluginState::critical(); + } + } + + if ($this->warning !== null) { + if (! $this->warning->valueIsValid($value)) { + return PluginState::warning(); + } + } + + return PluginState::ok(); + } +} |