Properly integrate imported nodes

* Fixed navigation flow
* Full tree rendering
This commit is contained in:
Johannes Meyer 2019-01-28 08:50:42 +01:00
parent e4d802b709
commit 2123b41f83
6 changed files with 149 additions and 194 deletions

View file

@ -2,12 +2,15 @@
namespace Icinga\Module\Businessprocess; namespace Icinga\Module\Businessprocess;
use Exception;
use LogicException;
use Icinga\Application\Config;
use Icinga\Exception\IcingaException; use Icinga\Exception\IcingaException;
use Icinga\Exception\NotFoundError; use Icinga\Exception\NotFoundError;
use Icinga\Module\Businessprocess\Exception\NestingError; use Icinga\Module\Businessprocess\Exception\NestingError;
use Icinga\Module\Businessprocess\Modification\ProcessChanges; use Icinga\Module\Businessprocess\Modification\ProcessChanges;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
use Icinga\Module\Monitoring\Backend\MonitoringBackend; use Icinga\Module\Monitoring\Backend\MonitoringBackend;
use Exception;
class BpConfig class BpConfig
{ {
@ -81,6 +84,13 @@ class BpConfig
*/ */
protected $root_nodes = array(); protected $root_nodes = array();
/**
* Imported configs
*
* @var array
*/
protected $importedConfigs = [];
/** /**
* All host names { 'hostA' => true, ... } * All host names { 'hostA' => true, ... }
* *
@ -424,7 +434,17 @@ class BpConfig
public function hasNode($name) 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) public function hasRootNode($name)
@ -474,7 +494,14 @@ class BpConfig
public function listInvolvedHostNames() 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) 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); $params = (object) array('configName' => $config);
if ($name !== null) { if ($name !== null) {
$params->node = $name; $params->node = $name;
@ -524,6 +563,25 @@ class BpConfig
return $node; 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 * @param $name
* @return Node * @return Node
@ -537,6 +595,12 @@ class BpConfig
if (array_key_exists($name, $this->nodes)) { if (array_key_exists($name, $this->nodes)) {
return $this->nodes[$name]; 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: // Fallback: if it is a service, create an empty one:

View file

@ -52,8 +52,8 @@ class BpNode extends Node
{ {
$this->bp = $bp; $this->bp = $bp;
$this->name = $object->name; $this->name = $object->name;
$this->setOperator($object->operator); $this->operator = $object->operator;
$this->setChildNames($object->child_names); $this->childNames = $object->child_names;
} }
public function getStateSummary() public function getStateSummary()
@ -140,12 +140,12 @@ class BpNode extends Node
public function hasChild($name) public function hasChild($name)
{ {
return in_array($name, $this->childNames); return in_array($name, $this->getChildNames());
} }
public function removeChild($name) public function removeChild($name)
{ {
if (($key = array_search($name, $this->childNames)) !== false) { if (($key = array_search($name, $this->getChildNames())) !== false) {
unset($this->childNames[$key]); unset($this->childNames[$key]);
if (! empty($this->children)) { if (! empty($this->children)) {
@ -276,7 +276,7 @@ class BpNode extends Node
public function hasAlias() public function hasAlias()
{ {
return $this->alias !== null; return $this->getAlias() !== null;
} }
public function getAlias() public function getAlias()
@ -357,7 +357,7 @@ class BpNode extends Node
$this->setLastStateChange($lastStateChange); $this->setLastStateChange($lastStateChange);
switch ($this->operator) { switch ($this->getOperator()) {
case self::OP_AND: case self::OP_AND:
$sort_state = max($sort_states); $sort_state = max($sort_states);
break; break;
@ -438,7 +438,8 @@ class BpNode extends Node
public function hasChildren($filter = null) public function hasChildren($filter = null)
{ {
return !empty($this->childNames); $childNames = $this->getChildNames();
return !empty($childNames);
} }
public function getChildNames() public function getChildNames()
@ -451,10 +452,11 @@ class BpNode extends Node
if ($this->children === null) { if ($this->children === null) {
$this->children = array(); $this->children = array();
if (! $this->bp->getMetadata()->isManuallyOrdered()) { if (! $this->bp->getMetadata()->isManuallyOrdered()) {
natcasesort($this->childNames); $childNames = $this->getChildNames();
$this->childNames = array_values($this->childNames); 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] = $this->bp->getNode($name);
$this->children[$name]->addParent($this); $this->children[$name]->addParent($this);
} }
@ -497,14 +499,14 @@ class BpNode extends Node
protected function assertNumericOperator() protected function assertNumericOperator()
{ {
if (! is_numeric($this->operator)) { if (! is_numeric($this->getOperator())) {
throw new ConfigurationError('Got invalid operator: %s', $this->operator); throw new ConfigurationError('Got invalid operator: %s', $this->operator);
} }
} }
public function operatorHtml() public function operatorHtml()
{ {
switch ($this->operator) { switch ($this->getOperator()) {
case self::OP_AND: case self::OP_AND:
return 'AND'; return 'AND';
break; break;

View file

@ -2,15 +2,13 @@
namespace Icinga\Module\Businessprocess; namespace Icinga\Module\Businessprocess;
use Icinga\Application\Config;
use Icinga\Module\Businessprocess\State\MonitoringState;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
use Exception; use Exception;
use Icinga\Web\Url;
use ipl\Html\Html;
class ImportedNode extends Node class ImportedNode extends BpNode
{ {
/** @var BpConfig */
protected $parentBp;
/** @var string */ /** @var string */
protected $configName; protected $configName;
@ -18,38 +16,27 @@ class ImportedNode extends Node
protected $nodeName; protected $nodeName;
/** @var BpNode */ /** @var BpNode */
private $node; protected $importedNode;
protected $className = 'subtree'; /** @var string */
protected $className = 'process subtree';
/** @var string */
protected $icon = 'download'; protected $icon = 'download';
/** @var BpConfig */
private $config;
/**
* @inheritdoc
*/
public function __construct(BpConfig $bp, $object) public function __construct(BpConfig $bp, $object)
{ {
$this->bp = $bp; $this->parentBp = $bp;
$this->configName = $object->configName; $this->configName = $object->configName;
$this->name = '@' . $object->configName; $this->nodeName = $object->node;
if (property_exists($object, 'node')) {
$this->nodeName = $object->node;
$this->name .= ':' . $object->node;
} else {
$this->useAllRootNodes();
}
if (isset($object->state)) { $importedConfig = $bp->getImportedConfig($this->configName);
$this->setState($object->state); parent::__construct($importedConfig, (object) [
} 'name' => '@' . $this->configName . ':' . $this->nodeName,
} 'operator' => null,
'child_names' => null
public function hasNode() ]
{ );
return $this->nodeName !== null;
} }
/** /**
@ -61,75 +48,38 @@ class ImportedNode extends Node
} }
/** /**
* @inheritdoc * @return string
*/ */
public function getState() public function getNodeName()
{ {
if ($this->state === null) { return $this->nodeName;
try {
MonitoringState::apply($this->importedConfig());
} catch (Exception $e) {
}
$this->state = $this->importedNode()->getState();
$this->setMissing(false);
}
return $this->state;
} }
/**
* @inheritdoc
*/
public function getAlias() public function getAlias()
{ {
return $this->importedNode()->getAlias(); if ($this->alias === null) {
} $this->alias = $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();
} }
return $this->downtime; return $this->alias;
} }
/** public function getOperator()
* @inheritdoc
*/
public function isAcknowledged()
{ {
if ($this->ack === null) { if ($this->operator === null) {
$this->getState(); $this->operator = $this->importedNode()->getOperator();
$this->downtime = $this->importedNode()->isAcknowledged();
} }
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() protected function importedNode()
{ {
if ($this->node === null) { if ($this->importedNode === null) {
$this->node = $this->loadImportedNode(); try {
} $this->importedNode = $this->bp->getBpNode($this->nodeName);
} catch (Exception $e) {
return $this->node; return $this->createFailedNode($e);
}
/**
* @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();
} }
$this->config = $import;
} }
return $this->config; return $this->importedNode;
}
/**
* @return LegacyStorage
*/
protected function storage()
{
return new LegacyStorage(
Config::module('businessprocess')->getSection('global')
);
} }
/** /**
@ -208,11 +105,11 @@ class ImportedNode extends Node
*/ */
protected function createFailedNode(Exception $e) protected function createFailedNode(Exception $e)
{ {
$this->bp->addError($e->getMessage()); $this->parentBp->addError($e->getMessage());
$node = new BpNode($this->importedConfig(), (object) array( $node = new BpNode($this->bp, (object) array(
'name' => $this->getName(), 'name' => $this->getName(),
'operator' => '&', 'operator' => '&',
'child_names' => array() 'child_names' => []
)); ));
$node->setState(2); $node->setState(2);
$node->setMissing(false) $node->setMissing(false)
@ -222,21 +119,4 @@ class ImportedNode extends Node
return $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()
);
}
} }

View file

@ -356,6 +356,14 @@ abstract class Node
return $paths; return $paths;
} }
/**
* @return BpConfig
*/
public function getBusinessProcess()
{
return $this->bp;
}
protected function stateToSortState($state) protected function stateToSortState($state)
{ {
if (array_key_exists($state, $this->stateToSortStateMap)) { if (array_key_exists($state, $this->stateToSortStateMap)) {

View file

@ -119,24 +119,19 @@ class NodeTile extends BaseHtmlElement
protected function buildBaseNodeUrl(Node $node) protected function buildBaseNodeUrl(Node $node)
{ {
$path = $this->path; $path = $this->path;
$name = $this->name; // TODO: ??
$renderer = $this->renderer; $renderer = $this->renderer;
$bp = $renderer->getBusinessProcess(); $params = [
$params = array( 'config' => $node->getBusinessProcess()->getName(),
'config' => $node instanceof ImportedNode ? 'node' => $node instanceof ImportedNode
$node->getConfigName() : ? $node->getNodeName()
$bp->getName() : $this->name
); ];
if ($name !== null) {
$params['node'] = $name;
}
$url = $renderer->getBaseUrl(); $url = $renderer->getBaseUrl();
$p = $url->getParams(); $p = $url->getParams();
$p->mergeValues($params); $p->mergeValues($params);
if (! empty($path)) { if (! empty($path) && !$node instanceof ImportedNode) {
$p->addValues('path', $path); $p->addValues('path', $path);
} }
@ -186,7 +181,7 @@ class NodeTile extends BaseHtmlElement
$link = Html::tag('a', ['href' => $url, 'data-base-target' => '_next'], $node->getHostname()); $link = Html::tag('a', ['href' => $url, 'data-base-target' => '_next'], $node->getHostname());
} else { } else {
$link = Html::tag('a', ['href' => $url], $node->getAlias()); $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'); $link->getAttributes()->add('data-base-target', '_next');
} else { } else {
$link->getAttributes()->add('data-base-target', '_self'); $link->getAttributes()->add('data-base-target', '_self');

View file

@ -5,6 +5,7 @@ namespace Icinga\Module\Businessprocess\Renderer;
use Icinga\Date\DateFormatter; use Icinga\Date\DateFormatter;
use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\ImportedNode;
use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Node;
use Icinga\Module\Businessprocess\Web\Form\CsrfToken; use Icinga\Module\Businessprocess\Web\Form\CsrfToken;
use ipl\Html\BaseHtmlElement; use ipl\Html\BaseHtmlElement;
@ -185,7 +186,12 @@ class TreeRenderer extends Renderer
]), ]),
'data-csrf-token' => CsrfToken::generate(), 'data-csrf-token' => CsrfToken::generate(),
'data-action-url' => $this->getUrl() 'data-action-url' => $this->getUrl()
->overwriteParams(['node' => (string) $node]) ->overwriteParams([
'config' => $node->getBusinessProcess()->getName(),
'node' => $node instanceof ImportedNode
? $node->getNodeName()
: (string) $node
])
->getAbsoluteUrl() ->getAbsoluteUrl()
]); ]);
$li->add($ul); $li->add($ul);