mirror of
https://github.com/Icinga/icingaweb2-module-director.git
synced 2026-06-04 22:32:55 -04:00
445 lines
16 KiB
PHP
445 lines
16 KiB
PHP
<?php
|
|
|
|
namespace Icinga\Module\Director\Controllers;
|
|
|
|
use Icinga\Application\Config;
|
|
use Icinga\Module\Director\Db;
|
|
use Icinga\Module\Director\Forms\DeleteCustomVariableForm;
|
|
use Icinga\Module\Director\Forms\CustomVariableForm;
|
|
use Icinga\Module\Director\Web\Table\CustomvarVariantsTable;
|
|
use Icinga\Module\Director\Web\Widget\CustomVarObjectList;
|
|
use Icinga\Module\Director\Web\Widget\CustomVarFieldsTable;
|
|
use Icinga\Web\Notification;
|
|
use ipl\Html\HtmlElement;
|
|
use ipl\Html\Text;
|
|
use ipl\Web\Compat\CompatController;
|
|
use ipl\Web\Url;
|
|
use ipl\Web\Widget\ButtonLink;
|
|
use ipl\Web\Widget\EmptyStateBar;
|
|
use ipl\Web\Widget\ListItem;
|
|
use ipl\Web\Widget\Tabs;
|
|
use Ramsey\Uuid\Uuid;
|
|
use Ramsey\Uuid\UuidInterface;
|
|
use Zend_Db;
|
|
use Zend_Db_Expr;
|
|
|
|
class CustomvarController extends CompatController
|
|
{
|
|
/** @var Db */
|
|
protected $db;
|
|
|
|
/** @var ?UuidInterface */
|
|
private ?UuidInterface $uuid = null;
|
|
|
|
/** @var ?UuidInterface */
|
|
private ?UuidInterface $parentUuid = null;
|
|
|
|
public function init()
|
|
{
|
|
parent::init();
|
|
|
|
$uuid = $this->params->shift('uuid');
|
|
if ($uuid !== null) {
|
|
$this->uuid = Uuid::fromString($uuid);
|
|
$parentUuid = $this->params->shift('parent_uuid');
|
|
|
|
if ($parentUuid) {
|
|
$this->parentUuid = Uuid::fromString($parentUuid);
|
|
}
|
|
}
|
|
|
|
$this->db = Db::fromResourceName(
|
|
Config::module('director')->get('db', 'resource')
|
|
);
|
|
}
|
|
|
|
public function indexAction()
|
|
{
|
|
$uuid = $this->uuid;
|
|
$parentUuid = $this->parentUuid ?? null;
|
|
$parent = [];
|
|
$db = $this->db->getDbAdapter();
|
|
$property = $this->fetchProperty($uuid);
|
|
if (empty($property)) {
|
|
$this->redirectNow(Url::fromPath('director/variables'));
|
|
}
|
|
|
|
if ($parentUuid) {
|
|
$parentUuid = Uuid::fromString($parentUuid);
|
|
$parent = $this->fetchProperty($parentUuid);
|
|
|
|
if ($parent['parent_uuid'] !== null) {
|
|
$usedCount = $this->fetchPropertyUsedCount(Uuid::fromBytes(
|
|
Db\DbUtil::binaryResult($parent['parent_uuid'])
|
|
));
|
|
} else {
|
|
$usedCount = $this->fetchPropertyUsedCount($parentUuid);
|
|
}
|
|
} else {
|
|
$usedCount = $this->fetchPropertyUsedCount($uuid);
|
|
}
|
|
|
|
$property['used_count'] = $usedCount;
|
|
|
|
if ($property['value_type'] === 'dynamic-array' || str_starts_with($property['value_type'], 'datalist-')) {
|
|
$itemTypeQuery = $db
|
|
->select()->from('director_property', 'value_type')
|
|
->where(
|
|
'parent_uuid = ? AND key_name = \'0\'',
|
|
Db\DbUtil::quoteBinaryCompat($uuid->getBytes(), $db)
|
|
);
|
|
|
|
$property['item_type'] = $db->fetchOne($itemTypeQuery);
|
|
}
|
|
|
|
if (str_starts_with($property['value_type'], 'datalist-')) {
|
|
$datalistId = $db
|
|
->select()->from(['dl' => 'director_datalist'], 'id')
|
|
->join(['dpl' => 'director_property_datalist'], 'dpl.list_uuid = dl.uuid', [])
|
|
->where(
|
|
'dpl.property_uuid = ?',
|
|
Db\DbUtil::quoteBinaryCompat($uuid->getBytes(), $db)
|
|
);
|
|
|
|
$property['list'] = $db->fetchOne($datalistId);
|
|
}
|
|
|
|
$showFields = $this->showFields($property['value_type']);
|
|
$propertyForm = (new CustomVariableForm($this->db, $uuid, $parentUuid !== null, $parentUuid))
|
|
->populate($property)
|
|
->setAction(Url::fromRequest()->getAbsoluteUrl())
|
|
->on(CustomVariableForm::ON_SENT, function (CustomVariableForm $form) use ($property, &$showFields) {
|
|
$showFields = $showFields && $form->getValue('value_type') === $property['value_type'];
|
|
})
|
|
->on(CustomVariableForm::ON_SUBMIT, function (CustomVariableForm $form) {
|
|
Notification::success(sprintf(
|
|
$this->translate('Custom variable configuration "%s" has successfully been saved'),
|
|
$form->getValue('key_name')
|
|
));
|
|
|
|
$this->sendExtraUpdates(['#col1']);
|
|
$redirectUrl = Url::fromPath(
|
|
'director/customvar',
|
|
['uuid' => $form->getUUid()->toString()]
|
|
);
|
|
|
|
if ($form->getParentUUid()) {
|
|
$redirectUrl->addParams(['parent_uuid' => $form->getParentUUid()->toString()]);
|
|
}
|
|
|
|
$this->redirectNow($redirectUrl);
|
|
});
|
|
|
|
if ($parent) {
|
|
$propertyForm
|
|
->setHideKeyNameElement($parent['value_type'] === 'fixed-array')
|
|
->setIsNestedField($parent['parent_uuid'] !== null);
|
|
}
|
|
|
|
$propertyForm->handleRequest($this->getServerRequest());
|
|
$this->addContent($propertyForm);
|
|
|
|
if ($showFields) {
|
|
$this->addContent(new HtmlElement('h2', null, Text::create($this->translate('Fields'))));
|
|
$button = (new ButtonLink(
|
|
Text::create($this->translate('Create Field')),
|
|
Url::fromPath('director/customvar/add-field', [
|
|
'uuid' => $uuid->toString()
|
|
]),
|
|
null,
|
|
['class' => 'control-button']
|
|
))->openInModal();
|
|
|
|
$fieldQuery = $db
|
|
->select()
|
|
->from(['dp' => 'director_property'], [])
|
|
->joinLeft(['ihp' => 'icinga_host_property'], 'ihp.property_uuid = dp.parent_uuid', [])
|
|
->columns([
|
|
'uuid',
|
|
'parent_uuid',
|
|
'key_name',
|
|
'category_id',
|
|
'value_type',
|
|
'label',
|
|
'description',
|
|
'used_count' => $property['used_count'] > 0 ? 'COUNT(1)' : '0',
|
|
])
|
|
->where('parent_uuid = ?', Db\DbUtil::quoteBinaryCompat($uuid->getBytes(), $db))
|
|
->group('dp.uuid')
|
|
->order('key_name');
|
|
|
|
$this->addContent($button);
|
|
|
|
$fields = $db->fetchAll($fieldQuery);
|
|
|
|
if (empty($fields)) {
|
|
$this->addContent(
|
|
new EmptyStateBar(
|
|
$this->translate('No fields have been added yet')
|
|
)
|
|
);
|
|
} else {
|
|
$this->addContent(new CustomVarFieldsTable($fields, true));
|
|
}
|
|
}
|
|
|
|
if ($parentUuid) {
|
|
$keyName = $parent['value_type'] === 'fixed-array'
|
|
? $property['label']
|
|
: $property['key_name'];
|
|
|
|
$title = $this->translate('Edit Field') . ': ' . $keyName;
|
|
} else {
|
|
$title = $this->translate('Custom Variable') . ': ' . $property['key_name'];
|
|
}
|
|
|
|
$this->setTitle($title);
|
|
$this->setTitleTab('customvar');
|
|
$this->setAutorefreshInterval(10);
|
|
}
|
|
|
|
public function usageAction(): void
|
|
{
|
|
$objectClass = null;
|
|
$usageList = (new CustomVarObjectList($this->fetchCustomVarUsage()))
|
|
->setDetailActionsDisabled(false)
|
|
->on(
|
|
CustomVarObjectList::BEFORE_ITEM_ADD,
|
|
function (ListItem $item, $data) use (&$objectClass, &$usageList) {
|
|
if ($objectClass !== $data->object_class) {
|
|
$usageList->addHtml(
|
|
HtmlElement::create(
|
|
'li',
|
|
['class' => 'list-item'],
|
|
HtmlElement::create('h2', content: ucfirst($data->object_class) . 's')
|
|
)
|
|
);
|
|
$objectClass = $data->object_class;
|
|
}
|
|
}
|
|
);
|
|
|
|
$this->addContent($usageList);
|
|
|
|
$this->setTitle($this->translate('Custom Variable Usage'));
|
|
$this->setTitleTab('usage');
|
|
$this->setAutorefreshInterval(10);
|
|
}
|
|
|
|
/**
|
|
* Fetch the give custom variable usage in templates
|
|
*
|
|
* @return array
|
|
*/
|
|
private function fetchCustomVarUsage(): array
|
|
{
|
|
$uuid = $this->uuid;
|
|
$property = $this->fetchProperty($uuid);
|
|
$db = $this->db->getDbAdapter();
|
|
if (isset($property['parent_uuid'])) {
|
|
$parentUuid = Uuid::fromBytes(Db\DbUtil::binaryResult($property['parent_uuid']));
|
|
$this->parentUuid = $parentUuid;
|
|
$parentProperty = $this->fetchProperty($parentUuid);
|
|
if (isset($parentProperty['parent_uuid'])) {
|
|
$rootUuid = Uuid::fromBytes(Db\DbUtil::binaryResult($parentProperty['parent_uuid']));
|
|
} else {
|
|
$rootUuid = $parentUuid;
|
|
}
|
|
|
|
$uuid = $rootUuid;
|
|
}
|
|
|
|
$objectClasses = ['host', 'service', 'notification', 'command', 'user'];
|
|
$usage = [];
|
|
|
|
foreach ($objectClasses as $objectClass) {
|
|
$customPropertyQuery = $db
|
|
->select()
|
|
->from(['io' => "icinga_$objectClass"], [])
|
|
->join(['iov' => "icinga_$objectClass" . '_var'], "io.id = iov.$objectClass" . '_id', [])
|
|
->join(['dp' => 'director_property'], 'iov.property_uuid = dp.uuid', []);
|
|
|
|
$unionQuery = $db
|
|
->select()
|
|
->from(['io' => "icinga_$objectClass"], [])
|
|
->join(['iop' => "icinga_$objectClass" . '_property'], "iop.$objectClass" . '_uuid = io.uuid', [])
|
|
->join(['dp' => 'director_property'], 'iop.property_uuid = dp.uuid', []);
|
|
|
|
$columns = [
|
|
'name' => 'io.object_name',
|
|
'type' => 'io.object_type',
|
|
'object_class' => new Zend_Db_Expr("'$objectClass'")
|
|
];
|
|
|
|
if ($objectClass === 'service') {
|
|
$customPropertyQuery = $customPropertyQuery->joinLeft(
|
|
['ioh' => 'icinga_host'],
|
|
'io.host_id = ioh.id',
|
|
[]
|
|
);
|
|
$unionQuery = $unionQuery->joinLeft(['ioh' => 'icinga_host'], 'io.host_id = ioh.id', []);
|
|
$columns['host_name'] = 'ioh.object_name';
|
|
}
|
|
|
|
$customPropertyQuery = $customPropertyQuery
|
|
->columns($columns)
|
|
->where('dp.uuid = ?', Db\DbUtil::quoteBinaryCompat($uuid->getBytes(), $db));
|
|
|
|
$unionQuery = $unionQuery
|
|
->columns($columns)
|
|
->where('dp.uuid = ?', Db\DbUtil::quoteBinaryCompat($uuid->getBytes(), $db));
|
|
|
|
$usage[] = $db->fetchAll($db->select()->union([$customPropertyQuery, $unionQuery]));
|
|
}
|
|
|
|
return array_merge(...$usage);
|
|
}
|
|
|
|
private function showFields(string $type): bool
|
|
{
|
|
return in_array($type, ['fixed-array', 'fixed-dictionary', 'dynamic-dictionary'], true);
|
|
}
|
|
|
|
public function addFieldAction()
|
|
{
|
|
$uuid = $this->uuid;
|
|
$this->addTitleTab($this->translate('Create Field'));
|
|
$uuid = Uuid::fromString($uuid);
|
|
|
|
$parent = $this->fetchProperty($uuid);
|
|
$propertyForm = (new CustomVariableForm($this->db, null, true, $uuid))
|
|
->setHideKeyNameElement($parent['value_type'] === 'fixed-array')
|
|
->setIsNestedField($parent['parent_uuid'] !== null)
|
|
->setAction(Url::fromRequest()->getAbsoluteUrl())
|
|
->on(CustomVariableForm::ON_SUBMIT, function (CustomVariableForm $form) {
|
|
Notification::success(sprintf(
|
|
$this->translate('Custom variable configuration "%s" has successfully been saved'),
|
|
$form->getValue('key_name')
|
|
));
|
|
|
|
$this->sendExtraUpdates(['#col1']);
|
|
$this->redirectNow(
|
|
Url::fromPath('director/customvar', ['uuid' => $form->getParentUUid()->toString()])
|
|
);
|
|
})
|
|
->handleRequest($this->getServerRequest());
|
|
|
|
$this->addContent($propertyForm);
|
|
}
|
|
|
|
public function deleteAction(): void
|
|
{
|
|
$uuid = $this->uuid;
|
|
$property = $this->fetchProperty($uuid);
|
|
$parent = [];
|
|
if ($property['parent_uuid'] !== null) {
|
|
$parent = $this->fetchProperty(Uuid::fromBytes($property['parent_uuid']));
|
|
}
|
|
|
|
$form = (new DeleteCustomVariableForm($this->db, $property, $parent))
|
|
->setAction(Url::fromRequest()->getAbsoluteUrl())
|
|
->on(DeleteCustomVariableForm::ON_SUBMIT, function () {
|
|
Notification::success($this->translate('Custom variable configuration has been successfully deleted'));
|
|
$this->sendExtraUpdates(['#col1']);
|
|
$this->redirectNow('__CLOSE__');
|
|
})
|
|
->handleRequest($this->getServerRequest());
|
|
|
|
$this->addContent($form);
|
|
|
|
$this->setTitle($this->translate('Delete Property') . ': ' . $property['key_name']);
|
|
}
|
|
|
|
public function variantsAction()
|
|
{
|
|
$varName = $this->params->getRequired('name');
|
|
$title = sprintf($this->translate('Custom Variable variants: %s'), $varName);
|
|
$this->setTitle($title);
|
|
$this->addTitleTab($title);
|
|
$this->addContent(CustomvarVariantsTable::create($this->db, $varName));
|
|
}
|
|
|
|
/**
|
|
* Fetch property for the given UUID
|
|
*
|
|
* @param UuidInterface $uuid UUID of the given property
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function fetchProperty(UuidInterface $uuid): array
|
|
{
|
|
$db = $this->db->getDbAdapter();
|
|
|
|
$query = $db
|
|
->select()
|
|
->from(['dp' => 'director_property'], [])
|
|
->joinLeft(['ihp' => 'icinga_host_property'], 'ihp.property_uuid = dp.uuid', [])
|
|
->columns([
|
|
'key_name',
|
|
'uuid',
|
|
'parent_uuid',
|
|
'category_id',
|
|
'value_type',
|
|
'label',
|
|
'description'
|
|
])
|
|
->where('uuid = ?', Db\DbUtil::quoteBinaryCompat($uuid->getBytes(), $db));
|
|
|
|
return $db->fetchRow($query, [], Zend_Db::FETCH_ASSOC) ?: [];
|
|
}
|
|
|
|
private function fetchPropertyUsedCount(UuidInterface $uuid): int
|
|
{
|
|
$db = $this->db->getDbAdapter();
|
|
|
|
$query = $db
|
|
->select()
|
|
->from(['dp' => 'director_property'], [])
|
|
->joinLeft(['ihp' => 'icinga_host_property'], 'ihp.property_uuid = dp.uuid', [])
|
|
->joinLeft(['isp' => 'icinga_service_property'], 'isp.property_uuid = dp.uuid', [])
|
|
->joinLeft(['iup' => 'icinga_user_property'], 'isp.property_uuid = dp.uuid', [])
|
|
->joinLeft(['icp' => 'icinga_command_property'], 'isp.property_uuid = dp.uuid', [])
|
|
->joinLeft(['inp' => 'icinga_notification_property'], 'isp.property_uuid = dp.uuid', [])
|
|
->columns([
|
|
'used_count' => 'COUNT(ihp.property_uuid) + COUNT(isp.property_uuid)'
|
|
. ' + COUNT(iup.property_uuid) + COUNT(icp.property_uuid)'
|
|
. ' + COUNT(inp.property_uuid)'
|
|
])
|
|
->where('uuid = ?', Db\DbUtil::quoteBinaryCompat($uuid->getBytes(), $db));
|
|
|
|
return (int) $db->fetchOne($query);
|
|
}
|
|
|
|
protected function setTitleTab(string $name): void
|
|
{
|
|
$tab = $this->createTabs()->get($name);
|
|
|
|
if ($tab !== null) {
|
|
$this->getTabs()->activate($name);
|
|
}
|
|
}
|
|
|
|
protected function createTabs(): Tabs
|
|
{
|
|
$url = Url::fromPath('director/customvar', ['uuid' => $this->uuid->toString()]);
|
|
if ($this->parentUuid) {
|
|
$url->addParams(['parent_uuid' => $this->parentUuid->toString()]);
|
|
$label = $this->translate('Edit Field');
|
|
} else {
|
|
$label = $this->translate('Custom Variable');
|
|
}
|
|
|
|
return $this->getTabs()
|
|
->add('customvar', [
|
|
'label' => $label,
|
|
'url' => $url
|
|
])
|
|
->add('usage', [
|
|
'label' => $this->translate('Custom Variable Usage'),
|
|
'url' => Url::fromPath(
|
|
'director/customvar/usage',
|
|
['uuid' => $this->uuid->toString()]
|
|
)
|
|
]);
|
|
}
|
|
}
|