diff --git a/library/Icingadb/Hook/CustomVarEnricherHook.php b/library/Icingadb/Hook/CustomVarEnricherHook.php new file mode 100644 index 000000000..02fbe636f --- /dev/null +++ b/library/Icingadb/Hook/CustomVarEnricherHook.php @@ -0,0 +1,61 @@ +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]); + } + } + + + return [$vars, $groups]; + } +} diff --git a/library/Icingadb/ProvidedHook/Icingadb/CustomVarItem.php b/library/Icingadb/ProvidedHook/Icingadb/CustomVarItem.php new file mode 100644 index 000000000..20f2efe14 --- /dev/null +++ b/library/Icingadb/ProvidedHook/Icingadb/CustomVarItem.php @@ -0,0 +1,24 @@ +item = $item; + } + + protected function assemble() + { + $this->addHtml($this->item); + } +} \ No newline at end of file diff --git a/library/Icingadb/ProvidedHook/Icingadb/CustomVarRenderer.php b/library/Icingadb/ProvidedHook/Icingadb/CustomVarRenderer.php new file mode 100644 index 000000000..38fe173af --- /dev/null +++ b/library/Icingadb/ProvidedHook/Icingadb/CustomVarRenderer.php @@ -0,0 +1,177 @@ +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])) { + $field = $this->fieldConfig[$name]; + $dataType = $field->get('datatype'); + + if ($dataType === get_class(new DataTypeDictionary())) { + $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[] = [ + $nestedVarName => $this->resolveCustomVarMapping( + $nestedVarName, + $nestedVarValue, + $conn, + false + ) + ]; + } + } + + return [$field->get('caption') => 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; + } +} \ No newline at end of file diff --git a/library/Icingadb/ProvidedHook/Icingadb/CustomVarSection.php b/library/Icingadb/ProvidedHook/Icingadb/CustomVarSection.php new file mode 100644 index 000000000..b4a486bee --- /dev/null +++ b/library/Icingadb/ProvidedHook/Icingadb/CustomVarSection.php @@ -0,0 +1,26 @@ +items[] = $item; + } + + public function assemble() + { + $this->addHtml($this->items); + } +} \ No newline at end of file diff --git a/library/Icingadb/Widget/Detail/CustomVarTable.php b/library/Icingadb/Widget/Detail/CustomVarTable.php index 9d6916b34..815f495ed 100644 --- a/library/Icingadb/Widget/Detail/CustomVarTable.php +++ b/library/Icingadb/Widget/Detail/CustomVarTable.php @@ -4,6 +4,7 @@ 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; @@ -11,6 +12,7 @@ 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; @@ -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); @@ -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); } @@ -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() @@ -248,7 +252,23 @@ protected function assemble() ksort($this->data); } - foreach ($this->data as $name => $value) { + $groups = []; + if ($this->object !== null) { + list($enrichedCustomVars, $groups) = CustomVarEnricherHook::prepareCustomEnrichedVar( + (array) $this->data, + $this->object + ); + } else { + $enrichedCustomVars = $this->data; + } + + foreach ($enrichedCustomVars as $name => $value) { + foreach ($groups as $group) { + if (array_key_exists($name, $group)) { + continue 2; + } + } + $this->renderVar($name, $value); } @@ -256,12 +276,12 @@ protected function assemble() // 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)); } } diff --git a/run.php b/run.php index b4c803222..b00758832 100644 --- a/run.php +++ b/run.php @@ -6,6 +6,7 @@ $this->provideHook('ApplicationState'); $this->provideHook('X509/Sni'); +$this->provideHook('Icingadb/CustomVarRenderer'); $this->provideHook('health', 'IcingaHealth'); $this->provideHook('health', 'RedisHealth'); $this->provideHook('Reporting/Report', 'Reporting/HostSlaReport');