summaryrefslogtreecommitdiffstats
path: root/library/Director/Import/Sync.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/Director/Import/Sync.php')
-rw-r--r--library/Director/Import/Sync.php120
1 files changed, 78 insertions, 42 deletions
diff --git a/library/Director/Import/Sync.php b/library/Director/Import/Sync.php
index 8fea46c..2957433 100644
--- a/library/Director/Import/Sync.php
+++ b/library/Director/Import/Sync.php
@@ -16,6 +16,7 @@ use Icinga\Module\Director\Objects\HostGroupMembershipResolver;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaHostGroup;
use Icinga\Module\Director\Objects\IcingaObject;
+use Icinga\Module\Director\Objects\IcingaObjectGroup;
use Icinga\Module\Director\Objects\ImportSource;
use Icinga\Module\Director\Objects\IcingaService;
use Icinga\Module\Director\Objects\SyncProperty;
@@ -49,6 +50,9 @@ class Sync
/** @var array<mixed, array<int, string>> key => [property, property]*/
protected $setNull = [];
+ /** @var array<mixed, array<string, mixed>> key => [propertyName, newValue]*/
+ protected $newProperties = [];
+
/** @var bool Whether we already prepared your sync */
protected $isPrepared = false;
@@ -88,6 +92,12 @@ class Sync
/** @var ?DbObjectStore */
protected $store;
+ /** @var IcingaObjectGroup[] */
+ protected $modifiedGroups = [];
+
+ /** @var IcingaObject[] */
+ protected $modifiedGroupObjects = [];
+
/**
* @param SyncRule $rule
* @param ?DbObjectStore $store
@@ -137,24 +147,6 @@ class Sync
}
/**
- * Transform the given value to an array
- *
- * @param array|string|null $value
- *
- * @return array
- */
- protected function wantArray($value)
- {
- if (is_array($value)) {
- return $value;
- } elseif ($value === null) {
- return [];
- } else {
- return [$value];
- }
- }
-
- /**
* Raise PHP resource limits
*
* @return self;
@@ -162,7 +154,7 @@ class Sync
protected function raiseLimits()
{
MemoryLimit::raiseTo('1024M');
- ini_set('max_execution_time', 0);
+ ini_set('max_execution_time', '0');
return $this;
}
@@ -452,7 +444,28 @@ class Sync
if ($this->store) {
$objects = $this->store->loadAll(DbObjectTypeRegistry::tableNameByType($ruleObjectType), 'object_name');
} else {
- $objects = IcingaObject::loadAllByType($ruleObjectType, $this->db);
+ $keyColumn = null;
+ $query = null;
+ // We enforce named index for combined-key templates (Services and Sets) and applied Sets
+ if ($ruleObjectType === 'service' || $ruleObjectType === 'serviceSet') {
+ foreach ($this->syncProperties as $prop) {
+ $configuredObjectType = $prop->get('source_expression');
+ if ($prop->get('destination_field') === 'object_type'
+ && (
+ $configuredObjectType === 'template'
+ || ($configuredObjectType === 'apply' && $ruleObjectType === 'serviceSet')
+ )
+ ) {
+ $keyColumn = 'object_name';
+ $table = $ruleObjectType === 'service'
+ ? BranchSupport::TABLE_ICINGA_SERVICE
+ : BranchSupport::TABLE_ICINGA_SERVICE_SET;
+ $query = $this->db->getDbAdapter()->select()
+ ->from($table)->where('object_type = ?', $configuredObjectType);
+ }
+ }
+ }
+ $objects = IcingaObject::loadAllByType($ruleObjectType, $this->db, $query, $keyColumn);
}
if ($useLowerCaseKeys) {
@@ -532,6 +545,15 @@ class Sync
*/
protected function prepareNewObject($row, DbObject $object, $objectKey, $sourceId)
{
+ if (!isset($this->newProperties[$objectKey])) {
+ $this->newProperties[$objectKey] = [];
+ }
+ // TODO: some more improvements are possible here. First, no need to instantiate
+ // all new objects, we could stick with the newProperties array. Next, we
+ // should be more correct when respecting sync property order. Right now,
+ // a property from another Import Source might win, even if property order
+ // tells something different. This is a very rare case, but still incorrect.
+ $properties = &$this->newProperties[$objectKey];
foreach ($this->syncProperties as $propertyKey => $p) {
if ($p->get('source_id') !== $sourceId) {
continue;
@@ -557,38 +579,35 @@ class Sync
$varName = substr($prop, 5);
if (substr($varName, -2) === '[]') {
$varName = substr($varName, 0, -2);
- $current = $this->wantArray($object->vars()->$varName);
$object->vars()->$varName = array_merge(
- $current,
- $this->wantArray($val)
+ (array) ($object->vars()->$varName),
+ (array) $val
);
} else {
- if ($val === null) {
- $this->setNull[$objectKey][$prop] = $prop;
- } else {
- unset($this->setNull[$objectKey][$prop]);
- $object->vars()->$varName = $val;
- }
+ $this->setPropertyWithNullLogic($object, $objectKey, $prop, $val, $properties);
}
} else {
- if ($val === null) {
- $this->setNull[$objectKey][$prop] = $prop;
- } else {
- unset($this->setNull[$objectKey][$prop]);
- $object->set($prop, $val);
- }
+ $this->setPropertyWithNullLogic($object, $objectKey, $prop, $val, $properties);
}
} else {
- if ($val === null) {
- $this->setNull[$objectKey][$prop] = $prop;
- } else {
- unset($this->setNull[$objectKey][$prop]);
- $object->set($prop, $val);
- }
+ $this->setPropertyWithNullLogic($object, $objectKey, $prop, $val, $properties);
}
}
}
+ protected function setPropertyWithNullLogic(DbObject $object, $objectKey, $property, $value, &$allProps)
+ {
+ if ($value === null) {
+ if (! array_key_exists($property, $allProps) || $allProps[$property] === null) {
+ $this->setNull[$objectKey][$property] = $property;
+ }
+ } else {
+ unset($this->setNull[$objectKey][$property]);
+ $object->set($property, $value);
+ }
+ $allProps[$property] = $value;
+ }
+
/**
* @return $this
*/
@@ -625,6 +644,9 @@ class Sync
protected function notifyResolvers()
{
if ($resolver = $this->getHostGroupMembershipResolver()) {
+ if ($this->rule->get('object_type') === 'hostgroup') {
+ $resolver->setGroups($this->modifiedGroups);
+ }
$resolver->refreshDb(true);
}
@@ -748,6 +770,13 @@ class Sync
}
}
+ protected function optionallyTellResolverAboutModifiedGroup(IcingaObjectGroup $group)
+ {
+ if (in_array('assign_filter', $group->getModifiedProperties())) {
+ $this->modifiedGroups[] = $group;
+ }
+ }
+
/**
* @param $key
* @param DbObject|IcingaObject $object
@@ -791,7 +820,11 @@ class Sync
}
}
- if (isset($this->setNull[$key])) {
+ // Hint: in theory, NULL should be set on new objects, but this has no effect
+ // anyway, and we also do not store vars.something = null, this would
+ // instead delete the variable. So here we do not need to check for new
+ // objects, and skip all null values with update policy = 'ignore'
+ if ($policy !== 'ignore' && isset($this->setNull[$key])) {
foreach ($this->setNull[$key] as $property) {
$this->objects[$key]->set($property, null);
}
@@ -850,6 +883,9 @@ class Sync
}
if ($object->hasBeenModified()) {
+ if ($object instanceof IcingaObjectGroup) {
+ $this->optionallyTellResolverAboutModifiedGroup($object);
+ }
$existing = $object->hasBeenLoadedFromDb();
if ($existing) {
if ($this->store) {