mirror of
https://github.com/Icinga/icingadb-web.git
synced 2026-02-03 20:40:15 -05:00
Provide integration for Icinga Notifications Web
This commit is contained in:
parent
0a3b0b9afb
commit
a0c9f03a78
2 changed files with 211 additions and 0 deletions
207
library/Icingadb/ProvidedHook/Notifications/V1/Source.php
Normal file
207
library/Icingadb/ProvidedHook/Notifications/V1/Source.php
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2025 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\ProvidedHook\Notifications\V1;
|
||||
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Module\Icingadb\Common\Backend;
|
||||
use Icinga\Module\Icingadb\Model\Host;
|
||||
use Icinga\Module\Icingadb\Model\Service;
|
||||
use Icinga\Module\Notifications\Hook\V1\SourceHook;
|
||||
use InvalidArgumentException;
|
||||
use ipl\Html\Attributes;
|
||||
use ipl\Html\Contract\Form;
|
||||
use ipl\Html\HtmlDocument;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Html\Text;
|
||||
use ipl\I18n\Translation;
|
||||
use ipl\Sql\Expression;
|
||||
use ipl\Stdlib\Filter;
|
||||
use ipl\Stdlib\Filter\Condition;
|
||||
use ipl\Web\Control\SearchBar\SearchException;
|
||||
use ipl\Web\Control\SearchEditor;
|
||||
use ipl\Web\Filter\QueryString;
|
||||
use ipl\Web\Filter\Renderer;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\IcingaIcon;
|
||||
use ipl\Web\Widget\Icon;
|
||||
use JsonException;
|
||||
|
||||
class Source implements SourceHook
|
||||
{
|
||||
use Translation;
|
||||
|
||||
/** @var string */
|
||||
public const TYPE_ALL = 'all';
|
||||
|
||||
/** @var array<string, string> */
|
||||
private array $allowedColumns;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->allowedColumns = [
|
||||
'host.name' => $this->translate('Host Name'),
|
||||
'hostgroup.name' => $this->translate('Hostgroup Name'),
|
||||
'host.user.name' => $this->translate('Contact Name'),
|
||||
'host.usergroup.name' => $this->translate('Contactgroup Name'),
|
||||
'service.name' => $this->translate('Service Name'),
|
||||
'servicegroup.name' => $this->translate('Servicegroup Name'),
|
||||
'service.user.name' => $this->translate('Contact Name'),
|
||||
'service.usergroup.name' => $this->translate('Contactgroup Name')
|
||||
];
|
||||
}
|
||||
|
||||
public function getSourceType(): string
|
||||
{
|
||||
return 'icinga2';
|
||||
}
|
||||
|
||||
public function getSourceLabel(): string
|
||||
{
|
||||
return 'Icinga';
|
||||
}
|
||||
|
||||
public function getSourceIcon(): Icon
|
||||
{
|
||||
return new IcingaIcon('icinga');
|
||||
}
|
||||
|
||||
public function getRuleFilterTargets(int $sourceId): array
|
||||
{
|
||||
return [
|
||||
'host' => $this->translate('Hosts only'),
|
||||
'service' => $this->translate('Services only'),
|
||||
self::TYPE_ALL => $this->translate('Hosts and Services')
|
||||
];
|
||||
}
|
||||
|
||||
public function getRuleFilterEditor(string $filter): SearchEditor
|
||||
{
|
||||
if ($filter === 'host' || $filter === 'service' || $filter === self::TYPE_ALL) {
|
||||
$type = $filter;
|
||||
$filter = '';
|
||||
} else {
|
||||
try {
|
||||
$data = json_decode($filter, true, flags: JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
Logger::error('Failed to parse rule filter configuration: %s (Error: %s)', $filter, $e);
|
||||
throw new ConfigurationError($this->translate(
|
||||
'Failed to parse rule filter configuration. Please contact your system administrator.'
|
||||
));
|
||||
}
|
||||
|
||||
if ($data['version'] !== 1 || ! isset($data['config']['type']) || ! isset($data['config']['filter'])) {
|
||||
Logger::error('Invalid rule filter configuration: %s', $filter);
|
||||
throw new ConfigurationError($this->translate(
|
||||
'Invalid rule filter configuration. Please contact your system administrator.'
|
||||
));
|
||||
}
|
||||
|
||||
$type = $data['config']['type'];
|
||||
$filter = $data['config']['filter'];
|
||||
}
|
||||
|
||||
$editor = new SearchEditor();
|
||||
$editor->setQueryString($filter);
|
||||
$editor->setSuggestionUrl(Url::fromPath(
|
||||
'icingadb/suggest/restriction-column',
|
||||
['_disableLayout' => true, 'showCompact' => true, 'type' => $type]
|
||||
));
|
||||
$editor->getParser()->on(QueryString::ON_CONDITION, function (Condition $condition) {
|
||||
if ($condition->getColumn()) {
|
||||
if (array_key_exists($condition->getColumn(), $this->allowedColumns)) {
|
||||
$condition->metaData()->set('columnLabel', $this->allowedColumns[$condition->getColumn()]);
|
||||
} elseif (preg_match('/^(host|service)\.vars\.(.*)/i', $condition->getColumn(), $m)) {
|
||||
$prefix = $m[1] === 'host' ? $this->translate('Host') : $this->translate('Service');
|
||||
$condition->metaData()->set('columnLabel', $prefix . ' ' . $m[2]);
|
||||
}
|
||||
}
|
||||
});
|
||||
$editor->on(SearchEditor::ON_VALIDATE_COLUMN, function (Condition $condition) {
|
||||
if (! array_key_exists($condition->getColumn(), $this->allowedColumns)) {
|
||||
if (! preg_match('/^(?:host|service)\.vars\./i', $condition->getColumn())) {
|
||||
throw new SearchException($this->translate('Is not a valid column'));
|
||||
}
|
||||
}
|
||||
})->on(HtmlDocument::ON_ASSEMBLED, function (SearchEditor $editor) use ($type) {
|
||||
$editor->prependHtml(new HtmlElement(
|
||||
'p',
|
||||
Attributes::create(['class' => 'description']),
|
||||
Text::create(
|
||||
match ($type) {
|
||||
'host' => $this->translate(
|
||||
'Only hosts matching the following criteria will be affected.'
|
||||
),
|
||||
'service' => $this->translate(
|
||||
'Only services matching the following criteria will be affected.'
|
||||
),
|
||||
self::TYPE_ALL => $this->translate(
|
||||
'All hosts and services matching the following criteria will be affected.'
|
||||
)
|
||||
}
|
||||
)
|
||||
));
|
||||
|
||||
// Not using addElement, as otherwise the submit button is hidden because it's not last-of-type
|
||||
$hidden = $editor->createElement('hidden', 'type', ['value' => $type]);
|
||||
$editor->registerElement($hidden);
|
||||
$editor->prependHtml($hidden);
|
||||
});
|
||||
|
||||
return $editor;
|
||||
}
|
||||
|
||||
public function serializeRuleFilter(Form $editor): string
|
||||
{
|
||||
if (! $editor instanceof SearchEditor) {
|
||||
throw new InvalidArgumentException('Editor must be an instance of ' . SearchEditor::class);
|
||||
}
|
||||
|
||||
$rule = $editor->getFilter();
|
||||
$filter = (new Renderer($rule))->render();
|
||||
if ($filter === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$type = $editor->getElement('type')->getValue();
|
||||
|
||||
$queries = [];
|
||||
if ($type === 'host' || $type === self::TYPE_ALL) {
|
||||
$queries['host'] = Host::on(Backend::getDb())
|
||||
->filter(Filter::all(
|
||||
Filter::equal('host.id', ':host_id'),
|
||||
Filter::equal('host.environment_id', ':environment_id')
|
||||
));
|
||||
}
|
||||
|
||||
if ($type === 'service' || $type === self::TYPE_ALL) {
|
||||
$queries['service'] = Service::on(Backend::getDb())
|
||||
->filter(Filter::all(
|
||||
Filter::equal('service.id', ':service_id'),
|
||||
Filter::equal('service.environment_id', ':environment_id')
|
||||
));
|
||||
}
|
||||
|
||||
return json_encode([
|
||||
'version' => 1,
|
||||
'config' => [
|
||||
'type' => $type,
|
||||
'filter' => $filter
|
||||
],
|
||||
'queries' => array_map(function ($query) use ($rule) {
|
||||
$query->columns([new Expression('1')])->filter($rule)->limit(1);
|
||||
|
||||
[$query, $parameters] = $query->getDb()->getQueryBuilder()->assembleSelect(
|
||||
$query->assembleSelect()->resetOrderBy()
|
||||
);
|
||||
|
||||
return [
|
||||
'query' => $query,
|
||||
'parameters' => $parameters
|
||||
];
|
||||
}, $queries)
|
||||
], JSON_THROW_ON_ERROR);
|
||||
}
|
||||
}
|
||||
4
run.php
4
run.php
|
|
@ -13,6 +13,10 @@ $this->provideHook('Reporting/Report', 'Reporting/TotalHostSlaReport');
|
|||
$this->provideHook('Reporting/Report', 'Reporting/ServiceSlaReport');
|
||||
$this->provideHook('Reporting/Report', 'Reporting/TotalServiceSlaReport');
|
||||
|
||||
if ($this::exists('notifications')) {
|
||||
$this->provideHook('Notifications/v1/Source');
|
||||
}
|
||||
|
||||
if ($this::exists('reporting')) {
|
||||
$this->provideHook('Icingadb/HostActions', 'CreateHostSlaReport');
|
||||
$this->provideHook('Icingadb/ServiceActions', 'CreateServiceSlaReport');
|
||||
|
|
|
|||
Loading…
Reference in a new issue