Alternative custom property support with dictionary handling
Introduce a first-class DirectorProperty concept that extends the existing
data-fields model with rich, structured variable types. Custom variables can
now be defined globally under a new "Custom Variables" section and assigned
to Icinga objects (hosts, services, commands, etc.).
Supported types: string, number, boolean, fixed-array, dynamic-array,
datalist-strict, datalist-non-strict, fixed-dictionary, and
dynamic-dictionary (one level of nesting allowed).
Key changes:
- DirectorProperty object with CRUD, inheritance, and apply-for rule support
- New form elements: Dictionary, DictionaryItem, NestedDictionary,
NestedDictionaryItem, ArrayElement, IplBoolean
- CustomvarController for managing global property definitions
- VariablesController for per-object variable assignment
- BasketSnapshotCustomVariableResolver for basket import/export of properties
- REST API: IcingaObjectHandler extended to expose and accept structured vars
- IcingaConfigHelper: renders dictionaries/arrays to valid Icinga 2 DSL
- CustomVarRenderer updated for icingadb hook display
- DB migration upgrade_192.sql: new director_property and related tables
- CLI: MigrateCommand for migrating legacy vars to properties;
HostsCommand for bulk host custom variable management
2026-03-25 07:01:32 -04:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Icinga\Module\Director\Forms;
|
|
|
|
|
|
|
|
|
|
use Icinga\Module\Director\Data\Db\DbConnection;
|
|
|
|
|
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
|
|
|
|
|
use Icinga\Module\Director\Db\DbUtil;
|
|
|
|
|
use Icinga\Module\Director\Objects\IcingaObject;
|
|
|
|
|
use Icinga\Web\Session;
|
|
|
|
|
use ipl\I18n\Translation;
|
|
|
|
|
use ipl\Web\Common\CsrfCounterMeasure;
|
|
|
|
|
use ipl\Web\Compat\CompatForm;
|
|
|
|
|
use Ramsey\Uuid\Uuid;
|
|
|
|
|
|
|
|
|
|
class ObjectCustomvarForm extends CompatForm
|
|
|
|
|
{
|
|
|
|
|
use CsrfCounterMeasure;
|
|
|
|
|
use Translation;
|
|
|
|
|
|
|
|
|
|
protected $customVars = [];
|
|
|
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
|
public readonly DbConnection $db,
|
2026-05-12 05:12:35 -04:00
|
|
|
public readonly IcingaObject $object,
|
|
|
|
|
private readonly array $alreadyAddedUuids = []
|
Alternative custom property support with dictionary handling
Introduce a first-class DirectorProperty concept that extends the existing
data-fields model with rich, structured variable types. Custom variables can
now be defined globally under a new "Custom Variables" section and assigned
to Icinga objects (hosts, services, commands, etc.).
Supported types: string, number, boolean, fixed-array, dynamic-array,
datalist-strict, datalist-non-strict, fixed-dictionary, and
dynamic-dictionary (one level of nesting allowed).
Key changes:
- DirectorProperty object with CRUD, inheritance, and apply-for rule support
- New form elements: Dictionary, DictionaryItem, NestedDictionary,
NestedDictionaryItem, ArrayElement, IplBoolean
- CustomvarController for managing global property definitions
- VariablesController for per-object variable assignment
- BasketSnapshotCustomVariableResolver for basket import/export of properties
- REST API: IcingaObjectHandler extended to expose and accept structured vars
- IcingaConfigHelper: renders dictionaries/arrays to valid Icinga 2 DSL
- CustomVarRenderer updated for icingadb hook display
- DB migration upgrade_192.sql: new director_property and related tables
- CLI: MigrateCommand for migrating legacy vars to properties;
HostsCommand for bulk host custom variable management
2026-03-25 07:01:32 -04:00
|
|
|
) {
|
|
|
|
|
$this->customVars = $this->getCustomVars();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getPropertyName(): string
|
|
|
|
|
{
|
|
|
|
|
$propertyUuid = $this->getValue('property');
|
|
|
|
|
if ($propertyUuid) {
|
|
|
|
|
return $this->customVars[$propertyUuid] ?? '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function assemble(): void
|
|
|
|
|
{
|
|
|
|
|
$this->addElement($this->createCsrfCounterMeasure(Session::getSession()->getId()));
|
|
|
|
|
$propertyElement = $this->createElement(
|
|
|
|
|
'select',
|
|
|
|
|
'property',
|
|
|
|
|
[
|
|
|
|
|
'label' => $this->translate('Variable'),
|
|
|
|
|
'required' => true,
|
|
|
|
|
'class' => ['autosubmit'],
|
|
|
|
|
'disabledOptions' => [''],
|
|
|
|
|
'value' => '',
|
|
|
|
|
'options' => array_merge(
|
|
|
|
|
['' => $this->translate('Please choose a custom variable to add')],
|
|
|
|
|
$this->getCustomVars()
|
|
|
|
|
)
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->addElement($propertyElement);
|
|
|
|
|
|
|
|
|
|
$this->addElement('submit', 'submit', [
|
|
|
|
|
'label' => $this->translate('Add')
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function getCustomVars(): array
|
|
|
|
|
{
|
|
|
|
|
$parents = $this->object->listAncestorIds();
|
|
|
|
|
$type = $this->object->getShortTableName();
|
|
|
|
|
|
|
|
|
|
$uuids = [];
|
|
|
|
|
$db = $this->db->getDbAdapter();
|
|
|
|
|
$class = DbObjectTypeRegistry::classByType($type);
|
|
|
|
|
foreach ($parents as $parent) {
|
|
|
|
|
$uuids[] = $class::load($parent, $this->object->getConnection())->get('uuid');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$uuids[] = $this->object->get('uuid');
|
|
|
|
|
|
|
|
|
|
$query = $db
|
|
|
|
|
->select()
|
|
|
|
|
->from(['dp' => 'director_property'], ['uuid' => 'dp.uuid'])
|
|
|
|
|
->join(['iop' => 'icinga_' . $type . '_property'], 'dp.uuid = iop.property_uuid', [])
|
|
|
|
|
->where(
|
|
|
|
|
'dp.parent_uuid IS NULL AND iop.' . $type . '_uuid IN (?)',
|
|
|
|
|
Dbutil::quoteBinaryCompat($uuids, $db)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$properties = $db->fetchAll(
|
|
|
|
|
$db->select()->from(
|
|
|
|
|
['odp' => 'director_property'],
|
|
|
|
|
['uuid' => 'odp.uuid', 'key_name' => 'odp.key_name']
|
|
|
|
|
)->where('parent_uuid IS NULL AND odp.uuid NOT IN (?)', $query)
|
|
|
|
|
->order('key_name')
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$propUuidKeyPairs = [];
|
|
|
|
|
foreach ($properties as $property) {
|
2026-05-12 05:12:35 -04:00
|
|
|
$uuid = DbUtil::binaryResult($property->uuid);
|
|
|
|
|
$uuidStr = Uuid::fromBytes($uuid)->toString();
|
|
|
|
|
if (! in_array($uuidStr, $this->alreadyAddedUuids, true)) {
|
|
|
|
|
$propUuidKeyPairs[$uuidStr] = $property->key_name;
|
Alternative custom property support with dictionary handling
Introduce a first-class DirectorProperty concept that extends the existing
data-fields model with rich, structured variable types. Custom variables can
now be defined globally under a new "Custom Variables" section and assigned
to Icinga objects (hosts, services, commands, etc.).
Supported types: string, number, boolean, fixed-array, dynamic-array,
datalist-strict, datalist-non-strict, fixed-dictionary, and
dynamic-dictionary (one level of nesting allowed).
Key changes:
- DirectorProperty object with CRUD, inheritance, and apply-for rule support
- New form elements: Dictionary, DictionaryItem, NestedDictionary,
NestedDictionaryItem, ArrayElement, IplBoolean
- CustomvarController for managing global property definitions
- VariablesController for per-object variable assignment
- BasketSnapshotCustomVariableResolver for basket import/export of properties
- REST API: IcingaObjectHandler extended to expose and accept structured vars
- IcingaConfigHelper: renders dictionaries/arrays to valid Icinga 2 DSL
- CustomVarRenderer updated for icingadb hook display
- DB migration upgrade_192.sql: new director_property and related tables
- CLI: MigrateCommand for migrating legacy vars to properties;
HostsCommand for bulk host custom variable management
2026-03-25 07:01:32 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $propUuidKeyPairs;
|
|
|
|
|
}
|
|
|
|
|
}
|