mirror of
https://github.com/Icinga/icingaweb2-module-director.git
synced 2025-07-28 16:24:05 +02:00
PropertyModifierCombine: implementation, tests...
...and related changes with some documentation fixes #922
This commit is contained in:
parent
220d15c523
commit
f91dd5fa0e
@ -69,7 +69,10 @@ class ImportSourceForm extends DirectorObjectForm
|
|||||||
. ' specified this will then be used as the object_name for the syncronized'
|
. ' specified this will then be used as the object_name for the syncronized'
|
||||||
. ' Icinga object. Especially when getting started with director please make'
|
. ' Icinga object. Especially when getting started with director please make'
|
||||||
. ' sure to strictly follow this rule. Duplicate values for this column on different'
|
. ' sure to strictly follow this rule. Duplicate values for this column on different'
|
||||||
. ' rows will trigger a failure, your import run will not succeed'
|
. ' rows will trigger a failure, your import run will not succeed. Please pay attention'
|
||||||
|
. ' when synching services, as "purge" will only work correctly with a key_column'
|
||||||
|
. ' corresponding to host!name. Check the "Combine" property modifier in case your'
|
||||||
|
. ' data source cannot provide such a field'
|
||||||
),
|
),
|
||||||
'placeholder' => $defaultKeyCol,
|
'placeholder' => $defaultKeyCol,
|
||||||
'required' => $defaultKeyCol === null,
|
'required' => $defaultKeyCol === null,
|
||||||
|
@ -13,6 +13,20 @@ abstract class PropertyModifierHook
|
|||||||
|
|
||||||
private $db;
|
private $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \stdClass
|
||||||
|
*/
|
||||||
|
private $row;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode to transform the given value
|
||||||
|
*
|
||||||
|
* Your custom property modifier needs to implement this method.
|
||||||
|
*
|
||||||
|
* @return value
|
||||||
|
*/
|
||||||
|
abstract public function transform($value);
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
$parts = explode('\\', get_class($this));
|
$parts = explode('\\', get_class($this));
|
||||||
@ -28,22 +42,93 @@ abstract class PropertyModifierHook
|
|||||||
return $class;
|
return $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this PropertyModifier wants to deal with array on it's own
|
||||||
|
*
|
||||||
|
* When true, the whole array value will be passed to transform(), otherwise
|
||||||
|
* transform() will be called for every single array member
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function hasArraySupport()
|
public function hasArraySupport()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this PropertyModifier wants access to the current row
|
||||||
|
*
|
||||||
|
* When true, the your modifier can access the current row via $this->getRow()
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function requiresRow()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current row
|
||||||
|
*
|
||||||
|
* Will be null when requiresRow was not null. Please do not modify the
|
||||||
|
* row. It might work right now, as we pass in an object reference for
|
||||||
|
* performance reasons. However, modifying row properties is not supported,
|
||||||
|
* and the outcome of such operation might change without pre-announcement
|
||||||
|
* in any future version.
|
||||||
|
*
|
||||||
|
* @return \stdClass|null
|
||||||
|
*/
|
||||||
|
public function getRow()
|
||||||
|
{
|
||||||
|
return $this->row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current row
|
||||||
|
*
|
||||||
|
* Please see requiresRow/getRow for related details. This method is called
|
||||||
|
* by the Import implementation, you should never need to call this on your
|
||||||
|
* own - apart from writing tests of course.
|
||||||
|
*
|
||||||
|
* @param \stdClass $row
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setRow($row)
|
||||||
|
{
|
||||||
|
$this->row = $row;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The desired target property. Modifiers might want to have their outcome
|
||||||
|
* written to another property of the current row.
|
||||||
|
*
|
||||||
|
* @param $property
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
public function setTargetProperty($property)
|
public function setTargetProperty($property)
|
||||||
{
|
{
|
||||||
$this->targetProperty = $property;
|
$this->targetProperty = $property;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the result of transform() should be written to a new property
|
||||||
|
*
|
||||||
|
* The Import implementation deals with this
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function hasTargetProperty()
|
public function hasTargetProperty()
|
||||||
{
|
{
|
||||||
return $this->targetProperty !== null;
|
return $this->targetProperty !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configured target property
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function getTargetProperty($default = null)
|
public function getTargetProperty($default = null)
|
||||||
{
|
{
|
||||||
if ($this->targetProperty === null) {
|
if ($this->targetProperty === null) {
|
||||||
@ -85,13 +170,6 @@ abstract class PropertyModifierHook
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Methode to transform the given value
|
|
||||||
*
|
|
||||||
* @return value
|
|
||||||
*/
|
|
||||||
abstract public function transform($value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override this method if you want to extend the settings form
|
* Override this method if you want to extend the settings form
|
||||||
*
|
*
|
||||||
|
@ -23,6 +23,18 @@ class SyncUtils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the given string contains variable names in the form ${var_name}
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function hasVariables($string)
|
||||||
|
{
|
||||||
|
return preg_match('/\${([^}]+)}/', $string);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively extract a value from a nested structure
|
* Recursively extract a value from a nested structure
|
||||||
*
|
*
|
||||||
@ -34,11 +46,11 @@ class SyncUtils
|
|||||||
* return { size => '255GB' }
|
* return { size => '255GB' }
|
||||||
*
|
*
|
||||||
* @param string $val The value to extract data from
|
* @param string $val The value to extract data from
|
||||||
* @param object $keys A list of nested keys pointing to desired data
|
* @param array $keys A list of nested keys pointing to desired data
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public static function getDeepValue($val, $keys)
|
public static function getDeepValue($val, array $keys)
|
||||||
{
|
{
|
||||||
$key = array_shift($keys);
|
$key = array_shift($keys);
|
||||||
if (! property_exists($val, $key)) {
|
if (! property_exists($val, $key)) {
|
||||||
|
@ -6,6 +6,7 @@ use Icinga\Application\Benchmark;
|
|||||||
use Icinga\Exception\ConfigurationError;
|
use Icinga\Exception\ConfigurationError;
|
||||||
use Icinga\Exception\NotFoundError;
|
use Icinga\Exception\NotFoundError;
|
||||||
use Icinga\Module\Director\Data\Db\DbObjectWithSettings;
|
use Icinga\Module\Director\Data\Db\DbObjectWithSettings;
|
||||||
|
use Icinga\Module\Director\Hook\PropertyModifierHook;
|
||||||
use Icinga\Module\Director\Import\Import;
|
use Icinga\Module\Director\Import\Import;
|
||||||
use Icinga\Module\Director\Import\SyncUtils;
|
use Icinga\Module\Director\Import\SyncUtils;
|
||||||
use Exception;
|
use Exception;
|
||||||
@ -97,7 +98,11 @@ class ImportSource extends DbObjectWithSettings
|
|||||||
$modifiers = $this->getRowModifiers();
|
$modifiers = $this->getRowModifiers();
|
||||||
|
|
||||||
foreach ($modifiers as $key => $mods) {
|
foreach ($modifiers as $key => $mods) {
|
||||||
|
/** @var PropertyModifierHook $mod */
|
||||||
foreach ($mods as $mod) {
|
foreach ($mods as $mod) {
|
||||||
|
if ($mod->requiresRow()) {
|
||||||
|
$mod->setRow($row);
|
||||||
|
}
|
||||||
if (! property_exists($row, $key)) {
|
if (! property_exists($row, $key)) {
|
||||||
// Partial support for nested keys. Must write result to
|
// Partial support for nested keys. Must write result to
|
||||||
// a dedicated flat key
|
// a dedicated flat key
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Module\Director\PropertyModifier;
|
||||||
|
|
||||||
|
use Icinga\Module\Director\Hook\PropertyModifierHook;
|
||||||
|
use Icinga\Module\Director\Import\SyncUtils;
|
||||||
|
use Icinga\Module\Director\Web\Form\QuickForm;
|
||||||
|
|
||||||
|
class PropertyModifierCombine extends PropertyModifierHook
|
||||||
|
{
|
||||||
|
public static function addSettingsFormFields(QuickForm $form)
|
||||||
|
{
|
||||||
|
$form->addElement('text', 'pattern', array(
|
||||||
|
'label' => $form->translate('Pattern'),
|
||||||
|
'required' => false,
|
||||||
|
'description' => $form->translate(
|
||||||
|
'This pattern will be evaluated, and variables like ${some_column}'
|
||||||
|
. ' will be filled accordingly. A typical use-case is generating'
|
||||||
|
. ' unique service idendifiers via ${host}!${service} in case your'
|
||||||
|
. ' data source doesn\'t allow you to ship such. The chosen "property"'
|
||||||
|
. ' has no effect here and will be ignored.'
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Combine multiple properties';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requiresRow()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function transform($value)
|
||||||
|
{
|
||||||
|
return SyncUtils::fillVariables($this->getSetting('pattern'), $this->getRow());
|
||||||
|
}
|
||||||
|
}
|
1
run.php
1
run.php
@ -40,6 +40,7 @@ $this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\Pro
|
|||||||
$this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierToInt');
|
$this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierToInt');
|
||||||
$this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierLConfCustomVar');
|
$this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierLConfCustomVar');
|
||||||
$this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierArrayFilter');
|
$this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierArrayFilter');
|
||||||
|
$this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierCombine');
|
||||||
|
|
||||||
$this->provideHook('director/Job', $prefix . 'Job\\HousekeepingJob');
|
$this->provideHook('director/Job', $prefix . 'Job\\HousekeepingJob');
|
||||||
$this->provideHook('director/Job', $prefix . 'Job\\ConfigJob');
|
$this->provideHook('director/Job', $prefix . 'Job\\ConfigJob');
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Icinga\Module\Director\Objects;
|
||||||
|
|
||||||
|
use Icinga\Module\Director\PropertyModifier\PropertyModifierCombine;
|
||||||
|
use Icinga\Module\Director\Test\BaseTestCase;
|
||||||
|
|
||||||
|
class PropertyModifierCombineTest extends BaseTestCase
|
||||||
|
{
|
||||||
|
public function testBuildsTypicalHostServiceCombination()
|
||||||
|
{
|
||||||
|
$row = (object) array('host' => 'localhost', 'service' => 'ping');
|
||||||
|
$modifier = new PropertyModifierCombine();
|
||||||
|
$modifier->setSettings(array('pattern' => '${host}!${service}'));
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'localhost!ping',
|
||||||
|
$modifier->setRow($row)->transform('something')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoesNotFailForMissingProperties()
|
||||||
|
{
|
||||||
|
$row = (object) array('host' => 'localhost');
|
||||||
|
$modifier = new PropertyModifierCombine();
|
||||||
|
$modifier->setSettings(array('pattern' => '${host}!${service}'));
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'localhost!',
|
||||||
|
$modifier->setRow($row)->transform('something')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoesNotEvaluateVariablesFromDataSource()
|
||||||
|
{
|
||||||
|
$row = (object) array('host' => '${service}', 'service' => 'ping');
|
||||||
|
$modifier = new PropertyModifierCombine();
|
||||||
|
$modifier->setSettings(array('pattern' => '${host}!${service}'));
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'${service}!ping',
|
||||||
|
$modifier->setRow($row)->transform('something')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRequiresRow()
|
||||||
|
{
|
||||||
|
$modifier = new PropertyModifierCombine();
|
||||||
|
$this->assertTrue($modifier->requiresRow());
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user