summaryrefslogtreecommitdiffstats
path: root/library/Director/CheckPlugin
diff options
context:
space:
mode:
Diffstat (limited to 'library/Director/CheckPlugin')
-rw-r--r--library/Director/CheckPlugin/Check.php59
-rw-r--r--library/Director/CheckPlugin/CheckResult.php31
-rw-r--r--library/Director/CheckPlugin/CheckResults.php150
-rw-r--r--library/Director/CheckPlugin/PluginState.php114
-rw-r--r--library/Director/CheckPlugin/Range.php101
-rw-r--r--library/Director/CheckPlugin/Threshold.php47
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();
+ }
+}