From 32abce2529b4ccddd71744ccc3f660f1721dba6e Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Thu, 27 Feb 2020 11:15:40 +0100 Subject: [PATCH 1/9] Don't show state-badges for empty nodes Before, the empty nodes were to be considered as missing nodes. Correspondingly, the counter for missing in BpNode::getStateSummary() was increased if an empty node is encountered. Now, the empty nodes are not assumed as missing nodes and the counter for missing is not increased for this case. --- library/Businessprocess/BpNode.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 2644d0b..0556527 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -11,6 +11,7 @@ class BpNode extends Node const OP_AND = '&'; const OP_OR = '|'; const OP_NOT = '!'; + protected $operator = '&'; protected $url; protected $info_command; @@ -73,9 +74,6 @@ class BpNode extends Node $this->counters[$state]++; } } - if (! $this->hasChildren()) { - $this->counters['MISSING']++; - } } return $this->counters; } From e533ff95f5419619f71fbfb246c144d1f700a49f Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Thu, 27 Feb 2020 11:28:44 +0100 Subject: [PATCH 2/9] Introduce NODE_EMPTY state for empty nodes An empty node state called `NODE_EMPTY` has been introduced with a value of 128 in class `Node`, and this state has been mapped to value *0* in structure `$stateToSortStateMap`. --- library/Businessprocess/Node.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index a68adc2..21ed313 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -21,6 +21,7 @@ abstract class Node const ICINGA_DOWN = 1; const ICINGA_UNREACHABLE = 2; const ICINGA_PENDING = 99; + const NODE_EMPTY = 128; /** @var bool Whether to treat acknowledged hosts/services always as UP/OK */ protected static $ackIsOk = false; @@ -42,6 +43,7 @@ abstract class Node self::ICINGA_CRITICAL => 4, self::ICINGA_WARNING => 2, self::ICINGA_OK => 0, + self::NODE_EMPTY => 0 ); /** @var string Alias of the node */ @@ -115,7 +117,8 @@ abstract class Node 'WARNING', 'CRITICAL', 'UNKNOWN', - 99 => 'PENDING' + 99 => 'PENDING', + 128 => 'EMPTY' ); /** From 7de814a4af44545a3aaf2d2d23280607cc650637 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Thu, 27 Feb 2020 11:36:30 +0100 Subject: [PATCH 3/9] Set state to NODE_EMPTY in case of empty nodes In case of empty nodes, the state is set to NODE_EMPTY now. --- library/Businessprocess/BpNode.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 0556527..1170d51 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -353,7 +353,7 @@ class BpNode extends Node if (!$this->hasChildren()) { // TODO: delegate this to operators, should mostly fail - $this->setState(self::ICINGA_UNKNOWN); + $this->setState(self::NODE_EMPTY); $this->setMissing(); return $this; } From 233e9758fa28c70024a878493d48fb3a55b99072 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Thu, 27 Feb 2020 11:52:35 +0100 Subject: [PATCH 4/9] Show gray tiles and gray state badges for empty states New tiles and state badges that are of color gray is introduced for empty nodes. --- public/css/module.less | 1 + public/css/state-ball.less | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/public/css/module.less b/public/css/module.less index 5b3584e..40d71f7 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -519,6 +519,7 @@ td > a > .badges { > .pending { background-color: @colorPending; > a { text-shadow: 0 0 1px mix(#000, @colorPending, 40%); }} > .missing { background-color: @gray-light; > a { text-shadow: 0 0 1px @gray }} > .addnew { background-color: @icinga-blue; > a { text-shadow: 0 0 1px mix(#000, @icinga-blue, 40%); }} + > .empty { background-color: @gray-light; > a { text-shadow: 0 0 1px @gray }} } /* diff --git a/public/css/state-ball.less b/public/css/state-ball.less index 54a8e7a..bc05059 100644 --- a/public/css/state-ball.less +++ b/public/css/state-ball.less @@ -26,6 +26,10 @@ background-color: @color-pending; } + &.state-empty { + background-color: @gray-light; + } + &.size-xs { line-height: 0.75em; height: 0.75em; From d8567896f2d3212d556837c9ac183174390ce5af Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Thu, 27 Feb 2020 16:18:04 +0100 Subject: [PATCH 5/9] Fix 'missing node' errors for empty child nodes Before the child empty nodes where set to missing nodes by BpNode::isMissing(). This has been corrected in this fix by checking if whether a child node is an empty node or not. --- library/Businessprocess/BpNode.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 1170d51..b27c3ef 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -216,7 +216,7 @@ class BpNode extends Node } } $bp->endLoopDetection($this->name); - $this->missing = ! $exists; + $this->missing = ! $exists && ! empty($this->getChildren()); } return $this->missing; } From 51c7fdf6c972b9a0a45764a0c6aed93d9d743031 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Wed, 26 Feb 2020 17:43:28 +0100 Subject: [PATCH 6/9] Fix 'Trying to access a missing business process node <$name>' If the imported node is empty or was deleted at a later time, then in NodeTile::render() $link should not be rendered. Also, NodeTile::addDetailsAction() should not add a `href` to this tile. --- .../Renderer/TileRenderer/NodeTile.php | 58 +++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index e4f378f..d359d1d 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -85,20 +85,30 @@ class NodeTile extends BaseHtmlElement $this->addActionLinks(); } } + if (! $node instanceof ImportedNode || ! $node->isMissing()) { + $link = $this->getMainNodeLink(); + if ($renderer->isBreadcrumb()) { + $link->prepend((new StateBall(strtolower($node->getStateName())))->addAttributes([ + 'title' => sprintf( + '%s %s', + $node->getStateName(), + DateFormatter::timeSince($node->getLastStateChange()) + ) + ])); + } - $link = $this->getMainNodeLink(); - if ($renderer->isBreadcrumb()) { - $link->prepend((new StateBall(strtolower($node->getStateName())))->addAttributes([ - 'title' => sprintf( - '%s %s', - $node->getStateName(), - DateFormatter::timeSince($node->getLastStateChange()) + $this->add($link); + } else { + $this->add(Html::tag( + 'a', + Html::tag( + 'span', + ['style' => 'font-size: 75%'], + sprintf('Trying to access a missing business process node "%s"', $node->getNodeName()) ) - ])); + )); } - $this->add($link); - if ($node instanceof BpNode && !$renderer->isBreadcrumb()) { $this->add(Html::tag( 'p', @@ -191,19 +201,21 @@ class NodeTile extends BaseHtmlElement ], Html::tag('i', ['class' => 'icon icon-sitemap']) )); - if ($node->getBpConfig()->getName() !== $this->renderer->getBusinessProcess()->getName()) { - $this->actions()->add(Html::tag( - 'a', - [ - 'data-base-target' => '_next', - 'href' => $this->renderer->getSourceUrl($node)->getAbsoluteUrl(), - 'title' => mt( - 'businessprocess', - 'Show this process as part of its original configuration' - ) - ], - Html::tag('i', ['class' => 'icon icon-forward']) - )); + if ($node instanceof ImportedNode) { + if (! $node->isMissing()) { + $this->actions()->add(Html::tag( + 'a', + [ + 'data-base-target' => '_next', + 'href' => $this->renderer->getSourceUrl($node)->getAbsoluteUrl(), + 'title' => mt( + 'businessprocess', + 'Show this process as part of its original configuration' + ) + ], + Html::tag('i', ['class' => 'icon icon-forward']) + )); + } } $url = $node->getInfoUrl(); From e19612bd4a7800c00b2fdc5f76fe357e9c68a923 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Tue, 3 Mar 2020 16:40:42 +0100 Subject: [PATCH 7/9] Extend abstract isEmpty() method to check for empty nodes in child nodes We need to check recurively whether the BP Nodes contatin only child BpNodes which are empty and set the entire tree to state NODE_EMPTY state in this case. --- library/Businessprocess/BpNode.php | 24 +++++++++++++++++++++++- library/Businessprocess/Node.php | 2 ++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index b27c3ef..b6e29d4 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -24,6 +24,7 @@ class BpNode extends Node protected $childNames = array(); protected $counters; protected $missing = null; + protected $empty = null; protected $missingChildren; protected static $emptyStateSummary = array( @@ -221,6 +222,28 @@ class BpNode extends Node return $this->missing; } + public function isEmpty() + { + $bp = $this->getBpConfig(); + $empty = true; + if ($this->countChildren()) { + $bp->beginLoopDetection($this->name); + foreach ($this->getChildren() as $child) { + if ($child instanceof MonitoredNode) { + $empty = false; + break; + } elseif (!$child->isEmpty()) { + $empty = false; + } + } + $bp->endLoopDetection($this->name); + } + $this->empty = $empty; + + return $this->empty; + } + + public function getMissingChildren() { if ($this->missingChildren === null) { @@ -354,7 +377,6 @@ class BpNode extends Node if (!$this->hasChildren()) { // TODO: delegate this to operators, should mostly fail $this->setState(self::NODE_EMPTY); - $this->setMissing(); return $this; } diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index 21ed313..7849a7c 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -110,6 +110,8 @@ abstract class Node protected $missing = false; + protected $empty = false; + protected $className = 'unknown'; protected $stateNames = array( From 6cc5eb8e74bb34bc5f74fe23dba369ccfd22a9c5 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Tue, 3 Mar 2020 16:46:48 +0100 Subject: [PATCH 8/9] Check recursively for Empty BpNodes In BpNode::recalculateState() the BpNode needs to be recursively checked if its children is empty using BpNode::isEmpty() instead of BpNode::hasChildren(). --- library/Businessprocess/BpNode.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index b6e29d4..9aeaab8 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -374,7 +374,7 @@ class BpNode extends Node $sort_states = array(); $lastStateChange = 0; - if (!$this->hasChildren()) { + if ($this->isEmpty()) { // TODO: delegate this to operators, should mostly fail $this->setState(self::NODE_EMPTY); return $this; From 1bc6bf6236f6d7faa3ec0de1d4d0f558447a92e6 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Kempapura Srinivasa Date: Tue, 3 Mar 2020 16:51:03 +0100 Subject: [PATCH 9/9] Use gray tiles and state-balls for the entire branch of empty BpNode The node state is recursively calculated in case the node contains only BpNodes as its children and are empty. The gray tiles and state-balls are used for the entire branch if the children are empty. --- library/Businessprocess/Renderer/Renderer.php | 11 ++++++++--- .../Renderer/TileRenderer/NodeTile.php | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/library/Businessprocess/Renderer/Renderer.php b/library/Businessprocess/Renderer/Renderer.php index c6fbbb6..4c9a8de 100644 --- a/library/Businessprocess/Renderer/Renderer.php +++ b/library/Businessprocess/Renderer/Renderer.php @@ -6,6 +6,7 @@ use Icinga\Exception\ProgrammingError; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\ImportedNode; +use Icinga\Module\Businessprocess\MonitoredNode; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Web\Url; use ipl\Html\BaseHtmlElement; @@ -176,9 +177,13 @@ abstract class Renderer extends HtmlDocument if ($node->isMissing()) { $classes = array('missing'); } else { - $classes = array( - strtolower($node->getStateName()) - ); + if ($node->isEmpty() && ! $node instanceof MonitoredNode) { + $classes = array('empty'); + } else { + $classes = array( + strtolower($node->getStateName()) + ); + } if ($node->hasMissingChildren()) { $classes[] = 'missing-children'; } diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index d359d1d..b393724 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -85,7 +85,7 @@ class NodeTile extends BaseHtmlElement $this->addActionLinks(); } } - if (! $node instanceof ImportedNode || ! $node->isMissing()) { + if (! $node instanceof ImportedNode || $node->getBpConfig()->hasNode($node->getName())) { $link = $this->getMainNodeLink(); if ($renderer->isBreadcrumb()) { $link->prepend((new StateBall(strtolower($node->getStateName())))->addAttributes([ @@ -202,7 +202,7 @@ class NodeTile extends BaseHtmlElement Html::tag('i', ['class' => 'icon icon-sitemap']) )); if ($node instanceof ImportedNode) { - if (! $node->isMissing()) { + if ($node->getBpConfig()->hasNode($node->getName())) { $this->actions()->add(Html::tag( 'a', [