Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
raviks789 committed Aug 27, 2024
1 parent 334aaf8 commit 2d1b93e
Show file tree
Hide file tree
Showing 7 changed files with 541 additions and 11 deletions.
71 changes: 71 additions & 0 deletions library/Icingadb/Hook/CustomVarEnricherHook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

/** Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */

namespace Icinga\Module\Icingadb\Hook;

use Icinga\Application\Hook;
use Icinga\Application\Logger;
use Icinga\Module\Icingadb\Hook\Common\HookUtils;
use ipl\Orm\Model;
use Throwable;

abstract class CustomVarEnricherHook
{
use HookUtils;

/**
* Return the grouped custom vars
*
* @return array
*/
abstract public function getGroups(): array;

/**
* Return a group name for the given variable name
*
* @param array $vars
*
* @return array
*/
abstract public function enrichCustomVars(array $vars, Model $object): array;

public static function prepareEnrichedCustomVars(array $vars, Model $object): array
{
$enrichedVars = [];

$groups = [];
foreach (Hook::all('Icingadb/CustomVarEnricher') as $hook) {
/** @var self $hook */
try {
$enrichedVars[] = $hook->enrichCustomVars($vars, $object);
$groups[] = $hook->getGroups();
} catch (Throwable $e) {
Logger::error('Failed to load hook %s:', get_class($hook), $e);
}
}

$enrichedVars = array_merge([], ...$enrichedVars);
$groups = array_merge([], ...$groups);
foreach ($vars as $key => $var) {
if (array_key_exists($key, $enrichedVars)) {
$label = key($enrichedVars[$key]);
$vars[$label] = $enrichedVars[$key][$label];

unset($vars[$key]);

$key = $label;
}

foreach ($groups as $group) {
if (array_key_exists($key, $group)) {
unset($vars[$key]);

break;
}
}
}

return [$vars, $groups];
}
}
179 changes: 179 additions & 0 deletions library/Icingadb/ProvidedHook/Icingadb/CustomVarEnricher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<?php

namespace Icinga\Module\Icingadb\ProvidedHook\Icingadb;

use Icinga\Application\Config;
use Icinga\Module\Director\Data\Db\DbConnection;
use Icinga\Module\Director\DataType\DataTypeDatalist;
use Icinga\Module\Director\DataType\DataTypeDictionary;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\DirectorDatafield;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaService;
use Icinga\Module\Director\Web\Form\IcingaObjectFieldLoader;
use Icinga\Module\Icingadb\Hook\CustomVarEnricherHook;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Model\Service;
use ipl\Orm\Model;

class CustomVarEnricher extends CustomVarEnricherHook
{
protected $fieldConfig;

protected $datalistMaps;

protected $groups = [];

public function prefetchForObject(Model $object): bool
{
return false;
}

public function renderCustomVarKey(string $key)
{
return $key;
}

public function renderCustomVarValue(string $key, $value)
{
return $value;
}

public function identifyCustomVarGroup(string $key): ?string
{
return null;
}

public function enrichCustomVars(array $vars, Model $object): array
{
$directorObject = null;
$connection = Db::fromResourceName(Config::module('director')->get('db', 'resource'));
if ($object instanceof Host) {
$directorObject = IcingaHost::load($object->name, $connection);
} elseif ($object instanceof Service) {
$directorHost = IcingaHost::load($object->host->name, $connection);
$directorObject = IcingaService::load(
['object_name' => $object->name, 'host_id' => $directorHost->get('id')],
$connection
);
}

$newVars = [];
$this->fieldConfig = (new IcingaObjectFieldLoader($directorObject))->getFields();

$this->buildDataListMap($connection);
if ($directorObject) {
foreach ($vars as $varName => $customVar) {
$newVars[$varName] = $this->resolveCustomVarMapping($varName, $customVar, $connection);
}
} else {
$newVars = $vars;
}

return $newVars;
}

/**
* Returns the resolved mapping to custom variables in Director
*
* @param string $name
* @param $val
* @param DbConnection $conn
* @param bool $grouping Whether to enable grouping of custom variables into sections
*
* @return array
*/
protected function resolveCustomVarMapping(string $name, $val, DbConnection $conn, bool $grouping = true): array
{
if (isset($this->fieldConfig[$name])) {
/** @var DirectorDatafield $field */
$field = $this->fieldConfig[$name];
$dataType = $field->get('datatype');

if ($dataType === get_class(new DataTypeDictionary())) {
$label = $field->get('caption');
$newVarValue = [];
foreach ($val as $nestedVarName => $nestedVarValue) {
if (isset($this->fieldConfig[$nestedVarName]) && is_array($nestedVarValue)) {
$childValues = [];
foreach ($nestedVarValue as $childName => $childValue) {
$childValues[] = $this->resolveCustomVarMapping($childName, $childValue, $conn, false);
}

$newVarValue[] = [$nestedVarName => array_merge([], ...$childValues)];
} else {
$newVarValue[] = $this->resolveCustomVarMapping(
$nestedVarName,
$nestedVarValue,
$conn,
false
);
}
}

return [$label => array_merge([], ...$newVarValue)];
} elseif ($dataType === get_class(new DataTypeDatalist())) {
if (isset($this->datalistMaps[$name])) {
$val = $this->datalistMaps[$name][$val];
}

$name = $field->get('caption');
} else {
$name = $field->get('caption');
}

if ($grouping && $field->get('category_id') !== null) {
if (! isset($this->groups[$field->getCategoryName()])) {
$this->groups[$field->getCategoryName()] = [$name => $val];
} else {
$this->groups[$field->getCategoryName()][$name] = $val;
}
}
} elseif (is_array($val)) {
$newValue = [];
foreach ($val as $childName => $childValue) {
$newValue[] = $this->resolveCustomVarMapping($childName, $childValue, $conn, false);
}

$val = array_merge([], ...$newValue);
}

return [$name => $val];
}

private function buildDataListMap(DbConnection $db)
{
$fieldsWithDataLists = [];
foreach ($this->fieldConfig as $field) {
if ($field->get('datatype') === 'Icinga\Module\Director\DataType\DataTypeDatalist') {
$fieldsWithDataLists[$field->get('id')] = $field;
}
}

if (! empty($fieldsWithDataLists)) {
$dataListEntries = $db->select()->from(
['dds' => 'director_datafield_setting'],
[
'dds.datafield_id',
'dde.entry_name',
'dde.entry_value'
]
)->join(
['dde' => 'director_datalist_entry'],
'CAST(dds.setting_value AS integer) = dde.list_id',
[]
)->where('dds.datafield_id', array_keys($fieldsWithDataLists))
->where('dds.setting_name', 'datalist_id');

foreach ($dataListEntries as $dataListEntry) {
$field = $fieldsWithDataLists[$dataListEntry->datafield_id];
$this->datalistMaps[$field->get('varname')][$dataListEntry->entry_name] = $dataListEntry->entry_value;
}
}
}

public function getGroups(): array
{
return $this->groups;
}
}
24 changes: 24 additions & 0 deletions library/Icingadb/ProvidedHook/Icingadb/CustomVarItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/** Icinga DB Web | (c) 2024 Icinga GmbH | GPLv2 */

