mirror of
https://github.com/Icinga/icingaweb2-module-director.git
synced 2025-07-30 01:04:12 +02:00
Add support for Apply for rules in services
Apply for rules are defined through `apply_for` property Only Array custom variables will be eligible in apply_for dropdown. API Example: ```bash ./director-curl POST director/service?name=my_service '{"apply_for": "for (checked_tcp_port in host.vars.checked_tcp_ports)" }' ``` Will render as: ``` apply Service "my_service" for (checked_tcp_port in host.vars.checked_tcp_ports) { ... } ``` Feature: https://dev.icinga.org/issues/11976 Depends-On: https://github.com/Icinga/icingaweb2-module-director/pull/20 refs #11976
This commit is contained in:
parent
0c5a568191
commit
e7bd4343b5
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Icinga\Module\Director\Forms;
|
||||
|
||||
use Icinga\Module\Director\Data\PropertiesFilter\ArrayCustomVariablesFilter;
|
||||
use Icinga\Module\Director\Exception\NestingError;
|
||||
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
@ -81,6 +82,7 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
->addImportsElement()
|
||||
->addGroupsElement()
|
||||
->addDisabledElement()
|
||||
->addApplyForElement()
|
||||
->groupMainProperties()
|
||||
->addAssignmentElements()
|
||||
->addCheckCommandElements()
|
||||
@ -235,6 +237,67 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function groupMainProperties()
|
||||
{
|
||||
$elements = array(
|
||||
'imports',
|
||||
'object_name',
|
||||
'display_name',
|
||||
'host_id',
|
||||
'address',
|
||||
'address6',
|
||||
'groups',
|
||||
'users',
|
||||
'user_groups',
|
||||
'apply_to',
|
||||
'command_id', // Notification
|
||||
'notification_interval',
|
||||
'period_id',
|
||||
'times_begin',
|
||||
'times_end',
|
||||
'email',
|
||||
'pager',
|
||||
'enable_notifications',
|
||||
'create_live',
|
||||
'disabled',
|
||||
'apply_for'
|
||||
);
|
||||
|
||||
$this->addDisplayGroup($elements, 'object_definition', array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'dl')),
|
||||
'Fieldset',
|
||||
),
|
||||
'order' => 20,
|
||||
'legend' => $this->translate('Main properties')
|
||||
));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function addApplyForElement()
|
||||
{
|
||||
if ($this->object->isApplyRule()) {
|
||||
$hostProperties = IcingaHost::enumProperties($this->object->getConnection(), 'host.',
|
||||
new ArrayCustomVariablesFilter());
|
||||
$this->addElement('select', 'apply_for', array(
|
||||
'label' => $this->translate('Apply For'),
|
||||
'class' => 'assign-property autosubmit',
|
||||
'multiOptions' => $this->optionalEnum($hostProperties, 'None'),
|
||||
'description' => $this->translate(
|
||||
'Evaluates the apply for rule for ' .
|
||||
'all objects with the custom attribute specified. ' .
|
||||
'E.g selecting "host.vars.custom_attr" will generate "for (value in ' .
|
||||
'host.vars.array_var)" where "value" will be accessible through "$$value$$". ' .
|
||||
'NOTE: only custom variables of type "Array" are eligible.'
|
||||
)
|
||||
));
|
||||
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function addGroupsElement()
|
||||
{
|
||||
$groups = $this->enumServicegroups();
|
||||
|
23
library/Director/Data/PropertiesFilter.php
Normal file
23
library/Director/Data/PropertiesFilter.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Data;
|
||||
|
||||
class PropertiesFilter
|
||||
{
|
||||
public static $CUSTOM_PROPERTY = 'CUSTOM_PROPERTY';
|
||||
public static $HOST_PROPERTY = 'HOST_PROPERTY';
|
||||
|
||||
protected $blacklist = array(
|
||||
'id',
|
||||
'object_name',
|
||||
'object_type',
|
||||
'disabled',
|
||||
'has_agent',
|
||||
'master_should_connect',
|
||||
'accept_config',
|
||||
);
|
||||
|
||||
public function match($type, $name, $object=null) {
|
||||
return ($type != self::$HOST_PROPERTY || !in_array($name, $this->blacklist));
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Data\PropertiesFilter;
|
||||
|
||||
class ArrayCustomVariablesFilter extends CustomVariablesFilter {
|
||||
public function match($type, $name, $object=null) {
|
||||
return parent::match($type, $name, $object)
|
||||
&& $object !== null
|
||||
&& preg_match('/DataTypeArray[\w]*$/', $object->datatype);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Data\PropertiesFilter;
|
||||
|
||||
use Icinga\Module\Director\Data\PropertiesFilter;
|
||||
|
||||
class CustomVariablesFilter extends PropertiesFilter
|
||||
{
|
||||
public function match($type, $name, $object=null) {
|
||||
return parent::match($type, $name, $object) && $type === self::$CUSTOM_PROPERTY;
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Objects;
|
||||
|
||||
use Icinga\Data\Db\DbConnection;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Module\Director\Data\PropertiesFilter;
|
||||
use Icinga\Module\Director\Db;
|
||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
|
||||
@ -81,31 +82,27 @@ class IcingaHost extends IcingaObject
|
||||
|
||||
protected $supportsFields = true;
|
||||
|
||||
public static function enumProperties(DbConnection $connection = null, $prefix = '')
|
||||
public static function enumProperties(DbConnection $connection = null, $prefix = '', $filter= null)
|
||||
{
|
||||
$hostProperties = array($prefix . 'name' => 'name');
|
||||
$hostProperties = array();
|
||||
if ($filter === null) {
|
||||
$filter = new PropertiesFilter();
|
||||
}
|
||||
$realProperties = static::create()->listProperties();
|
||||
sort($realProperties);
|
||||
|
||||
$blacklist = array(
|
||||
'id',
|
||||
'object_name',
|
||||
'object_type',
|
||||
'disabled',
|
||||
'has_agent',
|
||||
'master_should_connect',
|
||||
'accept_config',
|
||||
);
|
||||
|
||||
if ($filter->match(PropertiesFilter::$HOST_PROPERTY, 'name')) {
|
||||
$hostProperties[$prefix . 'name'] = 'name';
|
||||
}
|
||||
foreach ($realProperties as $prop) {
|
||||
if (in_array($prop, $blacklist)) {
|
||||
if (!$filter->match(PropertiesFilter::$HOST_PROPERTY, $prop)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (substr($prop, -3) === '_id') {
|
||||
$prop = substr($prop, 0, -3);
|
||||
}
|
||||
|
||||
|
||||
$hostProperties[$prefix . $prop] = $prop;
|
||||
}
|
||||
|
||||
@ -113,14 +110,16 @@ class IcingaHost extends IcingaObject
|
||||
|
||||
if ($connection !== null) {
|
||||
foreach ($connection->fetchDistinctHostVars() as $var) {
|
||||
if ($var->datatype) {
|
||||
$hostVars[$prefix . 'vars.' . $var->varname] = sprintf(
|
||||
'%s (%s)',
|
||||
$var->varname,
|
||||
$var->caption
|
||||
);
|
||||
} else {
|
||||
$hostVars[$prefix . 'vars.' . $var->varname] = $var->varname;
|
||||
if ($filter->match(PropertiesFilter::$CUSTOM_PROPERTY, $var->varname, $var)) {
|
||||
if ($var->datatype) {
|
||||
$hostVars[$prefix . 'vars.' . $var->varname] = sprintf(
|
||||
'%s (%s)',
|
||||
$var->varname,
|
||||
$var->caption
|
||||
);
|
||||
} else {
|
||||
$hostVars[$prefix . 'vars.' . $var->varname] = $var->varname;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -131,9 +130,11 @@ class IcingaHost extends IcingaObject
|
||||
|
||||
$props = mt('director', 'Host properties');
|
||||
$vars = mt('director', 'Custom variables');
|
||||
$properties = array(
|
||||
$props => $hostProperties,
|
||||
);
|
||||
|
||||
$properties = array();
|
||||
if (!empty($hostProperties)) {
|
||||
$properties[$props] = $hostProperties;
|
||||
}
|
||||
|
||||
if (!empty($hostVars)) {
|
||||
$properties[$vars] = $hostVars;
|
||||
|
@ -39,6 +39,7 @@ class IcingaService extends IcingaObject
|
||||
'icon_image' => null,
|
||||
'icon_image_alt' => null,
|
||||
'use_agent' => null,
|
||||
'apply_for' => null,
|
||||
'use_var_overrides' => null,
|
||||
);
|
||||
|
||||
@ -84,6 +85,13 @@ class IcingaService extends IcingaObject
|
||||
|
||||
protected $prioritizedProperties = array('host_id');
|
||||
|
||||
protected $propertiesNotForRendering = array(
|
||||
'id',
|
||||
'object_name',
|
||||
'object_type',
|
||||
'apply_for'
|
||||
);
|
||||
|
||||
public function getCheckCommand()
|
||||
{
|
||||
$id = $this->getResolvedProperty('check_command_id');
|
||||
@ -144,6 +152,23 @@ class IcingaService extends IcingaObject
|
||||
return $this->renderRelationProperty('host', $this->host_id, 'host_name');
|
||||
}
|
||||
|
||||
protected function renderObjectHeader()
|
||||
{
|
||||
if ($this->isApplyRule()
|
||||
&& !$this->hasBeenAssignedToHostTemplate()
|
||||
&& $this->get('apply_for') !== null) {
|
||||
|
||||
return sprintf(
|
||||
"%s %s %s for (value in %s) {\n",
|
||||
$this->getObjectTypeName(),
|
||||
$this->getType(),
|
||||
c::renderString($this->getObjectName()),
|
||||
$this->get('apply_for')
|
||||
);
|
||||
}
|
||||
return parent::renderObjectHeader();
|
||||
}
|
||||
|
||||
protected function renderAssignments()
|
||||
{
|
||||
if (! $this->hasBeenAssignedToHostTemplate()) {
|
||||
|
@ -72,10 +72,10 @@ abstract class QuickBaseForm extends Zend_Form
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function optionalEnum($enum)
|
||||
public function optionalEnum($enum, $text='- please choose -')
|
||||
{
|
||||
return array(
|
||||
null => $this->translate('- please choose -')
|
||||
null => $this->translate($text)
|
||||
) + $enum;
|
||||
}
|
||||
|
||||
|
6
schema/mysql-migrations/upgrade_119.sql
Normal file
6
schema/mysql-migrations/upgrade_119.sql
Normal file
@ -0,0 +1,6 @@
|
||||
ALTER TABLE icinga_service
|
||||
ADD COLUMN apply_for VARCHAR(255) DEFAULT NULL AFTER use_agent;
|
||||
|
||||
INSERT INTO director_schema_migration
|
||||
(schema_version, migration_time)
|
||||
VALUES (110, NOW());
|
6
schema/pgsql-migrations/upgrade_119.sql
Normal file
6
schema/pgsql-migrations/upgrade_119.sql
Normal file
@ -0,0 +1,6 @@
|
||||
ALTER TABLE icinga_service
|
||||
ADD COLUMN apply_for character varying(255) DEFAULT NULL;
|
||||
|
||||
INSERT INTO director_schema_migration
|
||||
(schema_version, migration_time)
|
||||
VALUES (110, NOW());
|
@ -2,7 +2,10 @@
|
||||
|
||||
namespace Tests\Icinga\Module\Director\Objects;
|
||||
|
||||
use Icinga\Module\Director\Data\PropertiesFilter\ArrayCustomVariablesFilter;
|
||||
use Icinga\Module\Director\Data\PropertiesFilter\CustomVariablesFilter;
|
||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||
use Icinga\Module\Director\Objects\DirectorDatafield;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
use Icinga\Module\Director\Objects\IcingaZone;
|
||||
use Icinga\Module\Director\Test\BaseTestCase;
|
||||
@ -11,6 +14,7 @@ use Icinga\Exception\IcingaException;
|
||||
class IcingaHostTest extends BaseTestCase
|
||||
{
|
||||
protected $testHostName = '___TEST___host';
|
||||
protected $testDatafieldName = 'test5';
|
||||
|
||||
public function testPropertiesCanBeSet()
|
||||
{
|
||||
@ -473,6 +477,137 @@ class IcingaHostTest extends BaseTestCase
|
||||
IcingaHost::loadWithApiKey('No___such___key', $db);
|
||||
}
|
||||
|
||||
public function testEnumProperties() {
|
||||
if ($this->skipForMissingDb()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = $this->getDb();
|
||||
$properties = IcingaHost::enumProperties($db);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'Host properties' => $this->getDefaultHostProperties()
|
||||
),
|
||||
$properties
|
||||
);
|
||||
}
|
||||
|
||||
public function testEnumPropertiesWithCustomVars() {
|
||||
if ($this->skipForMissingDb()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = $this->getDb();
|
||||
|
||||
$host = $this->host();
|
||||
$host->store($db);
|
||||
|
||||
$properties = IcingaHost::enumProperties($db);
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'Host properties' => $this->getDefaultHostProperties(),
|
||||
'Custom variables' => array(
|
||||
'vars.test1' => 'test1',
|
||||
'vars.test2' => 'test2',
|
||||
'vars.test3' => 'test3',
|
||||
'vars.test4' => 'test4'
|
||||
)
|
||||
),
|
||||
$properties
|
||||
);
|
||||
}
|
||||
|
||||
public function testEnumPropertiesWithPrefix() {
|
||||
if ($this->skipForMissingDb()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = $this->getDb();
|
||||
|
||||
$host = $this->host();
|
||||
$host->store($db);
|
||||
|
||||
$properties = IcingaHost::enumProperties($db, 'host.');
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'Host properties' => $this->getDefaultHostProperties('host.'),
|
||||
'Custom variables' => array(
|
||||
'host.vars.test1' => 'test1',
|
||||
'host.vars.test2' => 'test2',
|
||||
'host.vars.test3' => 'test3',
|
||||
'host.vars.test4' => 'test4'
|
||||
)
|
||||
),
|
||||
$properties
|
||||
);
|
||||
}
|
||||
|
||||
public function testEnumPropertiesWithFilter() {
|
||||
if ($this->skipForMissingDb()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = $this->getDb();
|
||||
|
||||
DirectorDatafield::create(array(
|
||||
'varname' => $this->testDatafieldName,
|
||||
'caption' => 'Blah',
|
||||
'description' => '',
|
||||
'datatype' => 'Icinga\Module\Director\DataType\DataTypeArray',
|
||||
'format' => 'json'
|
||||
))->store($db);
|
||||
|
||||
$host = $this->host();
|
||||
$host->{'vars.test5'} = array('a', '1');
|
||||
$host->store($db);
|
||||
|
||||
$properties = IcingaHost::enumProperties($db, '', new CustomVariablesFilter());
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'Custom variables' => array(
|
||||
'vars.test1' => 'test1',
|
||||
'vars.test2' => 'test2',
|
||||
'vars.test3' => 'test3',
|
||||
'vars.test4' => 'test4',
|
||||
'vars.test5' => 'test5 (Blah)'
|
||||
)
|
||||
),
|
||||
$properties
|
||||
);
|
||||
}
|
||||
|
||||
public function testEnumPropertiesWithArrayFilter() {
|
||||
if ($this->skipForMissingDb()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db = $this->getDb();
|
||||
|
||||
DirectorDatafield::create(array(
|
||||
'varname' => $this->testDatafieldName,
|
||||
'caption' => 'Blah',
|
||||
'description' => '',
|
||||
'datatype' => 'Icinga\Module\Director\DataType\DataTypeArray',
|
||||
'format' => 'json'
|
||||
))->store($db);
|
||||
|
||||
$host = $this->host();
|
||||
$host->{'vars.test5'} = array('a', '1');
|
||||
$host->store($db);
|
||||
|
||||
$properties = IcingaHost::enumProperties($db, '', new ArrayCustomVariablesFilter());
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'Custom variables' => array(
|
||||
'vars.test5' => 'test5 (Blah)'
|
||||
)
|
||||
),
|
||||
$properties
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
protected function getDummyRelatedProperties()
|
||||
{
|
||||
return array(
|
||||
@ -506,6 +641,36 @@ class IcingaHostTest extends BaseTestCase
|
||||
));
|
||||
}
|
||||
|
||||
protected function getDefaultHostProperties($prefix = '') {
|
||||
return array(
|
||||
"${prefix}name" => "name",
|
||||
"${prefix}action_url" => "action_url",
|
||||
"${prefix}address" => "address",
|
||||
"${prefix}address6" => "address6",
|
||||
"${prefix}api_key" => "api_key",
|
||||
"${prefix}check_command" => "check_command",
|
||||
"${prefix}check_interval" => "check_interval",
|
||||
"${prefix}check_period" => "check_period",
|
||||
"${prefix}command_endpoint" => "command_endpoint",
|
||||
"${prefix}display_name" => "display_name",
|
||||
"${prefix}enable_active_checks" => "enable_active_checks",
|
||||
"${prefix}enable_event_handler" => "enable_event_handler",
|
||||
"${prefix}enable_flapping" => "enable_flapping",
|
||||
"${prefix}enable_notifications" => "enable_notifications",
|
||||
"${prefix}enable_passive_checks" => "enable_passive_checks",
|
||||
"${prefix}enable_perfdata" => "enable_perfdata",
|
||||
"${prefix}event_command" => "event_command",
|
||||
"${prefix}flapping_threshold" => "flapping_threshold",
|
||||
"${prefix}icon_image" => "icon_image",
|
||||
"${prefix}icon_image_alt" => "icon_image_alt",
|
||||
"${prefix}max_check_attempts" => "max_check_attempts",
|
||||
"${prefix}notes" => "notes",
|
||||
"${prefix}notes_url" => "notes_url",
|
||||
"${prefix}retry_interval" => "retry_interval",
|
||||
"${prefix}volatile" => "volatile",
|
||||
"${prefix}zone" => "zone"
|
||||
);
|
||||
}
|
||||
protected function loadRendered($name)
|
||||
{
|
||||
return file_get_contents(__DIR__ . '/rendered/' . $name . '.out');
|
||||
@ -528,6 +693,24 @@ class IcingaHostTest extends BaseTestCase
|
||||
IcingaZone::load($name, $db)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$this->deleteDatafields();
|
||||
}
|
||||
}
|
||||
|
||||
protected function deleteDatafields() {
|
||||
$db = $this->getDb();
|
||||
$dbAdapter = $db->getDbAdapter();
|
||||
$kill = array($this->testDatafieldName);
|
||||
|
||||
foreach ($kill as $name) {
|
||||
$query = $dbAdapter->select()
|
||||
->from('director_datafield')
|
||||
->where('varname = ?', $name);
|
||||
foreach (DirectorDatafield::loadAll($db, $query, 'id') as $datafield) {
|
||||
$datafield->delete();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user