storage = $storage; return $this; } /** * Set the affected configuration * * @param BpConfig $bp * * @return $this */ public function setProcess(BpConfig $bp): self { $this->bp = $bp; return $this; } /** * Set the affected sub-process * * @param ?BpNode $node * * @return $this */ public function setParentNode(BpNode $node = null): self { $this->parent = $node; return $this; } /** * Set the user's session * * @param SessionNamespace $session * * @return $this */ public function setSession(SessionNamespace $session): self { $this->session = $session; return $this; } protected function assemble() { if ($this->parent !== null) { $title = sprintf($this->translate('Add a node to %s'), $this->parent->getAlias()); $nodeTypes = [ 'host' => $this->translate('Host'), 'service' => $this->translate('Service'), 'process' => $this->translate('Existing Process'), 'new-process' => $this->translate('New Process') ]; } else { $title = $this->translate('Add a new root node'); if (! $this->bp->isEmpty()) { $nodeTypes = [ 'process' => $this->translate('Existing Process'), 'new-process' => $this->translate('New Process') ]; } else { $nodeTypes = []; } } $this->addHtml(new HtmlElement('h2', null, Text::create($title))); if (! empty($nodeTypes)) { $this->addElement('select', 'node_type', [ 'label' => $this->translate('Node type'), 'options' => array_merge( ['' => ' - ' . $this->translate('Please choose') . ' - '], $nodeTypes ), 'disabledOptions' => [''], 'class' => 'autosubmit', 'required' => true, 'ignore' => true ]); $nodeType = $this->getPopulatedValue('node_type'); } else { $nodeType = 'new-process'; } if ($nodeType === 'new-process') { $this->assembleNewProcessElements(); } elseif ($nodeType === 'process') { $this->assembleExistingProcessElements(); } elseif ($nodeType === 'host') { $this->assembleHostElements(); } elseif ($nodeType === 'service') { $this->assembleServiceElements(); } $this->addElement('submit', 'submit', [ 'label' => $this->translate('Add Process') ]); } protected function assembleNewProcessElements(): void { $this->addElement('text', 'name', [ 'required' => true, 'ignore' => true, 'label' => $this->translate('ID'), 'description' => $this->translate('This is the unique identifier of this process'), 'validators' => [ 'callback' => function ($value, $validator) { if ($this->parent !== null ? $this->parent->hasChild($value) : $this->bp->hasRootNode($value)) { $validator->addMessage( sprintf($this->translate('%s is already defined in this process'), $value) ); return false; } return true; } ] ]); $this->addElement('text', 'alias', [ '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', [ 'required' => true, 'label' => $this->translate('Operator'), 'multiOptions' => Node::getOperators() ]); $display = 1; if (! $this->bp->isEmpty() && $this->bp->getMetadata()->isManuallyOrdered()) { $rootNodes = self::applyManualSorting($this->bp->getRootNodes()); $display = end($rootNodes)->getDisplay() + 1; } $this->addElement('select', 'display', [ 'required' => true, 'label' => $this->translate('Visualization'), 'description' => $this->translate('Where to show this process'), 'value' => $this->parent !== null ? '0' : "$display", 'multiOptions' => [ "$display" => $this->translate('Toplevel Process'), '0' => $this->translate('Subprocess only'), ] ]); $this->addElement('text', 'infoUrl', [ 'label' => $this->translate('Info URL'), 'description' => $this->translate('URL pointing to more information about this node') ]); } protected function assembleExistingProcessElements(): void { $termValidator = function (array $terms) { foreach ($terms as $term) { /** @var TermInput\ValidatedTerm $term */ $nodeName = $term->getSearchValue(); if ($nodeName[0] === '@') { if ($this->parent === null) { $term->setMessage($this->translate('Imported nodes cannot be used as root nodes')); } elseif (strpos($nodeName, ':') === false) { $term->setMessage($this->translate('Missing node name')); } else { [$config, $nodeName] = Str::trimSplit(substr($nodeName, 1), ':', 2); if (! $this->storage->hasProcess($config)) { $term->setMessage($this->translate('Config does not exist or access has been denied')); } else { try { $bp = $this->storage->loadProcess($config); } catch (Exception $e) { $term->setMessage( sprintf($this->translate('Cannot load config: %s'), $e->getMessage()) ); } if (isset($bp)) { if (! $bp->hasNode($nodeName)) { $term->setMessage($this->translate('No node with this name found in config')); } else { $term->setLabel($bp->getNode($nodeName)->getAlias()); } } } } } elseif (! $this->bp->hasNode($nodeName)) { $term->setMessage($this->translate('No node with this name found in config')); } else { $term->setLabel($this->bp->getNode($nodeName)->getAlias()); } if ($this->parent !== null && $this->parent->hasChild($term->getSearchValue())) { $term->setMessage($this->translate('Already defined in this process')); } if ($this->parent !== null && $term->getSearchValue() === $this->parent->getName()) { $term->setMessage($this->translate('Results in a parent/child loop')); } } }; $this->addElement( (new TermInput('children')) ->setRequired() ->setVerticalTermDirection() ->setLabel($this->translate('Process Nodes')) ->setSuggestionUrl(Url::fromPath('businessprocess/suggestions/process', [ 'node' => isset($this->parent) ? $this->parent->getName() : null, 'config' => $this->bp->getName(), 'showCompact' => true, '_disableLayout' => true ])) ->on(TermInput::ON_ENRICH, $termValidator) ->on(TermInput::ON_ADD, $termValidator) ->on(TermInput::ON_PASTE, $termValidator) ->on(TermInput::ON_SAVE, $termValidator) ); } protected function assembleHostElements(): void { if ($this->bp->getBackend() instanceof MonitoringBackend) { $suggestionsPath = 'businessprocess/suggestions/monitoring-host'; } else { $suggestionsPath = 'businessprocess/suggestions/icingadb-host'; } $this->addElement($this->createChildrenElementForObjects( $this->translate('Hosts'), $suggestionsPath )); $this->addElement('checkbox', 'host_override', [ 'ignore' => true, 'class' => 'autosubmit', 'label' => $this->translate('Override Host State') ]); if ($this->getPopulatedValue('host_override') === 'y') { $this->addElement(new IplStateOverrides('stateOverrides', [ 'label' => $this->translate('State Overrides'), 'options' => [ 0 => $this->translate('UP'), 1 => $this->translate('DOWN'), 99 => $this->translate('PENDING') ] ])); } } protected function assembleServiceElements(): void { if ($this->bp->getBackend() instanceof MonitoringBackend) { $suggestionsPath = 'businessprocess/suggestions/monitoring-service'; } else { $suggestionsPath = 'businessprocess/suggestions/icingadb-service'; } $this->addElement($this->createChildrenElementForObjects( $this->translate('Services'), $suggestionsPath )); $this->addElement('checkbox', 'service_override', [ 'ignore' => true, 'class' => 'autosubmit', 'label' => $this->translate('Override Service State') ]); if ($this->getPopulatedValue('service_override') === 'y') { $this->addElement(new IplStateOverrides('stateOverrides', [ 'label' => $this->translate('State Overrides'), 'options' => [ 0 => $this->translate('OK'), 1 => $this->translate('WARNING'), 2 => $this->translate('CRITICAL'), 3 => $this->translate('UNKNOWN'), 99 => $this->translate('PENDING'), ] ])); } } protected function createChildrenElementForObjects(string $label, string $suggestionsPath): TermInput { $termValidator = function (array $terms) { (new HostServiceTermValidator()) ->setParent($this->parent) ->isValid($terms); }; return (new TermInput('children')) ->setRequired() ->setLabel($label) ->setVerticalTermDirection() ->setSuggestionUrl(Url::fromPath($suggestionsPath, [ 'node' => isset($this->parent) ? $this->parent->getName() : null, 'config' => $this->bp->getName(), 'showCompact' => true, '_disableLayout' => true ])) ->on(TermInput::ON_ENRICH, $termValidator) ->on(TermInput::ON_ADD, $termValidator) ->on(TermInput::ON_PASTE, $termValidator) ->on(TermInput::ON_SAVE, $termValidator); } protected function onSuccess() { $changes = ProcessChanges::construct($this->bp, $this->session); $nodeType = $this->getValue('node_type'); if (! $nodeType || $nodeType === 'new-process') { $properties = $this->getValues(); if (! $properties['alias']) { unset($properties['alias']); } if ($this->parent !== null) { $properties['parentName'] = $this->parent->getName(); } $changes->createNode(BpConfig::escapeName($this->getValue('name')), $properties); } else { /** @var TermInput $term */ $term = $this->getElement('children'); $children = array_unique(array_map(function ($term) { return $term->getSearchValue(); }, $term->getTerms())); if ($nodeType === 'host' || $nodeType === 'service') { $stateOverrides = $this->getValue('stateOverrides'); if (! empty($stateOverrides)) { $childOverrides = []; foreach ($children as $nodeName) { $childOverrides[$nodeName] = $stateOverrides; } $changes->modifyNode($this->parent, [ 'stateOverrides' => array_merge($this->parent->getStateOverrides(), $childOverrides) ]); } } if ($this->parent !== null) { $changes->addChildrenToNode($children, $this->parent); } else { foreach ($children as $nodeName) { $changes->copyNode($nodeName); } } } unset($changes); } }