namespace Icinga\Module\Icingadb\Common;

use ipl\Html\BaseHtmlElement;
use ipl\Html\ValidHtml;

class CustomVarItem extends BaseHtmlElement
{
// TODO: Class for an item in custom HTML Section
protected $item;

public function __construct(ValidHtml $item)
{
$this->item = $item;
}

protected function assemble()
{
$this->addHtml($this->item);
}
}
23 changes: 23 additions & 0 deletions library/Icingadb/ProvidedHook/Icingadb/CustomVarSection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/** Icinga DB Web | (c) 2024 Icinga GmbH | GPLv2 */

namespace Icinga\Module\Icingadb\Common;

use ipl\Html\BaseHtmlElement;

class CustomVarSection extends BaseHtmlElement
{
// TODO: Class for custom HTML section
protected $items;

public function addItem(CustomVarItem $item)
{
$this->items[] = $item;
}

public function assemble()
{
$this->addHtml($this->items);
}
}
36 changes: 25 additions & 11 deletions library/Icingadb/Widget/Detail/CustomVarTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

namespace Icinga\Module\Icingadb\Widget\Detail;

use Icinga\Module\Icingadb\Hook\CustomVarEnricherHook;
use Icinga\Module\Icingadb\Hook\CustomVarRendererHook;
use ipl\Html\Attributes;
use ipl\Html\BaseHtmlElement;
use ipl\Html\Html;
use ipl\Html\HtmlDocument;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Html\ValidHtml;
use ipl\Orm\Model;
use ipl\Web\Widget\EmptyState;
use ipl\Web\Widget\Icon;
Expand Down Expand Up @@ -101,11 +103,11 @@ protected function addRow($name, $value)
protected function renderVar($name, $value)
{
if ($this->object !== null && $this->level === 0) {
list($name, $value, $group) = call_user_func($this->hookApplier, $name, $value);
if ($group !== null) {
$this->groups[$group][] = [$name, $value];
return;
}
// list($name, $value, $group) = call_user_func($this->hookApplier, $name, $value);
// if ($group !== null) {
// $this->groups[$group][] = [$name, $value];
// return;
// }
}

$isArray = is_array($value);
Expand All @@ -116,6 +118,8 @@ protected function renderVar($name, $value)
case $isArray:
$this->renderObject($name, $value);
break;
case $value instanceof ValidHtml:
// Todo: Needs new implementation
default:
$this->renderScalar($name, $value);
}
Expand Down Expand Up @@ -213,9 +217,9 @@ protected function renderGroup(string $name, $entries)

protected function assemble()
{
if ($this->object !== null) {
$this->hookApplier = CustomVarRendererHook::prepareForObject($this->object);
}
// if ($this->object !== null) {
// $this->hookApplier = CustomVarRendererHook::prepareForObject($this->object);
// }

if ($this->headerTitle !== null) {
$this->getAttributes()
Expand Down Expand Up @@ -248,20 +252,30 @@ protected function assemble()
ksort($this->data);
}

foreach ($this->data as $name => $value) {
$groups = [];
if ($this->object !== null) {
list($enrichedCustomVars, $groups) = CustomVarEnricherHook::prepareEnrichedCustomVars(
(array) $this->data,
$this->object
);
} else {
$enrichedCustomVars = $this->data;
}

foreach ($enrichedCustomVars as $name => $value) {
$this->renderVar($name, $value);
}

$this->addHtml($this->body);

// Hooks can return objects as replacement for keys, hence a generator is needed for group entries
$genGenerator = function ($entries) {
foreach ($entries as list($key, $value)) {
foreach ($entries as $key => $value) {
yield $key => $value;
}
};

foreach ($this->groups as $group => $entries) {
foreach ($groups as $group => $entries) {
$this->renderGroup($group, $genGenerator($entries));
}
}
Expand Down
1 change: 1 addition & 0 deletions run.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

$this->provideHook('ApplicationState');
$this->provideHook('X509/Sni');
$this->provideHook('Icingadb/CustomVarEnricher');
$this->provideHook('health', 'IcingaHealth');
$this->provideHook('health', 'RedisHealth');
$this->provideHook('Reporting/Report', 'Reporting/HostSlaReport');
Expand Down
Loading

0 comments on commit 2d1b93e

Please sign in to comment.