diff options
Diffstat (limited to 'application/forms/AddNodeForm.php')
-rw-r--r-- | application/forms/AddNodeForm.php | 579 |
1 files changed, 579 insertions, 0 deletions
diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php new file mode 100644 index 0000000..43afa4c --- /dev/null +++ b/application/forms/AddNodeForm.php @@ -0,0 +1,579 @@ +<?php + +namespace Icinga\Module\Businessprocess\Forms; + +use Icinga\Module\Businessprocess\BpNode; +use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\Common\EnumList; +use Icinga\Module\Businessprocess\ImportedNode; +use Icinga\Module\Businessprocess\Modification\ProcessChanges; +use Icinga\Module\Businessprocess\Storage\Storage; +use Icinga\Module\Businessprocess\Web\Form\QuickForm; +use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator; +use Icinga\Module\Monitoring\Backend\MonitoringBackend; +use Icinga\Web\Session\SessionNamespace; +use ipl\Sql\Connection as IcingaDbConnection; + +class AddNodeForm extends QuickForm +{ + use EnumList; + + /** @var MonitoringBackend|IcingaDbConnection*/ + protected $backend; + + /** @var Storage */ + protected $storage; + + /** @var BpConfig */ + protected $bp; + + /** @var BpNode */ + protected $parent; + + protected $objectList = array(); + + protected $processList = array(); + + /** @var SessionNamespace */ + protected $session; + + public function setup() + { + $view = $this->getView(); + if ($this->hasParentNode()) { + $this->addHtml( + '<h2>' . $view->escape( + sprintf($this->translate('Add a node to %s'), $this->parent->getAlias()) + ) . '</h2>' + ); + } else { + $this->addHtml( + '<h2>' . $this->translate('Add a new root node') . '</h2>' + ); + } + + $type = $this->selectNodeType(); + switch ($type) { + case 'host': + $this->selectHost(); + break; + case 'service': + $this->selectService(); + break; + case 'process': + $this->selectProcess(); + break; + case 'new-process': + $this->addNewProcess(); + break; + case 'hosts_from_filter': + $this->selectHostsFromFilter(); + break; + case 'services_from_filter': + $this->selectServicesFromFilter(); + break; + case null: + $this->setSubmitLabel($this->translate('Next')); + return; + } + } + + protected function addNewProcess() + { + $this->addElement('text', 'name', array( + 'label' => $this->translate('ID'), + 'required' => true, + 'description' => $this->translate( + 'This is the unique identifier of this process' + ), + 'validators' => [ + ['Callback', true, [ + 'callback' => function ($value) { + if ($this->hasParentNode()) { + return ! $this->parent->hasChild($value); + } + + return ! $this->bp->hasRootNode($value); + }, + 'messages' => [ + 'callbackValue' => $this->translate('%value% is already defined in this process') + ] + ]] + ] + )); + + $this->addElement('text', 'alias', array( + 'label' => $this->translate('Display Name'), + 'description' => $this->translate( + 'Usually this name will be shown for this node. Equals ID' + . ' if not given' + ), + )); + + $this->addElement('select', 'operator', array( + 'label' => $this->translate('Operator'), + 'required' => true, + 'multiOptions' => array( + '&' => $this->translate('AND'), + '|' => $this->translate('OR'), + '!' => $this->translate('NOT'), + '%' => $this->translate('DEGRADED'), + '1' => $this->translate('MIN 1'), + '2' => $this->translate('MIN 2'), + '3' => $this->translate('MIN 3'), + '4' => $this->translate('MIN 4'), + '5' => $this->translate('MIN 5'), + '6' => $this->translate('MIN 6'), + '7' => $this->translate('MIN 7'), + '8' => $this->translate('MIN 8'), + '9' => $this->translate('MIN 9'), + ) + )); + + $display = 1; + if ($this->bp->getMetadata()->isManuallyOrdered() && !$this->bp->isEmpty()) { + $rootNodes = $this->bp->getRootNodes(); + $display = end($rootNodes)->getDisplay() + 1; + } + $this->addElement('select', 'display', array( + 'label' => $this->translate('Visualization'), + 'required' => true, + 'description' => $this->translate( + 'Where to show this process' + ), + 'value' => $this->hasParentNode() ? '0' : "$display", + 'multiOptions' => array( + "$display" => $this->translate('Toplevel Process'), + '0' => $this->translate('Subprocess only'), + ) + )); + + $this->addElement('text', 'infoUrl', array( + 'label' => $this->translate('Info URL'), + 'description' => $this->translate( + 'URL pointing to more information about this node' + ) + )); + } + + /** + * @return string|null + */ + protected function selectNodeType() + { + $types = array(); + if ($this->hasParentNode()) { + $types['host'] = $this->translate('Host'); + $types['service'] = $this->translate('Service'); + $types['hosts_from_filter'] = $this->translate('Hosts from filter'); + $types['services_from_filter'] = $this->translate('Services from filter'); + } elseif (! $this->hasProcesses()) { + $this->addElement('hidden', 'node_type', array( + 'ignore' => true, + 'decorators' => array('ViewHelper'), + 'value' => 'new-process' + )); + + return 'new-process'; + } + + if ($this->hasProcesses() || ($this->hasParentNode() && $this->hasMoreConfigs())) { + $types['process'] = $this->translate('Existing Process'); + } + + $types['new-process'] = $this->translate('New Process Node'); + + $this->addElement('select', 'node_type', array( + 'label' => $this->translate('Node type'), + 'required' => true, + 'description' => $this->translate( + 'The node type you want to add' + ), + 'ignore' => true, + 'class' => 'autosubmit', + 'multiOptions' => $this->optionalEnum($types) + )); + + return $this->getSentValue('node_type'); + } + + protected function selectHost() + { + $this->addElement('multiselect', 'children', [ + 'label' => $this->translate('Hosts'), + 'required' => true, + 'size' => 8, + 'style' => 'width: 25em', + 'multiOptions' => $this->enumHostList(), + 'description' => $this->translate( + 'Hosts that should be part of this business process node' + ), + 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] + ]); + + $this->addHostOverrideCheckbox(); + if ($this->getSentValue('host_override') === '1') { + $this->addHostOverrideElement(); + } + } + + protected function selectService() + { + $this->addHostElement(); + if ($host = $this->getSentValue('host')) { + $this->addServicesElement($host); + $this->addServiceOverrideCheckbox(); + + if ($this->getSentValue('service_override') === '1') { + $this->addServiceOverrideElement(); + } + } else { + $this->setSubmitLabel($this->translate('Next')); + } + } + + protected function addHostElement() + { + $this->addElement('select', 'host', array( + 'label' => $this->translate('Host'), + 'required' => true, + 'ignore' => true, + 'class' => 'autosubmit', + 'multiOptions' => $this->optionalEnum($this->enumHostForServiceList()), + )); + } + + protected function addServicesElement($host) + { + $this->addElement('multiselect', 'children', [ + 'label' => $this->translate('Services'), + 'required' => true, + 'size' => 8, + 'style' => 'width: 25em', + 'multiOptions' => $this->enumServiceList($host), + 'description' => $this->translate( + 'Services that should be part of this business process node' + ), + 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] + ]); + } + + protected function addFilteredHostsElement($filter) + { + $this->addElement('submit', 'refresh', [ + 'label' => $this->translate('Refresh'), + 'class' => 'refresh-filter' + ]); + $this->addElement('multiselect', 'children', [ + 'label' => $this->translate('Hosts'), + 'required' => true, + 'size' => 8, + 'style' => 'width: 25em', + 'multiOptions' => $this->enumHostListByFilter($filter), + 'description' => $this->translate( + 'Hosts that should be part of this business process node' + ), + 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] + ]); + } + + protected function addFilteredServicesElement($filter) + { + $this->addElement('submit', 'refresh', [ + 'label' => $this->translate('Refresh'), + 'class' => 'refresh-filter' + ]); + $this->addElement('multiselect', 'children', [ + 'label' => $this->translate('Services'), + 'required' => true, + 'size' => 8, + 'style' => 'width: 25em', + 'multiOptions' => $this->enumServiceListByFilter($filter), + 'description' => $this->translate( + 'Services that should be part of this business process node' + ), + 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] + ]); + } + + protected function addFilterElement() + { + $this->addElement('text', 'filter', array( + 'label' => $this->translate('Filter'), + 'required' => true, + 'ignore' => true + )); + } + + protected function addFileElement() + { + $this->addElement('select', 'file', [ + 'label' => $this->translate('File'), + 'required' => true, + 'ignore' => true, + 'value' => $this->bp->getName(), + 'class' => 'autosubmit', + 'multiOptions' => $this->optionalEnum($this->enumConfigs()), + 'description' => $this->translate( + 'Choose a different configuration file to import its processes' + ) + ]); + } + + protected function addHostOverrideCheckbox() + { + $this->addElement('checkbox', 'host_override', [ + 'ignore' => true, + 'class' => 'autosubmit', + 'label' => $this->translate('Override Host State'), + 'description' => $this->translate('Enable host state overrides') + ]); + } + + protected function addHostOverrideElement() + { + $this->addElement('stateOverrides', 'stateOverrides', [ + 'required' => true, + 'label' => $this->translate('State Overrides'), + 'states' => $this->enumHostStateList() + ]); + } + + protected function addServiceOverrideCheckbox() + { + $this->addElement('checkbox', 'service_override', [ + 'ignore' => true, + 'class' => 'autosubmit', + 'label' => $this->translate('Override Service State'), + 'description' => $this->translate('Enable service state overrides') + ]); + } + + protected function addServiceOverrideElement() + { + $this->addElement('stateOverrides', 'stateOverrides', [ + 'required' => true, + 'label' => $this->translate('State Overrides'), + 'states' => $this->enumServiceStateList() + ]); + } + + protected function selectHostsFromFilter() + { + $this->addFilterElement(); + if ($filter = $this->getSentValue('filter')) { + $this->addFilteredHostsElement($filter); + } else { + $this->setSubmitLabel($this->translate('Next')); + } + } + + protected function selectServicesFromFilter() + { + $this->addFilterElement(); + if ($filter = $this->getSentValue('filter')) { + $this->addFilteredServicesElement($filter); + } else { + $this->setSubmitLabel($this->translate('Next')); + } + } + + protected function selectProcess() + { + if ($this->hasParentNode()) { + $this->addFileElement(); + } + + if (($file = $this->getSentValue('file')) || !$this->hasParentNode()) { + $this->addElement('multiselect', 'children', [ + 'label' => $this->translate('Process nodes'), + 'required' => true, + 'size' => 8, + 'style' => 'width: 25em', + 'multiOptions' => $this->enumProcesses($file), + 'description' => $this->translate( + 'Other processes that should be part of this business process node' + ), + 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] + ]); + } else { + $this->setSubmitLabel($this->translate('Next')); + } + } + + /** + * @param MonitoringBackend|IcingaDbConnection $backend + * @return $this + */ + public function setBackend($backend) + { + $this->backend = $backend; + return $this; + } + + /** + * @param Storage $storage + * @return $this + */ + public function setStorage(Storage $storage) + { + $this->storage = $storage; + return $this; + } + + /** + * @param BpConfig $process + * @return $this + */ + public function setProcess(BpConfig $process) + { + $this->bp = $process; + $this->setBackend($process->getBackend()); + return $this; + } + + /** + * @param BpNode|null $node + * @return $this + */ + public function setParentNode(BpNode $node = null) + { + $this->parent = $node; + return $this; + } + + /** + * @return bool + */ + public function hasParentNode() + { + return $this->parent !== null; + } + + /** + * @param SessionNamespace $session + * @return $this + */ + public function setSession(SessionNamespace $session) + { + $this->session = $session; + return $this; + } + + protected function hasProcesses() + { + return count($this->enumProcesses()) > 0; + } + + /** + * @param string $file + * @return array + */ + protected function enumProcesses($file = null) + { + $list = array(); + + $parents = array(); + + $differentFile = $file !== null && $file !== $this->bp->getName(); + + if (! $differentFile && $this->hasParentNode()) { + $this->collectAllParents($this->parent, $parents); + $parents[$this->parent->getName()] = $this->parent; + } + + $bp = $this->bp; + if ($differentFile) { + $bp = $this->storage->loadProcess($file); + } + + foreach ($bp->getNodes() as $node) { + if (! $node instanceof ImportedNode && $node instanceof BpNode && ! isset($parents[$node->getName()])) { + $name = $node->getName(); + if ($differentFile) { + $name = '@' . $file . ':' . $name; + } + + $list[$name] = $node->getName(); // display name? + } + } + + if (! $this->bp->getMetadata()->isManuallyOrdered()) { + natcasesort($list); + } + return $list; + } + + protected function hasMoreConfigs() + { + $configs = $this->enumConfigs(); + return !empty($configs); + } + + protected function enumConfigs() + { + return $this->storage->listProcesses(); + } + + /** + * Collect the given node's parents recursively into the given array by their names + * + * @param BpNode $node + * @param BpNode[] $parents + */ + protected function collectAllParents(BpNode $node, array &$parents) + { + foreach ($node->getParents() as $parent) { + $parents[$parent->getName()] = $parent; + $this->collectAllParents($parent, $parents); + } + } + + public function onSuccess() + { + $changes = ProcessChanges::construct($this->bp, $this->session); + switch ($this->getValue('node_type')) { + case 'host': + case 'service': + $stateOverrides = $this->getValue('stateOverrides'); + if (! empty($stateOverrides)) { + $childOverrides = []; + foreach ($this->getValue('children') as $service) { + $childOverrides[$service] = $stateOverrides; + } + + $changes->modifyNode($this->parent, [ + 'stateOverrides' => array_merge($this->parent->getStateOverrides(), $childOverrides) + ]); + } + + // Fallthrough + case 'process': + case 'hosts_from_filter': + case 'services_from_filter': + if ($this->hasParentNode()) { + $changes->addChildrenToNode($this->getValue('children'), $this->parent); + } else { + foreach ($this->getValue('children') as $nodeName) { + $changes->copyNode($nodeName); + } + } + + break; + case 'new-process': + $properties = $this->getValues(); + unset($properties['name']); + if ($this->hasParentNode()) { + $properties['parentName'] = $this->parent->getName(); + } + $changes->createNode($this->getValue('name'), $properties); + break; + } + + // Trigger session destruction to make sure it get's stored. + // TODO: figure out why this is necessary, might be an unclean shutdown on redirect + unset($changes); + + parent::onSuccess(); + } +} |