diff --git a/application/forms/IcingaServiceForm.php b/application/forms/IcingaServiceForm.php index 3e21bc8c..d5045147 100644 --- a/application/forms/IcingaServiceForm.php +++ b/application/forms/IcingaServiceForm.php @@ -612,6 +612,35 @@ class IcingaServiceForm extends DirectorObjectForm return $this; } + protected function applyForVars(): ?array + { + $query = $this->db->getDbAdapter() + ->select() + ->from( + ['dp' => 'director_property'], + [ + 'key_name' => 'dp.key_name', + 'uuid' => 'dp.uuid', + 'value_type' => 'dp.value_type', + 'label' => 'dp.label', + 'instantiable' => 'dp.instantiable', + 'required' => 'iop.required' + ] + ) + ->join(['iop' => 'icinga_host_property'], 'dp.uuid = iop.property_uuid', []) + ->where("value_type = 'array' AND instantiable = 'y'") + ->orWhere("value_type = 'dict'"); + + $vars = $this->db->getDbAdapter()->fetchAll($query); + + $properties = []; + foreach ($vars as $var) { + $properties['host.vars.' . $var->key_name] = $var->label . ' (' . $var->key_name . ')'; + } + + return [t('director', 'Custom variables') => $properties]; + } + /** * @return $this * @throws \Zend_Form_Exception @@ -619,11 +648,7 @@ class IcingaServiceForm extends DirectorObjectForm protected function addApplyForElement() { if ($this->object->isApplyRule()) { - $hostProperties = IcingaHost::enumProperties( - $this->object->getConnection(), - 'host.', - new ArrayCustomVariablesFilter() - ); + $hostProperties = $this->applyForVars(); $this->addElement('select', 'apply_for', array( 'label' => $this->translate('Apply For'), diff --git a/library/Director/CustomVariable/CustomVariableString.php b/library/Director/CustomVariable/CustomVariableString.php index 2d509681..f2d9e0f3 100644 --- a/library/Director/CustomVariable/CustomVariableString.php +++ b/library/Director/CustomVariable/CustomVariableString.php @@ -46,7 +46,17 @@ class CustomVariableString extends CustomVariable public function toConfigString($renderExpressions = false) { if ($renderExpressions) { - return c::renderStringWithVariables($this->getValue(), ['config']); + $whiteList = ['config']; + $value = $this->getValue(); + if ( + str_starts_with($value, '$') + && str_ends_with($value, '$') + && str_contains($value, 'vars.') + ) { + $whiteList[] = trim($value, '$'); + } + + return c::renderStringWithVariables($this->getValue(), $whiteList); } else { return c::renderString($this->getValue()); } diff --git a/library/Director/Objects/IcingaService.php b/library/Director/Objects/IcingaService.php index 9b51619b..6a7541ea 100644 --- a/library/Director/Objects/IcingaService.php +++ b/library/Director/Objects/IcingaService.php @@ -343,6 +343,24 @@ class IcingaService extends IcingaObject implements ExportInterface } } + /** + * @return string + */ + protected function renderCustomVars() + { + $vars = ''; + if ( + $this->isApplyRule() + && !$this->hasBeenAssignedToHostTemplate() + && $this->get('apply_for') !== null + && $this->isApplyRuleforDictionary(substr($this->get('apply_for'), strlen('host.vars.'))) + ) { + $vars .= "\n vars += config\n"; + } + + return $vars . parent::renderCustomVars(); + } + /** * @return string */ @@ -363,13 +381,25 @@ class IcingaService extends IcingaObject implements ExportInterface $name = ' ' . c::renderString($name); } - return sprintf( - "%s %s%s for (config in %s) {\n", - $this->getObjectTypeName(), - $this->getType(), - $name, - $this->get('apply_for') - ) . $extraName; + if ($this->isApplyRuleforDictionary(substr($this->get('apply_for'), strlen('host.vars.')))) { + $applyForConfig = sprintf( + "%s %s%s for (key => config in %s) {\n", + $this->getObjectTypeName(), + $this->getType(), + $name, + $this->get('apply_for') + ); + } else { + $applyForConfig = sprintf( + "%s %s%s for (config in %s) {\n", + $this->getObjectTypeName(), + $this->getType(), + $name, + $this->get('apply_for') + ) . $extraName; + } + + return $applyForConfig; } return parent::renderObjectHeader(); @@ -387,6 +417,30 @@ class IcingaService extends IcingaObject implements ExportInterface } } + protected function isApplyRuleforDictionary(string $applyFor): bool + { + $query = $this->db + ->select() + ->from( + ['dp' => 'director_property'], + [ + 'key_name' => 'dp.key_name', + 'uuid' => 'dp.uuid', + 'value_type' => 'dp.value_type', + 'label' => 'dp.label', + 'instantiable' => 'dp.instantiable', + 'required' => 'iop.required' + ] + ) + ->join(['iop' => 'icinga_host_property'], 'dp.uuid = iop.property_uuid', []) + ->where("value_type = 'dict'") + ->where("key_name = ?", $applyFor); + + $result = $this->db->fetchOne($query) ?? false; + + return $result !== false; + } + protected function rendersConditionalTemplate(): bool { return $this->getRenderingZone() === self::ALL_NON_GLOBAL_ZONES;