Skip to content

Commit

Permalink
Sync: preserve _override_servicevars
Browse files Browse the repository at this point in the history
fixes Icinga#1307

Signed-off-by: Barnim Grüneberg  <13362393+bargru@users.noreply.github.com>
  • Loading branch information
Thomas-Gelf committed May 4, 2018
1 parent d3aabe0 commit 5d8ea97
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 38 deletions.
1 change: 1 addition & 0 deletions doc/82-Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ before switching to a new version.
* FEATURE: new Property Modifier to url-encode values
* FEATURE: new Property Modifier: uppercase the first character of each word
* FEATURE: Kickstart Helper now also imports Event Commands (#1389)
* FEATURE: Preserve _override_servicevars on sync, even when replacing vars (#1307)

### Internals
* FEATURE: Html/Attribute now allows boolean properties
Expand Down
26 changes: 26 additions & 0 deletions library/Director/CustomVariable/CustomVariables.php
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,32 @@ public function setUnmodified()
return $this;
}

public function restoreStoredVar($key)
{
if (array_key_exists($key, $this->storedVars)) {
$this->vars[$key] = clone($this->storedVars[$key]);
$this->vars[$key]->setUnmodified();
$this->recheckForModifications();
$this->refreshIndex();
} elseif (array_key_exists($key, $this->vars)) {
unset($this->vars[$key]);
$this->recheckForModifications();
$this->refreshIndex();
}
}

protected function recheckForModifications()
{
$this->modified = false;
foreach ($this->vars as $var) {
if ($var->hasBeenModified()) {
$this->modified = true;

return;
}
}
}

public function getOriginalVars()
{
return $this->storedVars;
Expand Down
135 changes: 97 additions & 38 deletions library/Director/Import/Sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ class Sync

protected $replaceVars = false;

protected $hasPropertyDisabled = false;

protected $serviceOverrideKeyName;

/**
* @var SyncRun
*/
Expand Down Expand Up @@ -118,6 +122,7 @@ public function hasModifications()
* Retrieve modifications a given SyncRule would apply
*
* @return array Array of IcingaObject elements
* @throws Exception
*/
public function getExpectedModifications()
{
Expand Down Expand Up @@ -191,6 +196,10 @@ protected function fetchSyncProperties()
$this->replaceVars = true;
}

if ($prop->destination_field === 'disabled') {
$this->hasPropertyDisabled = true;
}

if (! strlen($prop->filter_expression)) {
continue;
}
Expand Down Expand Up @@ -263,6 +272,9 @@ protected function prepareSourceColumns()
protected function fetchImportedData()
{
Benchmark::measure('Begin loading imported data');
if ($this->rule->object_type === 'host') {
$this->serviceOverrideKeyName = $this->db->settings()->override_services_varname;
}

$this->imported = array();

Expand Down Expand Up @@ -575,9 +587,10 @@ protected function getHostGroupMembershipResolver()
/**
* Evaluates a SyncRule and returns a list of modified objects
*
* TODO: This needs to be splitted into smaller methods
* TODO: Split this into smaller methods
*
* @return DbObject[] List of modified IcingaObjects
* @return DbObject|IcingaObject[] List of modified IcingaObjects
* @throws Exception
*/
protected function prepare()
{
Expand All @@ -586,54 +599,25 @@ protected function prepare()
}

$this->raiseLimits()
->prepareCache()
->startMeasurements()
->prepareCache()
->fetchSyncProperties()
->prepareRelatedImportSources()
->prepareSourceColumns()
->loadExistingObjects()
->fetchImportedData()
->deferResolvers();

// TODO: directly work on existing objects, remember imported keys, then purge
$newObjects = $this->prepareNewObjects();

$hasDisabled = false;
foreach ($this->syncProperties as $property) {
if ($property->get('destination_field') === 'disabled') {
$hasDisabled = true;
}
}

Benchmark::measure('Begin preparing updated objects');
$newObjects = $this->prepareNewObjects();

Benchmark::measure('Ready to process objects');
/** @var DbObject|IcingaObject $object */
foreach ($newObjects as $key => $object) {
if (array_key_exists($key, $this->objects)) {
switch ($this->rule->get('update_policy')) {
case 'override':
$this->objects[$key]->replaceWith($object);
break;

case 'merge':
// TODO: re-evaluate merge settings. vars.x instead of
// just "vars" might suffice.
$this->objects[$key]->merge($object, $this->replaceVars);
if (! $hasDisabled && $object->hasProperty('disabled')) {
$this->objects[$key]->resetProperty('disabled');
}
break;

default:
// policy 'ignore', no action
}
} else {
$this->objects[$key] = $object;
}
$this->processObject($key, $object);
}

Benchmark::measure('Done preparing updated objects');

Benchmark::measure('Modified objects are ready, applying purge strategy');
$noAction = array();
foreach ($this->rule->purgeStrategy()->listObjectsToPurge() as $key) {
if (array_key_exists($key, $newObjects)) {
Expand Down Expand Up @@ -668,6 +652,68 @@ protected function prepare()
return $this->objects;
}

/**
* @param $key
* @param DbObject|IcingaObject $object
* @throws IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function processObject($key, $object)
{
if (array_key_exists($key, $this->objects)) {
$this->refreshObject($key, $object);
} else {
$this->addNewObject($key, $object);
}
}

/**
* @param $key
* @param DbObject|IcingaObject $object
* @throws IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function refreshObject($key, $object)
{
$policy = $this->rule->get('update_policy');

switch ($policy) {
case 'override':
$this->objects[$key]->replaceWith($object);
break;

case 'merge':
// TODO: re-evaluate merge settings. vars.x instead of
// just "vars" might suffice.
$this->objects[$key]->merge($object, $this->replaceVars);
if (! $this->hasPropertyDisabled && $object->hasProperty('disabled')) {
$this->objects[$key]->resetProperty('disabled');
}
break;

default:
// policy 'ignore', no action
}

if ($policy === 'override' || $policy === 'merge') {
if ($object instanceof IcingaHost) {
$keyName = $this->serviceOverrideKeyName;
if (! $object->hasInitializedVars() || ! isset($object->vars()->$key)) {
$this->objects[$key]->vars()->restoreStoredVar($keyName);
}
}
}
}

/**
* @param $key
* @param DbObject|IcingaObject $object
*/
protected function addNewObject($key, $object)
{
$this->objects[$key] = $object;
}

/**
* Runs a SyncRule and applies all resulting changes
* @return int
Expand All @@ -692,6 +738,7 @@ public function apply()
$created = 0;
$modified = 0;
$deleted = 0;
$failed = 0;
foreach ($objects as $object) {
$this->setResolver($object);
if ($object->shouldBeRemoved()) {
Expand All @@ -701,12 +748,24 @@ public function apply()
}

if ($object->hasBeenModified()) {
if ($object->hasBeenLoadedFromDb()) {
$existing = $object->hasBeenLoadedFromDb();

try {
$object->store($db);
} catch (Exception $e) {
if ($this->singleObjectsAreAllowedToFail()) {
$failed++;
continue;
} else {
throw $e;
}
}

if ($existing) {
$modified++;
} else {
$created++;
}
$object->store($db);
}
}

Expand Down
11 changes: 11 additions & 0 deletions library/Director/Objects/IcingaObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,17 @@ public function vars()
return $this->vars;
}

/**
* @return bool
* @throws ProgrammingError
*/
public function hasInitializedVars()
{
$this->assertCustomVarsSupport();

return $this->vars !== null;
}

public function getVarsTableName()
{
return $this->getTableName() . '_var';
Expand Down

0 comments on commit 5d8ea97

Please sign in to comment.