mirror of
https://github.com/Icinga/icingaweb2-module-businessprocess.git
synced 2026-01-01 11:19:34 -05:00
Add auto completion (#387)
resolves #295 requires https://github.com/Icinga/ipl-web/pull/179 requires https://github.com/Icinga/ipl-web/pull/178
This commit is contained in:
commit
a30f85dbcc
18 changed files with 1321 additions and 1117 deletions
|
|
@ -6,6 +6,8 @@ use Icinga\Application\Modules\Module;
|
|||
use Icinga\Date\DateFormatter;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\Forms\AddNodeForm;
|
||||
use Icinga\Module\Businessprocess\Forms\EditNodeForm;
|
||||
use Icinga\Module\Businessprocess\Node;
|
||||
use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport;
|
||||
use Icinga\Module\Businessprocess\Renderer\Breadcrumb;
|
||||
|
|
@ -269,13 +271,25 @@ class ProcessController extends Controller
|
|||
$canEdit = $bp->getMetadata()->canModify();
|
||||
|
||||
if ($action === 'add' && $canEdit) {
|
||||
$form = $this->loadForm('AddNode')
|
||||
->setSuccessUrl(Url::fromRequest()->without('action'))
|
||||
->setStorage($this->storage())
|
||||
$form = (new AddNodeForm())
|
||||
->setProcess($bp)
|
||||
->setParentNode($node)
|
||||
->setStorage($this->storage())
|
||||
->setSession($this->session())
|
||||
->handleRequest();
|
||||
->on(AddNodeForm::ON_SUCCESS, function () {
|
||||
$this->redirectNow(Url::fromRequest()->without('action'));
|
||||
})
|
||||
->handleRequest($this->getServerRequest());
|
||||
|
||||
if ($form->hasElement('children')) {
|
||||
foreach ($form->getElement('children')->prepareMultipartUpdate($this->getServerRequest()) as $update) {
|
||||
if (! is_array($update)) {
|
||||
$update = [$update];
|
||||
}
|
||||
|
||||
$this->addPart(...$update);
|
||||
}
|
||||
}
|
||||
} elseif ($action === 'cleanup' && $canEdit) {
|
||||
$form = $this->loadForm('CleanupNode')
|
||||
->setSuccessUrl(Url::fromRequest()->without('action'))
|
||||
|
|
@ -283,13 +297,15 @@ class ProcessController extends Controller
|
|||
->setSession($this->session())
|
||||
->handleRequest();
|
||||
} elseif ($action === 'editmonitored' && $canEdit) {
|
||||
$form = $this->loadForm('EditNode')
|
||||
->setSuccessUrl(Url::fromRequest()->without('action'))
|
||||
$form = (new EditNodeForm())
|
||||
->setProcess($bp)
|
||||
->setNode($bp->getNode($this->params->get('editmonitorednode')))
|
||||
->setParentNode($node)
|
||||
->setSession($this->session())
|
||||
->handleRequest();
|
||||
->on(EditNodeForm::ON_SUCCESS, function () {
|
||||
$this->redirectNow(Url::fromRequest()->without(['action', 'editmonitorednode']));
|
||||
})
|
||||
->handleRequest($this->getServerRequest());
|
||||
} elseif ($action === 'delete' && $canEdit) {
|
||||
$form = $this->loadForm('DeleteNode')
|
||||
->setSuccessUrl(Url::fromRequest()->without('action'))
|
||||
|
|
@ -349,8 +365,11 @@ class ProcessController extends Controller
|
|||
return;
|
||||
}
|
||||
|
||||
if ($this->params->get('action')) {
|
||||
$this->setAutorefreshInterval(45);
|
||||
if ($this->params->has('action')) {
|
||||
if ($this->params->get('action') !== 'add') {
|
||||
// The new add form uses the term input, which doesn't support value persistence across refreshes
|
||||
$this->setAutorefreshInterval(45);
|
||||
}
|
||||
} else {
|
||||
$this->setAutorefreshInterval(10);
|
||||
}
|
||||
|
|
|
|||
372
application/controllers/SuggestionsController.php
Normal file
372
application/controllers/SuggestionsController.php
Normal file
|
|
@ -0,0 +1,372 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Data\Filter\Filter as LegacyFilter;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\HostNode;
|
||||
use Icinga\Module\Businessprocess\IcingaDbObject;
|
||||
use Icinga\Module\Businessprocess\ImportedNode;
|
||||
use Icinga\Module\Businessprocess\Monitoring\DataView\HostStatus;
|
||||
use Icinga\Module\Businessprocess\Monitoring\DataView\ServiceStatus;
|
||||
use Icinga\Module\Businessprocess\MonitoringRestrictions;
|
||||
use Icinga\Module\Businessprocess\ServiceNode;
|
||||
use Icinga\Module\Businessprocess\Web\Controller;
|
||||
use Icinga\Module\Icingadb\Model\Host;
|
||||
use Icinga\Module\Icingadb\Model\Service;
|
||||
use ipl\Stdlib\Filter;
|
||||
use ipl\Web\FormElement\TermInput\TermSuggestions;
|
||||
|
||||
class SuggestionsController extends Controller
|
||||
{
|
||||
public function processAction()
|
||||
{
|
||||
$ignoreList = [];
|
||||
$forConfig = null;
|
||||
$forParent = null;
|
||||
if ($this->params->has('config')) {
|
||||
$forConfig = $this->loadModifiedBpConfig();
|
||||
|
||||
$parentName = $this->params->get('node');
|
||||
if ($parentName) {
|
||||
$forParent = $forConfig->getBpNode($parentName);
|
||||
|
||||
$collectParents = function ($node) use ($ignoreList, &$collectParents) {
|
||||
foreach ($node->getParents() as $parent) {
|
||||
$ignoreList[$parent->getName()] = true;
|
||||
|
||||
if ($parent->hasParents()) {
|
||||
$collectParents($parent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$ignoreList[$parentName] = true;
|
||||
if ($forParent->hasParents()) {
|
||||
$collectParents($forParent);
|
||||
}
|
||||
|
||||
foreach ($forParent->getChildNames() as $name) {
|
||||
$ignoreList[$name] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions = new TermSuggestions((function () use ($forConfig, $forParent, $ignoreList, &$suggestions) {
|
||||
foreach ($this->storage()->listProcessNames() as $config) {
|
||||
$differentConfig = false;
|
||||
if ($forConfig === null || $config !== $forConfig->getName()) {
|
||||
if ($forConfig !== null && $forParent === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$bp = $this->storage()->loadProcess($config);
|
||||
} catch (Exception $_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$differentConfig = true;
|
||||
} else {
|
||||
$bp = $forConfig;
|
||||
}
|
||||
|
||||
foreach ($bp->getBpNodes() as $bpNode) {
|
||||
/** @var BpNode $bpNode */
|
||||
if ($bpNode instanceof ImportedNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$search = $bpNode->getName();
|
||||
if ($differentConfig) {
|
||||
$search = "@$config:$search";
|
||||
}
|
||||
|
||||
if (in_array($search, $suggestions->getExcludeTerms(), true)
|
||||
|| isset($ignoreList[$search])
|
||||
|| ($forParent
|
||||
? $forParent->hasChild($search)
|
||||
: ($forConfig && $forConfig->hasRootNode($search))
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($suggestions->matchSearch($bpNode->getName())
|
||||
|| (! $bpNode->hasAlias() || $suggestions->matchSearch($bpNode->getAlias()))
|
||||
|| $bpNode->getName() === $suggestions->getOriginalSearchValue()
|
||||
|| $bpNode->getAlias() === $suggestions->getOriginalSearchValue()
|
||||
) {
|
||||
yield [
|
||||
'search' => $search,
|
||||
'label' => $bpNode->getAlias() ?? $bpNode->getName(),
|
||||
'config' => $config
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
})());
|
||||
$suggestions->setGroupingCallback(function (array $data) {
|
||||
return $this->storage()->loadMetadata($data['config'])->getTitle();
|
||||
});
|
||||
|
||||
$this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest()));
|
||||
}
|
||||
|
||||
public function icingadbHostAction()
|
||||
{
|
||||
$excludes = Filter::none();
|
||||
$forConfig = null;
|
||||
if ($this->params->has('config')) {
|
||||
$forConfig = $this->loadModifiedBpConfig();
|
||||
|
||||
if ($this->params->has('node')) {
|
||||
$nodeName = $this->params->get('node');
|
||||
$node = $forConfig->getBpNode($nodeName);
|
||||
|
||||
foreach ($node->getChildren() as $child) {
|
||||
if ($child instanceof HostNode) {
|
||||
$excludes->add(Filter::equal('host.name', $child->getHostname()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions = new TermSuggestions((function () use ($forConfig, $excludes, &$suggestions) {
|
||||
foreach ($suggestions->getExcludeTerms() as $excludeTerm) {
|
||||
[$hostName, $_] = BpConfig::splitNodeName($excludeTerm);
|
||||
$excludes->add(Filter::equal('host.name', $hostName));
|
||||
}
|
||||
|
||||
$hosts = Host::on($forConfig->getBackend())
|
||||
->columns(['host.name', 'host.display_name'])
|
||||
->limit(50);
|
||||
IcingaDbObject::applyIcingaDbRestrictions($hosts);
|
||||
$hosts->filter(Filter::all(
|
||||
$excludes,
|
||||
Filter::any(
|
||||
Filter::like('host.name', $suggestions->getSearchTerm()),
|
||||
Filter::equal('host.name', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('host.display_name', $suggestions->getSearchTerm()),
|
||||
Filter::equal('host.display_name', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('host.address', $suggestions->getSearchTerm()),
|
||||
Filter::equal('host.address', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('host.address6', $suggestions->getSearchTerm()),
|
||||
Filter::equal('host.address6', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('host.customvar_flat.flatvalue', $suggestions->getSearchTerm()),
|
||||
Filter::equal('host.customvar_flat.flatvalue', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('hostgroup.name', $suggestions->getSearchTerm()),
|
||||
Filter::equal('hostgroup.name', $suggestions->getOriginalSearchValue())
|
||||
)
|
||||
));
|
||||
foreach ($hosts as $host) {
|
||||
yield [
|
||||
'search' => BpConfig::joinNodeName($host->name, 'Hoststatus'),
|
||||
'label' => $host->display_name,
|
||||
'class' => 'host'
|
||||
];
|
||||
}
|
||||
})());
|
||||
|
||||
$this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest()));
|
||||
}
|
||||
|
||||
public function icingadbServiceAction()
|
||||
{
|
||||
$excludes = Filter::none();
|
||||
$forConfig = null;
|
||||
if ($this->params->has('config')) {
|
||||
$forConfig = $this->loadModifiedBpConfig();
|
||||
|
||||
if ($this->params->has('node')) {
|
||||
$nodeName = $this->params->get('node');
|
||||
$node = $forConfig->getBpNode($nodeName);
|
||||
|
||||
foreach ($node->getChildren() as $child) {
|
||||
if ($child instanceof ServiceNode) {
|
||||
$excludes->add(Filter::all(
|
||||
Filter::equal('host.name', $child->getHostname()),
|
||||
Filter::equal('service.name', $child->getServiceDescription())
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions = new TermSuggestions((function () use ($forConfig, $excludes, &$suggestions) {
|
||||
foreach ($suggestions->getExcludeTerms() as $excludeTerm) {
|
||||
[$hostName, $serviceName] = BpConfig::splitNodeName($excludeTerm);
|
||||
if ($serviceName !== null && $serviceName !== 'Hoststatus') {
|
||||
$excludes->add(Filter::all(
|
||||
Filter::equal('host.name', $hostName),
|
||||
Filter::equal('service.name', $serviceName)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$services = Service::on($forConfig->getBackend())
|
||||
->columns(['host.name', 'host.display_name', 'service.name', 'service.display_name'])
|
||||
->limit(50);
|
||||
IcingaDbObject::applyIcingaDbRestrictions($services);
|
||||
$services->filter(Filter::all(
|
||||
$excludes,
|
||||
Filter::any(
|
||||
Filter::like('host.name', $suggestions->getSearchTerm()),
|
||||
Filter::equal('host.name', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('host.display_name', $suggestions->getSearchTerm()),
|
||||
Filter::equal('host.display_name', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('service.name', $suggestions->getSearchTerm()),
|
||||
Filter::equal('service.name', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('service.display_name', $suggestions->getSearchTerm()),
|
||||
Filter::equal('service.display_name', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('service.customvar_flat.flatvalue', $suggestions->getSearchTerm()),
|
||||
Filter::equal('service.customvar_flat.flatvalue', $suggestions->getOriginalSearchValue()),
|
||||
Filter::like('servicegroup.name', $suggestions->getSearchTerm()),
|
||||
Filter::equal('servicegroup.name', $suggestions->getOriginalSearchValue())
|
||||
)
|
||||
));
|
||||
foreach ($services as $service) {
|
||||
yield [
|
||||
'class' => 'service',
|
||||
'search' => BpConfig::joinNodeName($service->host->name, $service->name),
|
||||
'label' => sprintf(
|
||||
$this->translate('%s on %s', '<service> on <host>'),
|
||||
$service->display_name,
|
||||
$service->host->display_name
|
||||
)
|
||||
];
|
||||
}
|
||||
})());
|
||||
|
||||
$this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest()));
|
||||
}
|
||||
|
||||
public function monitoringHostAction()
|
||||
{
|
||||
$excludes = LegacyFilter::matchAny();
|
||||
$forConfig = null;
|
||||
if ($this->params->has('config')) {
|
||||
$forConfig = $this->loadModifiedBpConfig();
|
||||
|
||||
if ($this->params->has('node')) {
|
||||
$nodeName = $this->params->get('node');
|
||||
$node = $forConfig->getBpNode($nodeName);
|
||||
|
||||
foreach ($node->getChildren() as $child) {
|
||||
if ($child instanceof HostNode) {
|
||||
$excludes->addFilter(LegacyFilter::where('host_name', $child->getHostname()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions = new TermSuggestions((function () use ($forConfig, $excludes, &$suggestions) {
|
||||
foreach ($suggestions->getExcludeTerms() as $excludeTerm) {
|
||||
[$hostName, $_] = BpConfig::splitNodeName($excludeTerm);
|
||||
$excludes->addFilter(LegacyFilter::where('host_name', $hostName));
|
||||
}
|
||||
|
||||
$hosts = (new HostStatus($forConfig->getBackend()->select(), ['host_name', 'host_display_name']))
|
||||
->limit(50)
|
||||
->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects'))
|
||||
->applyFilter(LegacyFilter::matchAny(
|
||||
LegacyFilter::where('host_name', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('host_display_name', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('host_address', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('host_address6', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('_host_%', $suggestions->getSearchTerm()),
|
||||
// This also forces a group by on the query, needed anyway due to the custom var filter
|
||||
// above, which may return multiple rows because of the wildcard in the name filter.
|
||||
LegacyFilter::where('hostgroup_name', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('hostgroup_alias', $suggestions->getSearchTerm())
|
||||
));
|
||||
if (! $excludes->isEmpty()) {
|
||||
$hosts->applyFilter(LegacyFilter::not($excludes));
|
||||
}
|
||||
|
||||
foreach ($hosts as $row) {
|
||||
yield [
|
||||
'search' => BpConfig::joinNodeName($row->host_name, 'Hoststatus'),
|
||||
'label' => $row->host_display_name,
|
||||
'class' => 'host'
|
||||
];
|
||||
}
|
||||
})());
|
||||
|
||||
$this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest()));
|
||||
}
|
||||
|
||||
public function monitoringServiceAction()
|
||||
{
|
||||
$excludes = LegacyFilter::matchAny();
|
||||
$forConfig = null;
|
||||
if ($this->params->has('config')) {
|
||||
$forConfig = $this->loadModifiedBpConfig();
|
||||
|
||||
if ($this->params->has('node')) {
|
||||
$nodeName = $this->params->get('node');
|
||||
$node = $forConfig->getBpNode($nodeName);
|
||||
|
||||
foreach ($node->getChildren() as $child) {
|
||||
if ($child instanceof ServiceNode) {
|
||||
$excludes->addFilter(LegacyFilter::matchAll(
|
||||
LegacyFilter::where('host_name', $child->getHostname()),
|
||||
LegacyFilter::where('service_description', $child->getServiceDescription())
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions = new TermSuggestions((function () use ($forConfig, $excludes, &$suggestions) {
|
||||
foreach ($suggestions->getExcludeTerms() as $excludeTerm) {
|
||||
[$hostName, $serviceName] = BpConfig::splitNodeName($excludeTerm);
|
||||
if ($serviceName !== null && $serviceName !== 'Hoststatus') {
|
||||
$excludes->addFilter(LegacyFilter::matchAll(
|
||||
LegacyFilter::where('host_name', $hostName),
|
||||
LegacyFilter::where('service_description', $serviceName)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$services = (new ServiceStatus($forConfig->getBackend()->select(), [
|
||||
'host_name',
|
||||
'host_display_name',
|
||||
'service_description',
|
||||
'service_display_name'
|
||||
]))
|
||||
->limit(50)
|
||||
->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects'))
|
||||
->applyFilter(LegacyFilter::matchAny(
|
||||
LegacyFilter::where('host_name', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('host_display_name', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('service_description', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('service_display_name', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('_service_%', $suggestions->getSearchTerm()),
|
||||
// This also forces a group by on the query, needed anyway due to the custom var filter
|
||||
// above, which may return multiple rows because of the wildcard in the name filter.
|
||||
LegacyFilter::where('servicegroup_name', $suggestions->getSearchTerm()),
|
||||
LegacyFilter::where('servicegroup_alias', $suggestions->getSearchTerm())
|
||||
));
|
||||
if (! $excludes->isEmpty()) {
|
||||
$services->applyFilter(LegacyFilter::not($excludes));
|
||||
}
|
||||
|
||||
foreach ($services as $row) {
|
||||
yield [
|
||||
'class' => 'service',
|
||||
'search' => BpConfig::joinNodeName($row->host_name, $row->service_description),
|
||||
'label' => sprintf(
|
||||
$this->translate('%s on %s', '<service> on <host>'),
|
||||
$row->service_display_name,
|
||||
$row->host_display_name
|
||||
)
|
||||
];
|
||||
}
|
||||
})());
|
||||
|
||||
$this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest()));
|
||||
}
|
||||
}
|
||||
|
|
@ -5,509 +5,406 @@ namespace Icinga\Module\Businessprocess\Forms;
|
|||
use Exception;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\Common\EnumList;
|
||||
use Icinga\Module\Businessprocess\Common\Sort;
|
||||
use Icinga\Module\Businessprocess\ImportedNode;
|
||||
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
|
||||
use Icinga\Module\Businessprocess\Node;
|
||||
use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm;
|
||||
use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator;
|
||||
use Icinga\Module\Businessprocess\Storage\Storage;
|
||||
use Icinga\Module\Businessprocess\Web\Form\Element\IplStateOverrides;
|
||||
use Icinga\Module\Businessprocess\Web\Form\Validator\HostServiceTermValidator;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Web\Session\SessionNamespace;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Html\Text;
|
||||
use ipl\I18n\Translation;
|
||||
use ipl\Stdlib\Str;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Web\FormElement\TermInput;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class AddNodeForm extends BpConfigBaseForm
|
||||
class AddNodeForm extends CompatForm
|
||||
{
|
||||
use EnumList;
|
||||
use Sort;
|
||||
use Translation;
|
||||
|
||||
/** @var BpNode */
|
||||
/** @var Storage */
|
||||
protected $storage;
|
||||
|
||||
/** @var ?BpConfig */
|
||||
protected $bp;
|
||||
|
||||
/** @var ?BpNode */
|
||||
protected $parent;
|
||||
|
||||
protected $objectList = array();
|
||||
|
||||
protected $processList = array();
|
||||
|
||||
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' => Node::getOperators()
|
||||
));
|
||||
|
||||
$display = 1;
|
||||
if ($this->bp->getMetadata()->isManuallyOrdered() && ! $this->bp->isEmpty()) {
|
||||
$rootNodes = self::applyManualSorting($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'
|
||||
)
|
||||
));
|
||||
}
|
||||
/** @var SessionNamespace */
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* @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,
|
||||
'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,
|
||||
'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,
|
||||
'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,
|
||||
'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,
|
||||
'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 BpNode|null $node
|
||||
* Set the storage to use
|
||||
*
|
||||
* @param Storage $storage
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParentNode(BpNode $node = null)
|
||||
public function setStorage(Storage $storage): self
|
||||
{
|
||||
$this->parent = $node;
|
||||
$this->storage = $storage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* Set the affected configuration
|
||||
*
|
||||
* @param BpConfig $bp
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function hasParentNode()
|
||||
public function setProcess(BpConfig $bp): self
|
||||
{
|
||||
return $this->parent !== null;
|
||||
}
|
||||
$this->bp = $bp;
|
||||
|
||||
protected function hasProcesses()
|
||||
{
|
||||
return count($this->enumProcesses()) > 0;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @return array
|
||||
* Set the affected sub-process
|
||||
*
|
||||
* @param ?BpNode $node
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function enumProcesses($file = null)
|
||||
public function setParentNode(BpNode $node = null): self
|
||||
{
|
||||
$list = array();
|
||||
$this->parent = $node;
|
||||
|
||||
$parents = array();
|
||||
return $this;
|
||||
}
|
||||
|
||||
$differentFile = $file !== null && $file !== $this->bp->getName();
|
||||
/**
|
||||
* Set the user's session
|
||||
*
|
||||
* @param SessionNamespace $session
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(SessionNamespace $session): self
|
||||
{
|
||||
$this->session = $session;
|
||||
|
||||
if (! $differentFile && $this->hasParentNode()) {
|
||||
$this->collectAllParents($this->parent, $parents);
|
||||
$parents[$this->parent->getName()] = $this->parent;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
$bp = $this->bp;
|
||||
if ($differentFile) {
|
||||
try {
|
||||
$bp = $this->storage->loadProcess($file);
|
||||
} catch (Exception $e) {
|
||||
$this->addError('Cannot add invalid config file');
|
||||
|
||||
return $list;
|
||||
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 = [];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($bp->getNodes() as $node) {
|
||||
if (! $node instanceof ImportedNode && $node instanceof BpNode && ! isset($parents[$node->getName()])) {
|
||||
$name = $node->getName();
|
||||
if ($differentFile) {
|
||||
$name = '@' . $file . ':' . $name;
|
||||
$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());
|
||||
}
|
||||
|
||||
$list[$name] = $node->getName(); // display name?
|
||||
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';
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
$this->addElement($this->createChildrenElementForObjects(
|
||||
$this->translate('Hosts'),
|
||||
$suggestionsPath
|
||||
));
|
||||
|
||||
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);
|
||||
$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')
|
||||
]
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
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);
|
||||
switch ($this->getValue('node_type')) {
|
||||
case 'host':
|
||||
case 'service':
|
||||
|
||||
$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 {
|
||||
$children = array_unique(array_map(function ($term) {
|
||||
return $term->getSearchValue();
|
||||
}, $this->getElement('children')->getTerms()));
|
||||
|
||||
if ($nodeType === 'host' || $nodeType === 'service') {
|
||||
$stateOverrides = $this->getValue('stateOverrides');
|
||||
if (! empty($stateOverrides)) {
|
||||
$childOverrides = [];
|
||||
foreach ($this->getValue('children') as $service) {
|
||||
$childOverrides[$service] = $stateOverrides;
|
||||
foreach ($children as $nodeName) {
|
||||
$childOverrides[$nodeName] = $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);
|
||||
}
|
||||
if ($this->parent !== null) {
|
||||
$changes->addChildrenToNode($children, $this->parent);
|
||||
} else {
|
||||
foreach ($children as $nodeName) {
|
||||
$changes->copyNode($nodeName);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'new-process':
|
||||
$properties = $this->getValues();
|
||||
unset($properties['name']);
|
||||
if (! $properties['alias']) {
|
||||
unset($properties['alias']);
|
||||
}
|
||||
if ($this->hasParentNode()) {
|
||||
$properties['parentName'] = $this->parent->getName();
|
||||
}
|
||||
$changes->createNode(BpConfig::escapeName($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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,397 +4,312 @@ namespace Icinga\Module\Businessprocess\Forms;
|
|||
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\Common\EnumList;
|
||||
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
|
||||
use Icinga\Module\Businessprocess\Node;
|
||||
use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm;
|
||||
use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator;
|
||||
use Icinga\Module\Businessprocess\ServiceNode;
|
||||
use Icinga\Module\Businessprocess\Web\Form\Element\IplStateOverrides;
|
||||
use Icinga\Module\Businessprocess\Web\Form\Validator\HostServiceTermValidator;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Web\Session\SessionNamespace;
|
||||
use ipl\Html\Attributes;
|
||||
use ipl\Html\FormattedString;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Html\ValidHtml;
|
||||
use ipl\I18n\Translation;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Web\FormElement\TermInput\ValidatedTerm;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class EditNodeForm extends BpConfigBaseForm
|
||||
class EditNodeForm extends CompatForm
|
||||
{
|
||||
use EnumList;
|
||||
use Translation;
|
||||
|
||||
/** @var Node */
|
||||
/** @var ?BpConfig */
|
||||
protected $bp;
|
||||
|
||||
/** @var ?Node */
|
||||
protected $node;
|
||||
|
||||
/** @var BpNode */
|
||||
/** @var ?BpNode */
|
||||
protected $parent;
|
||||
|
||||
protected $objectList = array();
|
||||
|
||||
protected $processList = array();
|
||||
|
||||
protected $service;
|
||||
|
||||
protected $host;
|
||||
|
||||
public function setup()
|
||||
{
|
||||
[$this->host, $suffix] = BpConfig::splitNodeName($this->getNode()->getName());
|
||||
if ($suffix !== 'Hoststatus') {
|
||||
$this->service = $suffix;
|
||||
}
|
||||
|
||||
$view = $this->getView();
|
||||
$nodeName = $this->getNode()->getAlias() ?? $this->getNode()->getName();
|
||||
$this->addHtml(
|
||||
'<h2>' . $view->escape(
|
||||
sprintf($this->translate('Modify "%s"'), $nodeName)
|
||||
) . '</h2>'
|
||||
);
|
||||
|
||||
$monitoredNodeType = null;
|
||||
if ($this->isService()) {
|
||||
$monitoredNodeType = 'service';
|
||||
} else {
|
||||
$monitoredNodeType = 'host';
|
||||
}
|
||||
|
||||
$type = $this->selectNodeType($monitoredNodeType);
|
||||
switch ($type) {
|
||||
case 'host':
|
||||
$this->selectHost();
|
||||
break;
|
||||
case 'service':
|
||||
$this->selectService();
|
||||
break;
|
||||
case 'process':
|
||||
$this->selectProcess();
|
||||
break;
|
||||
case 'new-process':
|
||||
$this->addNewProcess();
|
||||
break;
|
||||
case null:
|
||||
$this->setSubmitLabel($this->translate('Next'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected function isService()
|
||||
{
|
||||
if (strpos($this->getNode()->getName(), ';Hoststatus')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function addNewProcess()
|
||||
{
|
||||
$this->addElement('text', 'name', array(
|
||||
'label' => $this->translate('ID'),
|
||||
'required' => true,
|
||||
'disabled' => true,
|
||||
'description' => $this->translate(
|
||||
'This is the unique identifier of 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' => Node::getOperators()
|
||||
));
|
||||
|
||||
$display = $this->getNode()->getDisplay() ?: 1;
|
||||
$this->addElement('select', 'display', array(
|
||||
'label' => $this->translate('Visualization'),
|
||||
'required' => true,
|
||||
'description' => $this->translate(
|
||||
'Where to show this process'
|
||||
),
|
||||
'value' => $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'
|
||||
)
|
||||
));
|
||||
}
|
||||
/** @var SessionNamespace */
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
protected function selectNodeType($monitoredNodeType = null)
|
||||
{
|
||||
if ($this->hasParentNode()) {
|
||||
$this->addElement('hidden', 'node_type', [
|
||||
'disabled' => true,
|
||||
'decorators' => ['ViewHelper'],
|
||||
'value' => $monitoredNodeType
|
||||
]);
|
||||
|
||||
return $monitoredNodeType;
|
||||
} elseif (! $this->hasProcesses()) {
|
||||
$this->addElement('hidden', 'node_type', array(
|
||||
'ignore' => true,
|
||||
'decorators' => array('ViewHelper'),
|
||||
'value' => 'new-process'
|
||||
));
|
||||
|
||||
return 'new-process';
|
||||
}
|
||||
}
|
||||
|
||||
protected function selectHost()
|
||||
{
|
||||
$this->addElement('select', 'children', array(
|
||||
'required' => true,
|
||||
'value' => $this->getNode()->getName(),
|
||||
'multiOptions' => $this->enumHostList(),
|
||||
'label' => $this->translate('Host'),
|
||||
'description' => $this->translate('The host for this business process node'),
|
||||
'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]]
|
||||
));
|
||||
|
||||
$this->addHostOverrideCheckbox();
|
||||
$hostOverrideSent = $this->getSentValue('host_override');
|
||||
if ($hostOverrideSent === '1'
|
||||
|| ($hostOverrideSent === null && $this->getElement('host_override')->isChecked())
|
||||
) {
|
||||
$this->addHostOverrideElement();
|
||||
}
|
||||
}
|
||||
|
||||
protected function selectService()
|
||||
{
|
||||
$this->addHostElement();
|
||||
|
||||
if ($this->getSentValue('hosts') === null) {
|
||||
$this->addServicesElement($this->host);
|
||||
$this->addServiceOverrideCheckbox();
|
||||
if ($this->getElement('service_override')->isChecked() || $this->getSentValue('service_override') === '1') {
|
||||
$this->addServiceOverrideElement();
|
||||
}
|
||||
} elseif ($host = $this->getSentValue('hosts')) {
|
||||
$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', 'hosts', array(
|
||||
'label' => $this->translate('Host'),
|
||||
'required' => true,
|
||||
'ignore' => true,
|
||||
'class' => 'autosubmit',
|
||||
'multiOptions' => $this->optionalEnum($this->enumHostForServiceList()),
|
||||
));
|
||||
|
||||
$this->getElement('hosts')->setValue($this->host);
|
||||
}
|
||||
|
||||
protected function addHostOverrideCheckbox()
|
||||
{
|
||||
$this->addElement('checkbox', 'host_override', [
|
||||
'ignore' => true,
|
||||
'class' => 'autosubmit',
|
||||
'value' => ! empty($this->parent->getStateOverrides($this->node->getName())),
|
||||
'label' => $this->translate('Override Host State'),
|
||||
'description' => $this->translate('Enable host state overrides')
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addHostOverrideElement()
|
||||
{
|
||||
$this->addElement('stateOverrides', 'stateOverrides', [
|
||||
'required' => true,
|
||||
'states' => $this->enumHostStateList(),
|
||||
'value' => $this->parent->getStateOverrides($this->node->getName()),
|
||||
'label' => $this->translate('State Overrides')
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addServicesElement($host)
|
||||
{
|
||||
$this->addElement('select', 'children', array(
|
||||
'required' => true,
|
||||
'value' => $this->getNode()->getName(),
|
||||
'multiOptions' => $this->enumServiceList($host),
|
||||
'label' => $this->translate('Service'),
|
||||
'description' => $this->translate('The service for this business process node'),
|
||||
'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]]
|
||||
));
|
||||
}
|
||||
|
||||
protected function addServiceOverrideCheckbox()
|
||||
{
|
||||
$this->addElement('checkbox', 'service_override', [
|
||||
'ignore' => true,
|
||||
'class' => 'autosubmit',
|
||||
'value' => ! empty($this->parent->getStateOverrides($this->node->getName())),
|
||||
'label' => $this->translate('Override Service State'),
|
||||
'description' => $this->translate('Enable service state overrides')
|
||||
]);
|
||||
}
|
||||
|
||||
protected function addServiceOverrideElement()
|
||||
{
|
||||
$this->addElement('stateOverrides', 'stateOverrides', [
|
||||
'required' => true,
|
||||
'states' => $this->enumServiceStateList(),
|
||||
'value' => $this->parent->getStateOverrides($this->node->getName()),
|
||||
'label' => $this->translate('State Overrides')
|
||||
]);
|
||||
}
|
||||
|
||||
protected function selectProcess()
|
||||
{
|
||||
$this->addElement('multiselect', 'children', array(
|
||||
'label' => $this->translate('Process nodes'),
|
||||
'required' => true,
|
||||
'size' => 8,
|
||||
'multiOptions' => $this->enumProcesses(),
|
||||
'description' => $this->translate(
|
||||
'Other processes that should be part of this business process node'
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BpNode|null $node
|
||||
* Set the affected configuration
|
||||
*
|
||||
* @param BpConfig $bp
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParentNode(BpNode $node = null)
|
||||
public function setProcess(BpConfig $bp): self
|
||||
{
|
||||
$this->parent = $node;
|
||||
$this->bp = $bp;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasParentNode()
|
||||
{
|
||||
return $this->parent !== null;
|
||||
}
|
||||
|
||||
protected function hasProcesses()
|
||||
{
|
||||
return count($this->enumProcesses()) > 0;
|
||||
}
|
||||
|
||||
protected function enumProcesses()
|
||||
{
|
||||
$list = array();
|
||||
|
||||
$parents = array();
|
||||
|
||||
if ($this->hasParentNode()) {
|
||||
$this->collectAllParents($this->parent, $parents);
|
||||
$parents[$this->parent->getName()] = $this->parent;
|
||||
}
|
||||
|
||||
foreach ($this->bp->getNodes() as $node) {
|
||||
if ($node instanceof BpNode && ! isset($parents[$node->getName()])) {
|
||||
$list[$node->getName()] = $node->getName(); // display name?
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the given node's parents recursively into the given array by their names
|
||||
* Set the affected node
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $node
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setNode(Node $node)
|
||||
public function setNode(Node $node): self
|
||||
{
|
||||
$this->node = $node;
|
||||
|
||||
$this->populate([
|
||||
'node-search' => $node->getName(),
|
||||
'node-label' => $node->getAlias()
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNode()
|
||||
/**
|
||||
* Set the affected sub-process
|
||||
*
|
||||
* @param ?BpNode $node
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParentNode(BpNode $node = null): self
|
||||
{
|
||||
return $this->node;
|
||||
$this->parent = $node;
|
||||
|
||||
if ($this->node !== null) {
|
||||
$stateOverrides = $this->parent->getStateOverrides($this->node->getName());
|
||||
if (! empty($stateOverrides)) {
|
||||
$this->populate([
|
||||
'overrideStates' => 'y',
|
||||
'stateOverrides' => $stateOverrides
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
/**
|
||||
* Set the user's session
|
||||
*
|
||||
* @param SessionNamespace $session
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(SessionNamespace $session): self
|
||||
{
|
||||
$this->session = $session;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify and return the node the user has chosen
|
||||
*
|
||||
* @return Node
|
||||
*/
|
||||
protected function identifyChosenNode(): Node
|
||||
{
|
||||
$userInput = $this->getPopulatedValue('node');
|
||||
$nodeName = $this->getPopulatedValue('node-search');
|
||||
$nodeLabel = $this->getPopulatedValue('node-label');
|
||||
|
||||
if ($nodeName && $userInput === $nodeLabel) {
|
||||
// User accepted a suggestion and didn't change it manually
|
||||
$node = $this->bp->getNode($nodeName);
|
||||
} elseif ($userInput && (! $nodeLabel || $userInput !== $nodeLabel)) {
|
||||
// User didn't choose a suggestion or changed it manually
|
||||
$node = $this->bp->getNode(BpConfig::joinNodeName($userInput, 'Hoststatus'));
|
||||
} else {
|
||||
// If the search and user input are both empty, it can only be the initial value
|
||||
$node = $this->node;
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$this->addHtml(new HtmlElement('h2', null, FormattedString::create(
|
||||
$this->translate('Modify "%s"'),
|
||||
$this->node->getAlias() ?? $this->node->getName()
|
||||
)));
|
||||
|
||||
if ($this->node instanceof ServiceNode) {
|
||||
$this->assembleServiceElements();
|
||||
} else {
|
||||
$this->assembleHostElements();
|
||||
}
|
||||
|
||||
$this->addElement('submit', 'btn_submit', [
|
||||
'label' => $this->translate('Save Changes')
|
||||
]);
|
||||
}
|
||||
|
||||
protected function assembleServiceElements(): void
|
||||
{
|
||||
if ($this->bp->getBackend() instanceof MonitoringBackend) {
|
||||
$suggestionsPath = 'businessprocess/suggestions/monitoring-service';
|
||||
} else {
|
||||
$suggestionsPath = 'businessprocess/suggestions/icingadb-service';
|
||||
}
|
||||
|
||||
$node = $this->identifyChosenNode();
|
||||
|
||||
$this->addHtml($this->createSearchInput(
|
||||
$this->translate('Service'),
|
||||
$node->getAlias() ?? $node->getName(),
|
||||
$suggestionsPath
|
||||
));
|
||||
|
||||
$this->addElement('checkbox', 'overrideStates', [
|
||||
'ignore' => true,
|
||||
'class' => 'autosubmit',
|
||||
'label' => $this->translate('Override Service State')
|
||||
]);
|
||||
if ($this->getPopulatedValue('overrideStates') === '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 assembleHostElements(): void
|
||||
{
|
||||
if ($this->bp->getBackend() instanceof MonitoringBackend) {
|
||||
$suggestionsPath = 'businessprocess/suggestions/monitoring-host';
|
||||
} else {
|
||||
$suggestionsPath = 'businessprocess/suggestions/icingadb-host';
|
||||
}
|
||||
|
||||
$node = $this->identifyChosenNode();
|
||||
|
||||
$this->addHtml($this->createSearchInput(
|
||||
$this->translate('Host'),
|
||||
$node->getAlias() ?? $node->getName(),
|
||||
$suggestionsPath
|
||||
));
|
||||
|
||||
$this->addElement('checkbox', 'overrideStates', [
|
||||
'ignore' => true,
|
||||
'class' => 'autosubmit',
|
||||
'label' => $this->translate('Override Host State')
|
||||
]);
|
||||
if ($this->getPopulatedValue('overrideStates') === '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 createSearchInput(string $label, string $value, string $suggestionsPath): ValidHtml
|
||||
{
|
||||
$userInput = $this->createElement('text', 'node', [
|
||||
'ignore' => true,
|
||||
'required' => true,
|
||||
'autocomplete' => 'off',
|
||||
'label' => $label,
|
||||
'value' => $value,
|
||||
'data-enrichment-type' => 'completion',
|
||||
'data-term-suggestions' => '#node-suggestions',
|
||||
'data-suggest-url' => Url::fromPath($suggestionsPath, [
|
||||
'node' => isset($this->parent) ? $this->parent->getName() : null,
|
||||
'config' => $this->bp->getName(),
|
||||
'showCompact' => true,
|
||||
'_disableLayout' => true
|
||||
]),
|
||||
'validators' => ['callback' => function ($_, $validator) {
|
||||
$newName = $this->identifyChosenNode()->getName();
|
||||
if ($newName === $this->node->getName()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$term = new ValidatedTerm($newName);
|
||||
|
||||
(new HostServiceTermValidator())
|
||||
->setParent($this->parent)
|
||||
->isValid($term);
|
||||
|
||||
if (! $term->isValid()) {
|
||||
$validator->addMessage($term->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}]
|
||||
]);
|
||||
|
||||
$fieldset = new HtmlElement('fieldset');
|
||||
|
||||
$searchInput = $this->createElement('hidden', 'node-search', ['ignore' => true]);
|
||||
$this->registerElement($searchInput);
|
||||
$fieldset->addHtml($searchInput);
|
||||
|
||||
$labelInput = $this->createElement('hidden', 'node-label', ['ignore' => true]);
|
||||
$this->registerElement($labelInput);
|
||||
$fieldset->addHtml($labelInput);
|
||||
|
||||
$this->registerElement($userInput);
|
||||
$this->decorate($userInput);
|
||||
|
||||
$fieldset->addHtml(
|
||||
$userInput,
|
||||
new HtmlElement('div', Attributes::create([
|
||||
'id' => 'node-suggestions',
|
||||
'class' => 'search-suggestions'
|
||||
]))
|
||||
);
|
||||
|
||||
return $fieldset;
|
||||
}
|
||||
|
||||
protected function onSuccess()
|
||||
{
|
||||
$changes = ProcessChanges::construct($this->bp, $this->session);
|
||||
|
||||
$children = $this->parent->getChildNames();
|
||||
$previousPos = array_search($this->node->getName(), $children, true);
|
||||
$node = $this->identifyChosenNode();
|
||||
$nodeName = $node->getName();
|
||||
|
||||
$changes->deleteNode($this->node, $this->parent->getName());
|
||||
$changes->addChildrenToNode([$nodeName], $this->parent);
|
||||
|
||||
switch ($this->getValue('node_type')) {
|
||||
case 'host':
|
||||
case 'service':
|
||||
$stateOverrides = $this->getValue('stateOverrides') ?: [];
|
||||
if (! empty($stateOverrides)) {
|
||||
$stateOverrides = array_merge(
|
||||
$this->parent->getStateOverrides(),
|
||||
[$this->getValue('children') => $stateOverrides]
|
||||
);
|
||||
} else {
|
||||
$stateOverrides = $this->parent->getStateOverrides();
|
||||
unset($stateOverrides[$this->getValue('children')]);
|
||||
}
|
||||
|
||||
$changes->modifyNode($this->parent, ['stateOverrides' => $stateOverrides]);
|
||||
// Fallthrough
|
||||
case 'process':
|
||||
$changes->addChildrenToNode($this->getValue('children'), $this->parent);
|
||||
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;
|
||||
$stateOverrides = $this->getValue('stateOverrides');
|
||||
if (! empty($stateOverrides)) {
|
||||
$changes->modifyNode($this->parent, [
|
||||
'stateOverrides' => array_merge($this->parent->getStateOverrides(), [
|
||||
$nodeName => $stateOverrides
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
if ($this->bp->getMetadata()->isManuallyOrdered() && ($newPos = count($children) - 1) > $previousPos) {
|
||||
$changes->moveNode(
|
||||
$node,
|
||||
$newPos,
|
||||
$previousPos,
|
||||
$this->parent->getName(),
|
||||
$this->parent->getName()
|
||||
);
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
public function isValid($data)
|
||||
{
|
||||
// Don't allow to override disabled elements. This is probably too harsh
|
||||
// but also wouldn't be necessary if this would be a Icinga\Web\Form...
|
||||
foreach ($this->getElements() as $element) {
|
||||
/** @var \Zend_Form_Element $element */
|
||||
if ($element->getAttrib('disabled')) {
|
||||
$data[$element->getName()] = $element->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return parent::isValid($data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,6 +173,8 @@ class BpNode extends Node
|
|||
if (! empty($this->children)) {
|
||||
unset($this->children[$name]);
|
||||
}
|
||||
|
||||
$this->childNames = array_values($this->childNames);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
|
|
|||
|
|
@ -1,170 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Common;
|
||||
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\IcingaDbObject;
|
||||
use Icinga\Module\Businessprocess\MonitoringRestrictions;
|
||||
use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport;
|
||||
|
||||
trait EnumList
|
||||
{
|
||||
protected function enumHostForServiceList()
|
||||
{
|
||||
if ($this->useIcingaDbBackend()) {
|
||||
$names = (new IcingaDbObject())->yieldHostnames();
|
||||
} else {
|
||||
$names = $this->backend
|
||||
->select()
|
||||
->from('hostStatus', ['hostname' => 'host_name'])
|
||||
->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects'))
|
||||
->order('host_name')
|
||||
->getQuery()
|
||||
->fetchColumn();
|
||||
}
|
||||
|
||||
// fetchPairs doesn't seem to work when using the same column with
|
||||
// different aliases twice
|
||||
$res = array();
|
||||
foreach ($names as $name) {
|
||||
$res[$name] = $name;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function enumHostList()
|
||||
{
|
||||
if ($this->useIcingaDbBackend()) {
|
||||
$names = (new IcingaDbObject())->yieldHostnames();
|
||||
} else {
|
||||
$names = $this->backend
|
||||
->select()
|
||||
->from('hostStatus', ['hostname' => 'host_name'])
|
||||
->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects'))
|
||||
->order('host_name')
|
||||
->getQuery()
|
||||
->fetchColumn();
|
||||
}
|
||||
|
||||
// fetchPairs doesn't seem to work when using the same column with
|
||||
// different aliases twice
|
||||
$res = array();
|
||||
foreach ($names as $name) {
|
||||
$res[BpConfig::joinNodeName($name, 'Hoststatus')] = $name;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function enumServiceList($host)
|
||||
{
|
||||
if ($this->useIcingaDbBackend()) {
|
||||
$names = (new IcingaDbObject())->yieldServicenames($host);
|
||||
} else {
|
||||
$names = $this->backend
|
||||
->select()
|
||||
->from('serviceStatus', ['service' => 'service_description'])
|
||||
->where('host_name', $host)
|
||||
->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects'))
|
||||
->order('service_description')
|
||||
->getQuery()
|
||||
->fetchColumn();
|
||||
}
|
||||
|
||||
$services = array();
|
||||
foreach ($names as $name) {
|
||||
$services[BpConfig::joinNodeName($host, $name)] = $name;
|
||||
}
|
||||
|
||||
return $services;
|
||||
}
|
||||
|
||||
protected function enumHostListByFilter($filter)
|
||||
{
|
||||
if ($this->useIcingaDbBackend()) {
|
||||
$names = (new IcingaDbObject())->yieldHostnames($filter);
|
||||
} else {
|
||||
$names = $this->backend
|
||||
->select()
|
||||
->from('hostStatus', ['hostname' => 'host_name'])
|
||||
->applyFilter(Filter::fromQueryString($filter))
|
||||
->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects'))
|
||||
->order('host_name')
|
||||
->getQuery()
|
||||
->fetchColumn();
|
||||
}
|
||||
|
||||
// fetchPairs doesn't seem to work when using the same column with
|
||||
// different aliases twice
|
||||
$res = array();
|
||||
foreach ($names as $name) {
|
||||
$res[BpConfig::joinNodeName($name, 'Hoststatus')] = $name;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function enumServiceListByFilter($filter)
|
||||
{
|
||||
$services = array();
|
||||
|
||||
if ($this->useIcingaDbBackend()) {
|
||||
$objects = (new IcingaDbObject())->fetchServices($filter);
|
||||
foreach ($objects as $object) {
|
||||
$services[BpConfig::joinNodeName($object->host->name, $object->name)]
|
||||
= $object->host->name . ':' . $object->name;
|
||||
}
|
||||
} else {
|
||||
$objects = $this->backend
|
||||
->select()
|
||||
->from('serviceStatus', ['host' => 'host_name', 'service' => 'service_description'])
|
||||
->applyFilter(Filter::fromQueryString($filter))
|
||||
->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects'))
|
||||
->order('service_description')
|
||||
->getQuery()
|
||||
->fetchAll();
|
||||
foreach ($objects as $object) {
|
||||
$services[BpConfig::joinNodeName($object->host, $object->service)]
|
||||
= $object->host . ':' . $object->service;
|
||||
}
|
||||
}
|
||||
|
||||
return $services;
|
||||
}
|
||||
|
||||
protected function enumHostStateList()
|
||||
{
|
||||
$hostStateList = [
|
||||
0 => $this->translate('UP'),
|
||||
1 => $this->translate('DOWN'),
|
||||
99 => $this->translate('PENDING')
|
||||
];
|
||||
|
||||
return $hostStateList;
|
||||
}
|
||||
|
||||
protected function enumServiceStateList()
|
||||
{
|
||||
$serviceStateList = [
|
||||
0 => $this->translate('OK'),
|
||||
1 => $this->translate('WARNING'),
|
||||
2 => $this->translate('CRITICAL'),
|
||||
3 => $this->translate('UNKNOWN'),
|
||||
99 => $this->translate('PENDING'),
|
||||
];
|
||||
|
||||
return $serviceStateList;
|
||||
}
|
||||
|
||||
protected function useIcingaDbBackend()
|
||||
{
|
||||
if (Module::exists('icingadb')) {
|
||||
return ! $this->bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Monitoring\Backend\Ido\Query;
|
||||
|
||||
use Icinga\Module\Monitoring\Backend\Ido\Query\ServicecommenthistoryQuery;
|
||||
use Icinga\Module\Monitoring\Backend\Ido\Query\ServicecommentQuery;
|
||||
use Icinga\Module\Monitoring\Backend\Ido\Query\ServicedowntimeQuery;
|
||||
use Icinga\Module\Monitoring\Backend\Ido\Query\ServicedowntimestarthistoryQuery;
|
||||
use Icinga\Module\Monitoring\Backend\Ido\Query\ServiceflappingstarthistoryQuery;
|
||||
use Icinga\Module\Monitoring\Backend\Ido\Query\ServicegroupQuery;
|
||||
use Icinga\Module\Monitoring\Backend\Ido\Query\ServicenotificationQuery;
|
||||
use Icinga\Module\Monitoring\Backend\Ido\Query\ServicestatehistoryQuery;
|
||||
use Zend_Db_Select;
|
||||
|
||||
trait CustomVarJoinTemplateOverride
|
||||
{
|
||||
private $customVarsJoinTemplate = '%1$s = %2$s.object_id AND %2$s.varname LIKE %3$s';
|
||||
|
||||
/**
|
||||
* This is a 1:1 copy of {@see IdoQuery::joinCustomvar()} to be able to
|
||||
* adjust {@see IdoQuery::$customVarsJoinTemplate} as it's private
|
||||
*/
|
||||
protected function joinCustomvar($customvar)
|
||||
{
|
||||
// TODO: This is not generic enough yet
|
||||
list($type, $name) = $this->customvarNameToTypeName($customvar);
|
||||
$alias = ($type === 'host' ? 'hcv_' : 'scv_') . preg_replace('~[^a-zA-Z0-9_]~', '_', $name);
|
||||
|
||||
// We're replacing any problematic char with an underscore, which will lead to duplicates, this avoids them
|
||||
$from = $this->select->getPart(Zend_Db_Select::FROM);
|
||||
for ($i = 2; array_key_exists($alias, $from); $i++) {
|
||||
$alias = $alias . '_' . $i;
|
||||
}
|
||||
|
||||
$this->customVars[strtolower($customvar)] = $alias;
|
||||
|
||||
if ($type === 'host') {
|
||||
if ($this instanceof ServicecommentQuery
|
||||
|| $this instanceof ServicedowntimeQuery
|
||||
|| $this instanceof ServicecommenthistoryQuery
|
||||
|| $this instanceof ServicedowntimestarthistoryQuery
|
||||
|| $this instanceof ServiceflappingstarthistoryQuery
|
||||
|| $this instanceof ServicegroupQuery
|
||||
|| $this instanceof ServicenotificationQuery
|
||||
|| $this instanceof ServicestatehistoryQuery
|
||||
|| $this instanceof \Icinga\Module\Monitoring\Backend\Ido\Query\ServicestatusQuery
|
||||
) {
|
||||
$this->requireVirtualTable('services');
|
||||
$leftcol = 's.host_object_id';
|
||||
} else {
|
||||
$leftcol = 'ho.object_id';
|
||||
if (! $this->hasJoinedTable('ho')) {
|
||||
$this->requireVirtualTable('hosts');
|
||||
}
|
||||
}
|
||||
} else { // $type === 'service'
|
||||
$leftcol = 'so.object_id';
|
||||
if (! $this->hasJoinedTable('so')) {
|
||||
$this->requireVirtualTable('services');
|
||||
}
|
||||
}
|
||||
|
||||
$mapped = $this->getMappedField($leftcol);
|
||||
if ($mapped !== null) {
|
||||
$this->requireColumn($leftcol);
|
||||
$leftcol = $mapped;
|
||||
}
|
||||
|
||||
$joinOn = sprintf(
|
||||
$this->customVarsJoinTemplate,
|
||||
$leftcol,
|
||||
$alias,
|
||||
$this->db->quote($name)
|
||||
);
|
||||
|
||||
$this->select->joinLeft(
|
||||
array($alias => $this->prefix . 'customvariablestatus'),
|
||||
$joinOn,
|
||||
array()
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Monitoring\Backend\Ido\Query;
|
||||
|
||||
class HostStatusQuery extends \Icinga\Module\Monitoring\Backend\Ido\Query\HoststatusQuery
|
||||
{
|
||||
use CustomVarJoinTemplateOverride;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Monitoring\Backend\Ido\Query;
|
||||
|
||||
class ServiceStatusQuery extends \Icinga\Module\Monitoring\Backend\Ido\Query\ServicestatusQuery
|
||||
{
|
||||
use CustomVarJoinTemplateOverride;
|
||||
}
|
||||
16
library/Businessprocess/Monitoring/DataView/HostStatus.php
Normal file
16
library/Businessprocess/Monitoring/DataView/HostStatus.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Monitoring\DataView;
|
||||
|
||||
use Icinga\Data\ConnectionInterface;
|
||||
use Icinga\Module\Businessprocess\Monitoring\Backend\Ido\Query\HostStatusQuery;
|
||||
|
||||
class HostStatus extends \Icinga\Module\Monitoring\DataView\Hoststatus
|
||||
{
|
||||
public function __construct(ConnectionInterface $connection, array $columns = null)
|
||||
{
|
||||
parent::__construct($connection, $columns);
|
||||
|
||||
$this->query = new HostStatusQuery($connection->getResource(), $columns);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Monitoring\DataView;
|
||||
|
||||
use Icinga\Data\ConnectionInterface;
|
||||
use Icinga\Module\Businessprocess\Monitoring\Backend\Ido\Query\ServiceStatusQuery;
|
||||
|
||||
class ServiceStatus extends \Icinga\Module\Monitoring\DataView\Servicestatus
|
||||
{
|
||||
public function __construct(ConnectionInterface $connection, array $columns = null)
|
||||
{
|
||||
parent::__construct($connection, $columns);
|
||||
|
||||
$this->query = new ServiceStatusQuery($connection->getResource(), $columns);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,12 @@
|
|||
namespace Icinga\Module\Businessprocess;
|
||||
|
||||
use Icinga\Module\Businessprocess\Web\Url;
|
||||
use ipl\I18n\Translation;
|
||||
|
||||
class ServiceNode extends MonitoredNode
|
||||
{
|
||||
use Translation;
|
||||
|
||||
protected $hostname;
|
||||
|
||||
/** @var string Alias of the host */
|
||||
|
|
@ -69,7 +72,11 @@ class ServiceNode extends MonitoredNode
|
|||
return null;
|
||||
}
|
||||
|
||||
return $this->getHostAlias() . ': ' . $this->alias;
|
||||
return sprintf(
|
||||
$this->translate('%s on %s', '<service> on <host>'),
|
||||
$this->alias,
|
||||
$this->getHostAlias()
|
||||
);
|
||||
}
|
||||
|
||||
public function getUrl()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Form\Element;
|
||||
|
||||
use ipl\Html\Attributes;
|
||||
use ipl\Html\FormElement\FieldsetElement;
|
||||
|
||||
class IplStateOverrides extends FieldsetElement
|
||||
{
|
||||
/** @var array */
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* Set the options show
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOptions(array $options): self
|
||||
{
|
||||
$this->options = $options;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the options to show
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function getValues()
|
||||
{
|
||||
$cleanedValue = parent::getValues();
|
||||
|
||||
if (! empty($cleanedValue)) {
|
||||
foreach ($cleanedValue as $from => $to) {
|
||||
if ((int) $from === (int) $to) {
|
||||
unset($cleanedValue[$from]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $cleanedValue;
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$states = $this->getOptions();
|
||||
foreach ($states as $state => $label) {
|
||||
if ($state === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->addElement('select', $state, [
|
||||
'label' => $label,
|
||||
'value' => $state,
|
||||
'options' => [$state => $this->translate('Keep actual state')] + $states
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function registerAttributeCallbacks(Attributes $attributes)
|
||||
{
|
||||
parent::registerAttributeCallbacks($attributes);
|
||||
|
||||
$this->getAttributes()
|
||||
->registerAttributeCallback('options', null, [$this, 'setOptions']);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Form\Element;
|
||||
|
||||
class StateOverrides extends FormElement
|
||||
{
|
||||
public $helper = 'formStateOverrides';
|
||||
|
||||
/** @var array The overridable states */
|
||||
protected $states;
|
||||
|
||||
/**
|
||||
* Set the overridable states
|
||||
*
|
||||
* @param array $states
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setStates(array $states)
|
||||
{
|
||||
$this->states = $states;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the overridable states
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getStates()
|
||||
{
|
||||
return $this->states;
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->setIsArray(true);
|
||||
}
|
||||
|
||||
public function setValue($value)
|
||||
{
|
||||
$cleanedValue = [];
|
||||
|
||||
if (! empty($value)) {
|
||||
foreach ($value as $from => $to) {
|
||||
if ((int) $from !== (int) $to) {
|
||||
$cleanedValue[$from] = $to;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::setValue($cleanedValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Form\Validator;
|
||||
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\ServiceNode;
|
||||
use Icinga\Module\Businessprocess\State\IcingaDbState;
|
||||
use Icinga\Module\Businessprocess\State\MonitoringState;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use ipl\I18n\Translation;
|
||||
use ipl\Validator\BaseValidator;
|
||||
use ipl\Web\FormElement\TermInput\Term;
|
||||
use LogicException;
|
||||
|
||||
class HostServiceTermValidator extends BaseValidator
|
||||
{
|
||||
use Translation;
|
||||
|
||||
/** @var ?BpNode */
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* Set the affected process
|
||||
*
|
||||
* @param BpNode $parent
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParent(BpNode $parent): self
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isValid($terms)
|
||||
{
|
||||
if ($this->parent === null) {
|
||||
throw new LogicException('Missing parent process. Cannot validate terms.');
|
||||
}
|
||||
|
||||
if (! is_array($terms)) {
|
||||
$terms = [$terms];
|
||||
}
|
||||
|
||||
$testConfig = new BpConfig();
|
||||
|
||||
foreach ($terms as $term) {
|
||||
/** @var Term $term */
|
||||
[$hostName, $serviceName] = BpConfig::splitNodeName($term->getSearchValue());
|
||||
if ($serviceName !== null && $serviceName !== 'Hoststatus') {
|
||||
$node = $testConfig->createService($hostName, $serviceName);
|
||||
} else {
|
||||
$node = $testConfig->createHost($hostName);
|
||||
if ($serviceName === null) {
|
||||
$term->setSearchValue(BpConfig::joinNodeName($hostName, 'Hoststatus'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->parent->hasChild($term->getSearchValue())) {
|
||||
$term->setMessage($this->translate('Already defined in this process'));
|
||||
} else {
|
||||
$testConfig->getNode('__unbound__')
|
||||
->addChild($node);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->parent->getBpConfig()->getBackend() instanceof MonitoringBackend) {
|
||||
MonitoringState::apply($testConfig);
|
||||
} else {
|
||||
IcingaDbState::apply($testConfig);
|
||||
}
|
||||
|
||||
foreach ($terms as $term) {
|
||||
/** @var Term $term */
|
||||
$node = $testConfig->getNode($term->getSearchValue());
|
||||
if ($node->isMissing()) {
|
||||
if ($node instanceof ServiceNode) {
|
||||
$term->setMessage($this->translate('Service not found'));
|
||||
} else {
|
||||
$term->setMessage($this->translate('Host not found'));
|
||||
}
|
||||
} else {
|
||||
$term->setLabel($node->getAlias());
|
||||
$term->setClass($node->getObjectClassName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Web\Form\Validator;
|
||||
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\BpNode;
|
||||
use Icinga\Module\Businessprocess\Forms\EditNodeForm;
|
||||
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
|
||||
use Zend_Validate_Abstract;
|
||||
|
||||
class NoDuplicateChildrenValidator extends Zend_Validate_Abstract
|
||||
{
|
||||
const CHILD_FOUND = 'childFound';
|
||||
|
||||
/** @var QuickForm */
|
||||
protected $form;
|
||||
|
||||
/** @var BpConfig */
|
||||
protected $bp;
|
||||
|
||||
/** @var BpNode */
|
||||
protected $parent;
|
||||
|
||||
/** @var string */
|
||||
protected $label;
|
||||
|
||||
public function __construct(QuickForm $form, BpConfig $bp, BpNode $parent = null)
|
||||
{
|
||||
$this->form = $form;
|
||||
$this->bp = $bp;
|
||||
$this->parent = $parent;
|
||||
|
||||
$this->_messageVariables['label'] = 'label';
|
||||
$this->_messageTemplates = [
|
||||
self::CHILD_FOUND => mt('businessprocess', '%label% is already defined in this process')
|
||||
];
|
||||
}
|
||||
|
||||
public function isValid($value)
|
||||
{
|
||||
if ($this->parent === null) {
|
||||
$found = $this->bp->hasRootNode($value);
|
||||
} elseif ($this->form instanceof EditNodeForm && $this->form->getNode()->getName() === $value) {
|
||||
$found = false;
|
||||
} else {
|
||||
$found = $this->parent->hasChild($value);
|
||||
}
|
||||
|
||||
if (! $found) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->label = $this->form->getElement('children')->getMultiOptions()[$value];
|
||||
$this->_error(self::CHILD_FOUND);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -869,29 +869,6 @@ form.bp-form {
|
|||
}
|
||||
}
|
||||
|
||||
#stateOverrides-element {
|
||||
display: inline-table;
|
||||
table-layout: fixed;
|
||||
border-spacing: .5em;
|
||||
padding: 0;
|
||||
|
||||
label {
|
||||
display: table-row;
|
||||
|
||||
span, select {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
span {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
select {
|
||||
width: 26em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 36em;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class ServiceNodeTest extends BaseTestCase
|
|||
public function testReturnsCorrectAlias()
|
||||
{
|
||||
$this->assertEquals(
|
||||
'localhost: ping <> pong',
|
||||
'ping <> pong on localhost',
|
||||
$this->pingOnLocalhost()->getAlias()
|
||||
);
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ class ServiceNodeTest extends BaseTestCase
|
|||
{
|
||||
$this->assertEquals(
|
||||
'<a href="/icingaweb2/businessprocess/service/show?host=localhost&service=ping%20%3C%3E%20pong">'
|
||||
. 'localhost: ping <> pong</a>',
|
||||
. 'ping <> pong on localhost</a>',
|
||||
$this->pingOnLocalhost()->getLink()->render()
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue