diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index 03db018..04fd331 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -2,12 +2,15 @@ namespace Icinga\Module\Businessprocess; +use Exception; +use LogicException; +use Icinga\Application\Config; use Icinga\Exception\IcingaException; use Icinga\Exception\NotFoundError; use Icinga\Module\Businessprocess\Exception\NestingError; use Icinga\Module\Businessprocess\Modification\ProcessChanges; +use Icinga\Module\Businessprocess\Storage\LegacyStorage; use Icinga\Module\Monitoring\Backend\MonitoringBackend; -use Exception; class BpConfig { @@ -81,6 +84,13 @@ class BpConfig */ protected $root_nodes = array(); + /** + * Imported configs + * + * @var array + */ + protected $importedConfigs = []; + /** * All host names { 'hostA' => true, ... } * @@ -424,7 +434,17 @@ class BpConfig public function hasNode($name) { - return array_key_exists($name, $this->nodes); + if (array_key_exists($name, $this->nodes)) { + return true; + } elseif (! empty($this->importedConfigs)) { + foreach ($this->importedConfigs as $config) { + if ($config->hasNode($name)) { + return true; + } + } + } + + return false; } public function hasRootNode($name) @@ -474,7 +494,14 @@ class BpConfig public function listInvolvedHostNames() { - return array_keys($this->hosts); + $hosts = $this->hosts; + if (! empty($this->importedConfigs)) { + foreach ($this->importedConfigs as $config) { + $hosts += array_flip($config->listInvolvedHostNames()); + } + } + + return array_keys($hosts); } /** @@ -514,6 +541,18 @@ class BpConfig public function createImportedNode($config, $name = null) { + if (! isset($this->importedConfigs[$config])) { + $import = $this->storage()->loadProcess($config); + + if ($this->usesSoftStates()) { + $import->useSoftStates(); + } else { + $import->useHardStates(); + } + + $this->importedConfigs[$config] = $import; + } + $params = (object) array('configName' => $config); if ($name !== null) { $params->node = $name; @@ -524,6 +563,25 @@ class BpConfig return $node; } + public function getImportedConfig($name) + { + if (! isset($this->importedConfigs[$name])) { + throw new LogicException("Config $name not imported yet"); + } + + return $this->importedConfigs[$name]; + } + + /** + * @return LegacyStorage + */ + protected function storage() + { + return new LegacyStorage( + Config::module('businessprocess')->getSection('global') + ); + } + /** * @param $name * @return Node @@ -537,6 +595,12 @@ class BpConfig if (array_key_exists($name, $this->nodes)) { return $this->nodes[$name]; + } elseif (! empty($this->importedConfigs)) { + foreach ($this->importedConfigs as $config) { + if ($config->hasNode($name)) { + return $config->getNode($name); + } + } } // Fallback: if it is a service, create an empty one: diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index f244343..f514198 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -52,8 +52,8 @@ class BpNode extends Node { $this->bp = $bp; $this->name = $object->name; - $this->setOperator($object->operator); - $this->setChildNames($object->child_names); + $this->operator = $object->operator; + $this->childNames = $object->child_names; } public function getStateSummary() @@ -140,12 +140,12 @@ class BpNode extends Node public function hasChild($name) { - return in_array($name, $this->childNames); + return in_array($name, $this->getChildNames()); } public function removeChild($name) { - if (($key = array_search($name, $this->childNames)) !== false) { + if (($key = array_search($name, $this->getChildNames())) !== false) { unset($this->childNames[$key]); if (! empty($this->children)) { @@ -276,7 +276,7 @@ class BpNode extends Node public function hasAlias() { - return $this->alias !== null; + return $this->getAlias() !== null; } public function getAlias() @@ -357,7 +357,7 @@ class BpNode extends Node $this->setLastStateChange($lastStateChange); - switch ($this->operator) { + switch ($this->getOperator()) { case self::OP_AND: $sort_state = max($sort_states); break; @@ -438,7 +438,8 @@ class BpNode extends Node public function hasChildren($filter = null) { - return !empty($this->childNames); + $childNames = $this->getChildNames(); + return !empty($childNames); } public function getChildNames() @@ -451,10 +452,11 @@ class BpNode extends Node if ($this->children === null) { $this->children = array(); if (! $this->bp->getMetadata()->isManuallyOrdered()) { - natcasesort($this->childNames); - $this->childNames = array_values($this->childNames); + $childNames = $this->getChildNames(); + natcasesort($childNames); + $this->childNames = array_values($childNames); } - foreach ($this->childNames as $name) { + foreach ($this->getChildNames() as $name) { $this->children[$name] = $this->bp->getNode($name); $this->children[$name]->addParent($this); } @@ -497,14 +499,14 @@ class BpNode extends Node protected function assertNumericOperator() { - if (! is_numeric($this->operator)) { + if (! is_numeric($this->getOperator())) { throw new ConfigurationError('Got invalid operator: %s', $this->operator); } } public function operatorHtml() { - switch ($this->operator) { + switch ($this->getOperator()) { case self::OP_AND: return 'AND'; break; diff --git a/library/Businessprocess/ImportedNode.php b/library/Businessprocess/ImportedNode.php index dcb9944..02d0ff2 100644 --- a/library/Businessprocess/ImportedNode.php +++ b/library/Businessprocess/ImportedNode.php @@ -2,15 +2,13 @@ namespace Icinga\Module\Businessprocess; -use Icinga\Application\Config; -use Icinga\Module\Businessprocess\State\MonitoringState; -use Icinga\Module\Businessprocess\Storage\LegacyStorage; use Exception; -use Icinga\Web\Url; -use ipl\Html\Html; -class ImportedNode extends Node +class ImportedNode extends BpNode { + /** @var BpConfig */ + protected $parentBp; + /** @var string */ protected $configName; @@ -18,38 +16,27 @@ class ImportedNode extends Node protected $nodeName; /** @var BpNode */ - private $node; + protected $importedNode; - protected $className = 'subtree'; + /** @var string */ + protected $className = 'process subtree'; + /** @var string */ protected $icon = 'download'; - /** @var BpConfig */ - private $config; - - /** - * @inheritdoc - */ public function __construct(BpConfig $bp, $object) { - $this->bp = $bp; + $this->parentBp = $bp; $this->configName = $object->configName; - $this->name = '@' . $object->configName; - if (property_exists($object, 'node')) { - $this->nodeName = $object->node; - $this->name .= ':' . $object->node; - } else { - $this->useAllRootNodes(); - } + $this->nodeName = $object->node; - if (isset($object->state)) { - $this->setState($object->state); - } - } - - public function hasNode() - { - return $this->nodeName !== null; + $importedConfig = $bp->getImportedConfig($this->configName); + parent::__construct($importedConfig, (object) [ + 'name' => '@' . $this->configName . ':' . $this->nodeName, + 'operator' => null, + 'child_names' => null + ] + ); } /** @@ -61,75 +48,38 @@ class ImportedNode extends Node } /** - * @inheritdoc + * @return string */ - public function getState() + public function getNodeName() { - if ($this->state === null) { - try { - MonitoringState::apply($this->importedConfig()); - } catch (Exception $e) { - } - - $this->state = $this->importedNode()->getState(); - $this->setMissing(false); - } - - return $this->state; + return $this->nodeName; } - /** - * @inheritdoc - */ public function getAlias() { - return $this->importedNode()->getAlias(); - } - - public function getUrl() - { - $params = array( - 'config' => $this->getConfigName(), - 'node' => $this->importedNode()->getName() - ); - - return Url::fromPath('businessprocess/process/show', $params); - } - - /** - * @inheritdoc - */ - public function isMissing() - { - $this->getState(); - // Probably doesn't work, as we create a fake node with worse state - return $this->missing; - } - - /** - * @inheritdoc - */ - public function isInDowntime() - { - if ($this->downtime === null) { - $this->getState(); - $this->downtime = $this->importedNode()->isInDowntime(); + if ($this->alias === null) { + $this->alias = $this->importedNode()->getAlias(); } - return $this->downtime; + return $this->alias; } - /** - * @inheritdoc - */ - public function isAcknowledged() + public function getOperator() { - if ($this->ack === null) { - $this->getState(); - $this->downtime = $this->importedNode()->isAcknowledged(); + if ($this->operator === null) { + $this->operator = $this->importedNode()->getOperator(); } - return $this->ack; + return $this->operator; + } + + public function getChildNames() + { + if ($this->childNames === null) { + $this->childNames = $this->importedNode()->getChildNames(); + } + + return $this->childNames; } /** @@ -137,68 +87,15 @@ class ImportedNode extends Node */ protected function importedNode() { - if ($this->node === null) { - $this->node = $this->loadImportedNode(); - } - - return $this->node; - } - - /** - * @return BpNode - */ - protected function loadImportedNode() - { - try { - $import = $this->importedConfig(); - - return $import->getNode($this->nodeName); - } catch (Exception $e) { - return $this->createFailedNode($e); - } - } - - protected function useAllRootNodes() - { - try { - $bp = $this->importedConfig(); - $this->node = new BpNode($bp, (object) array( - 'name' => $this->getName(), - 'operator' => '&', - 'child_names' => $bp->listRootNodes(), - )); - } catch (Exception $e) { - $this->createFailedNode($e); - } - } - - /** - * @return BpConfig - */ - protected function importedConfig() - { - if ($this->config === null) { - $import = $this->storage()->loadProcess($this->configName); - if ($this->bp->usesSoftStates()) { - $import->useSoftStates(); - } else { - $import->useHardStates(); + if ($this->importedNode === null) { + try { + $this->importedNode = $this->bp->getBpNode($this->nodeName); + } catch (Exception $e) { + return $this->createFailedNode($e); } - - $this->config = $import; } - return $this->config; - } - - /** - * @return LegacyStorage - */ - protected function storage() - { - return new LegacyStorage( - Config::module('businessprocess')->getSection('global') - ); + return $this->importedNode; } /** @@ -208,11 +105,11 @@ class ImportedNode extends Node */ protected function createFailedNode(Exception $e) { - $this->bp->addError($e->getMessage()); - $node = new BpNode($this->importedConfig(), (object) array( + $this->parentBp->addError($e->getMessage()); + $node = new BpNode($this->bp, (object) array( 'name' => $this->getName(), 'operator' => '&', - 'child_names' => array() + 'child_names' => [] )); $node->setState(2); $node->setMissing(false) @@ -222,21 +119,4 @@ class ImportedNode extends Node return $node; } - - /** - * @inheritdoc - */ - public function getLink() - { - return Html::tag( - 'a', - [ - 'href' => Url::fromPath('businessprocess/process/show', [ - 'config' => $this->configName, - 'node' => $this->nodeName - ]) - ], - $this->getAlias() - ); - } } diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index 05d1a2d..5e2d58b 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -356,6 +356,14 @@ abstract class Node return $paths; } + /** + * @return BpConfig + */ + public function getBusinessProcess() + { + return $this->bp; + } + protected function stateToSortState($state) { if (array_key_exists($state, $this->stateToSortStateMap)) { diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index c2e30ac..63e4cce 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -119,24 +119,19 @@ class NodeTile extends BaseHtmlElement protected function buildBaseNodeUrl(Node $node) { $path = $this->path; - $name = $this->name; // TODO: ?? $renderer = $this->renderer; - $bp = $renderer->getBusinessProcess(); - $params = array( - 'config' => $node instanceof ImportedNode ? - $node->getConfigName() : - $bp->getName() - ); - - if ($name !== null) { - $params['node'] = $name; - } + $params = [ + 'config' => $node->getBusinessProcess()->getName(), + 'node' => $node instanceof ImportedNode + ? $node->getNodeName() + : $this->name + ]; $url = $renderer->getBaseUrl(); $p = $url->getParams(); $p->mergeValues($params); - if (! empty($path)) { + if (! empty($path) && !$node instanceof ImportedNode) { $p->addValues('path', $path); } @@ -186,7 +181,7 @@ class NodeTile extends BaseHtmlElement $link = Html::tag('a', ['href' => $url, 'data-base-target' => '_next'], $node->getHostname()); } else { $link = Html::tag('a', ['href' => $url], $node->getAlias()); - if ($node instanceof ImportedNode) { + if ($node->getBusinessProcess()->getName() !== $this->renderer->getBusinessProcess()->getName()) { $link->getAttributes()->add('data-base-target', '_next'); } else { $link->getAttributes()->add('data-base-target', '_self'); diff --git a/library/Businessprocess/Renderer/TreeRenderer.php b/library/Businessprocess/Renderer/TreeRenderer.php index 0280f5c..d2a89f6 100644 --- a/library/Businessprocess/Renderer/TreeRenderer.php +++ b/library/Businessprocess/Renderer/TreeRenderer.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Businessprocess\Renderer; use Icinga\Date\DateFormatter; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Web\Form\CsrfToken; use ipl\Html\BaseHtmlElement; @@ -185,7 +186,12 @@ class TreeRenderer extends Renderer ]), 'data-csrf-token' => CsrfToken::generate(), 'data-action-url' => $this->getUrl() - ->overwriteParams(['node' => (string) $node]) + ->overwriteParams([ + 'config' => $node->getBusinessProcess()->getName(), + 'node' => $node instanceof ImportedNode + ? $node->getNodeName() + : (string) $node + ]) ->getAbsoluteUrl() ]); $li->add($ul);