diff --git a/application/clicommands/ProcessCommand.php b/application/clicommands/ProcessCommand.php index a11a202..7b6fb4e 100644 --- a/application/clicommands/ProcessCommand.php +++ b/application/clicommands/ProcessCommand.php @@ -60,6 +60,17 @@ class ProcessCommand extends Command } } + protected function listConfigNames($withTitle) + { + foreach ($this->storage->listProcesses() as $key => $title) { + if ($withTitle) { + echo $title . "\n"; + } else { + echo $key . "\n"; + } + } + } + /** * Check a specific process * @@ -75,6 +86,16 @@ class ProcessCommand extends Command * --state-type Define which state type to look at. Could be * either soft or hard, overrides an eventually * configured default + * --blame Show problem details as a tree reduced to the + * nodes which have the same state as the business + * process + * --root-cause Used in combination with --blame. Only shows + * the path of the nodes which are responsible for + * the state of the business process + * --downtime-is-ok Treat hosts/services in downtime always as + * UP/OK. + * --ack-is-ok Treat acknowledged hosts/services always as + * UP/OK. */ public function checkAction() { @@ -106,25 +127,28 @@ class ProcessCommand extends Command exit(3); } + if ($this->params->shift('ack-is-ok')) { + Node::setAckIsOk(); + } + + if ($this->params->shift('downtime-is-ok')) { + Node::setDowntimeIsOk(); + } + printf("Business Process %s: %s\n", $node->getStateName(), $node->getAlias()); if ($this->params->shift('details')) { echo $this->renderProblemTree($node->getProblemTree(), $this->params->shift('colors')); } + if ($this->params->shift('blame')) { + echo $this->renderProblemTree( + $node->getProblemTreeBlame($this->params->shift('root-cause')), + $this->params->shift('colors') + ); + } exit($node->getState()); } - protected function listConfigNames($withTitle) - { - foreach ($this->storage->listProcesses() as $key => $title) { - if ($withTitle) { - echo $title . "\n"; - } else { - echo $key . "\n"; - } - } - } - protected function listBpNames(BpConfig $config) { foreach ($config->listBpNodes() as $title) { diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 1575b34..2644d0b 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -21,7 +21,6 @@ class BpNode extends Node /** @var array */ protected $childNames = array(); - protected $alias; protected $counters; protected $missing = null; protected $missingChildren; @@ -175,6 +174,38 @@ class BpNode extends Node return $tree; } + /** + * Get the problem nodes as tree reduced to the nodes which have the same state as the business process + * + * @param bool $rootCause Reduce nodes to the nodes which are responsible for the state of the business process + * + * @return array + */ + public function getProblemTreeBlame($rootCause = false) + { + $tree = []; + $nodeState = $this->getState(); + + if ($nodeState !== 0) { + foreach ($this->getChildren() as $child) { + $childState = $rootCause ? $child->getSortingState() : $child->getState(); + if (($rootCause ? $this->getSortingState() : $nodeState) === $childState) { + $name = $child->getName(); + $tree[$name] = [ + 'children' => [], + 'node' => $child + ]; + if ($child instanceof BpNode) { + $tree[$name]['children'] = $child->getProblemTreeBlame($rootCause); + } + } + } + } + + return $tree; + } + + public function isMissing() { if ($this->missing === null) { @@ -275,22 +306,11 @@ class BpNode extends Node return $this->info_command; } - public function hasAlias() - { - return $this->getAlias() !== null; - } - public function getAlias() { return $this->alias ? preg_replace('~_~', ' ', $this->alias) : $this->name; } - public function setAlias($name) - { - $this->alias = $name; - return $this; - } - /** * @return int */ diff --git a/library/Businessprocess/HostNode.php b/library/Businessprocess/HostNode.php index b02d3ec..8229e95 100644 --- a/library/Businessprocess/HostNode.php +++ b/library/Businessprocess/HostNode.php @@ -45,11 +45,6 @@ class HostNode extends MonitoredNode } } - public function getAlias() - { - return $this->getHostname(); - } - public function getHostname() { return $this->hostname; @@ -67,9 +62,4 @@ class HostNode extends MonitoredNode return Url::fromPath('businessprocess/host/show', $params); } - - public function getLink() - { - return Html::tag('a', ['href' => $this->getUrl()], $this->hostname); - } } diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index 2c9e7a8..067d433 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -22,6 +22,12 @@ abstract class Node const ICINGA_UNREACHABLE = 2; const ICINGA_PENDING = 99; + /** @var bool Whether to treat acknowledged hosts/services always as UP/OK */ + protected static $ackIsOk = false; + + /** @var bool Whether to treat hosts/services in downtime always as UP/OK */ + protected static $downtimeIsOk = false; + protected $sortStateToStateMap = array( 4 => self::ICINGA_CRITICAL, 3 => self::ICINGA_UNKNOWN, @@ -38,6 +44,9 @@ abstract class Node self::ICINGA_OK => 0, ); + /** @var string Alias of the node */ + protected $alias; + /** * Main business process object * @@ -111,6 +120,26 @@ abstract class Node abstract public function __construct($object); + /** + * Set whether to treat acknowledged hosts/services always as UP/OK + * + * @param bool $ackIsOk + */ + public static function setAckIsOk($ackIsOk = true) + { + self::$ackIsOk = $ackIsOk; + } + + /** + * Set whether to treat hosts/services in downtime always as UP/OK + * + * @param bool $downtimeIsOk + */ + public static function setDowntimeIsOk($downtimeIsOk = true) + { + self::$downtimeIsOk = $downtimeIsOk; + } + public function setBpConfig(BpConfig $bp) { $this->bp = $bp; @@ -219,13 +248,24 @@ abstract class Node public function getSortingState() { - $sort = $this->stateToSortState($this->getState()); + $state = $this->getState(); + + if (self::$ackIsOk && $this->isAcknowledged()) { + $state = self::ICINGA_OK; + } + + if (self::$downtimeIsOk && $this->isInDowntime()) { + $state = self::ICINGA_OK; + } + + $sort = $this->stateToSortState($state); $sort = ($sort << self::SHIFT_FLAGS) + ($this->isInDowntime() ? self::FLAG_DOWNTIME : 0) + ($this->isAcknowledged() ? self::FLAG_ACK : 0); if (! ($sort & (self::FLAG_DOWNTIME | self::FLAG_ACK))) { $sort |= self::FLAG_NONE; } + return $sort; } @@ -294,12 +334,31 @@ abstract class Node public function hasAlias() { - return false; + return $this->alias !== null; } + /** + * Get the alias of the node + * + * @return string + */ public function getAlias() { - return $this->name; + return $this->alias; + } + + /** + * Set the alias of the node + * + * @param string $alias + * + * @return $this + */ + public function setAlias($alias) + { + $this->alias = $alias; + + return $this; } public function hasParents() diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index 24efc1c..1686ccc 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -162,10 +162,8 @@ class NodeTile extends BaseHtmlElement { $node = $this->node; $url = $this->getMainNodeUrl($node); - if ($node instanceof ServiceNode) { + if ($node instanceof MonitoredNode) { $link = Html::tag('a', ['href' => $url, 'data-base-target' => '_next'], $node->getAlias()); - } elseif ($node instanceof HostNode) { - $link = Html::tag('a', ['href' => $url, 'data-base-target' => '_next'], $node->getHostname()); } else { $link = Html::tag('a', ['href' => $url], $node->getAlias()); $link->getAttributes()->add('data-base-target', '_self'); diff --git a/library/Businessprocess/ServiceNode.php b/library/Businessprocess/ServiceNode.php index b40ba02..6160bce 100644 --- a/library/Businessprocess/ServiceNode.php +++ b/library/Businessprocess/ServiceNode.php @@ -8,6 +8,9 @@ class ServiceNode extends MonitoredNode { protected $hostname; + /** @var string Alias of the host */ + protected $hostAlias; + protected $service; protected $className = 'service'; @@ -31,6 +34,30 @@ class ServiceNode extends MonitoredNode return $this->hostname; } + /** + * Get the host alias + * + * @return string + */ + public function getHostAlias() + { + return $this->hostAlias; + } + + /** + * Set the host alias + * + * @param string $hostAlias + * + * @return $this + */ + public function setHostAlias($hostAlias) + { + $this->hostAlias = $hostAlias; + + return $this; + } + public function getServiceDescription() { return $this->service; @@ -38,7 +65,7 @@ class ServiceNode extends MonitoredNode public function getAlias() { - return $this->hostname . ': ' . $this->service; + return $this->getHostAlias() . ': ' . $this->alias; } public function getUrl() diff --git a/library/Businessprocess/State/MonitoringState.php b/library/Businessprocess/State/MonitoringState.php index 80d5f41..d317528 100644 --- a/library/Businessprocess/State/MonitoringState.php +++ b/library/Businessprocess/State/MonitoringState.php @@ -6,6 +6,7 @@ use Exception; use Icinga\Application\Benchmark; use Icinga\Data\Filter\Filter; use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\ServiceNode; use Icinga\Module\Monitoring\Backend\MonitoringBackend; class MonitoringState @@ -74,7 +75,8 @@ class MonitoringState 'last_state_change' => $hostStateChangeColumn, 'in_downtime' => 'host_in_downtime', 'ack' => 'host_acknowledged', - 'state' => $hostStateColumn + 'state' => $hostStateColumn, + 'display_name' => 'host_display_name' ))->applyFilter($hostFilter)->getQuery()->fetchAll(); Benchmark::measure('Retrieved states for ' . count($hostStatus) . ' hosts in ' . $config->getName()); @@ -88,7 +90,9 @@ class MonitoringState 'last_state_change' => $serviceStateChangeColumn, 'in_downtime' => 'service_in_downtime', 'ack' => 'service_acknowledged', - 'state' => $serviceStateColumn + 'state' => $serviceStateColumn, + 'display_name' => 'service_display_name', + 'host_display_name' => 'host_display_name' ))->applyFilter($hostFilter)->getQuery()->fetchAll(); Benchmark::measure('Retrieved states for ' . count($serviceStatus) . ' services in ' . $config->getName()); @@ -137,5 +141,11 @@ class MonitoringState if ((int) $row->ack === 1) { $node->setAck(true); } + + $node->setAlias($row->display_name); + + if ($node instanceof ServiceNode) { + $node->setHostAlias($row->host_display_name); + } } } diff --git a/test/php/library/Businessprocess/HostNodeTest.php b/test/php/library/Businessprocess/HostNodeTest.php index 069f432..9839959 100644 --- a/test/php/library/Businessprocess/HostNodeTest.php +++ b/test/php/library/Businessprocess/HostNodeTest.php @@ -60,6 +60,6 @@ class HostNodeTest extends BaseTestCase return (new HostNode((object) array( 'hostname' => 'localhost', 'state' => 0, - )))->setBpConfig($bp); + )))->setBpConfig($bp)->setAlias('localhost'); } } diff --git a/test/php/library/Businessprocess/ServiceNodeTest.php b/test/php/library/Businessprocess/ServiceNodeTest.php index d4b3e5a..d56529d 100644 --- a/test/php/library/Businessprocess/ServiceNodeTest.php +++ b/test/php/library/Businessprocess/ServiceNodeTest.php @@ -51,6 +51,6 @@ class ServiceNodeTest extends BaseTestCase 'hostname' => 'localhost', 'service' => 'ping <> pong', 'state' => 0, - )))->setBpConfig($bp); + )))->setBpConfig($bp)->setHostAlias('localhost')->setAlias('ping <> pong'); } }