diff --git a/application/forms/AssignListSubForm.php b/application/forms/AssignListSubForm.php
index 41954673..814e0cfd 100644
--- a/application/forms/AssignListSubForm.php
+++ b/application/forms/AssignListSubForm.php
@@ -7,7 +7,6 @@ use Icinga\Module\Director\Web\Form\QuickSubForm;
class AssignListSubForm extends QuickSubForm
{
-
protected $object;
public function setObject($object)
@@ -16,20 +15,15 @@ class AssignListSubForm extends QuickSubForm
return $this;
}
- public function setValue($value)
- {
- var_dump($value);
- }
-
public function setup()
{
$idx = -1;
if ($this->object && $this->object->supportsAssignments()) {
-// $this->setElementValue('assignlist', $object->assignments()->getFormValues());
- foreach ($this->object->assignments()->getFormValues() as $values) {
+
+ foreach ($this->object->assignments()->getValues() as $values) {
$idx++;
- $sub = new AssignmentSubForm();
+ $sub = $this->loadForm('assignmentSub');
$sub->setObject($this->object);
$sub->setup();
$sub->populate($values);
@@ -38,7 +32,7 @@ class AssignListSubForm extends QuickSubForm
}
$idx++;
- $sub = new AssignmentSubForm();
+ $sub = $this->loadForm('assignmentSub');
$sub->setObject($this->object);
$sub->setup();
$this->addSubForm($sub, $idx);
@@ -48,6 +42,7 @@ class AssignListSubForm extends QuickSubForm
'ignore' => true,
));
$this->getElement('addmore')->setDecorators(array('ViewHelper'));
+
}
public function loadDefaultDecorators()
@@ -56,7 +51,7 @@ class AssignListSubForm extends QuickSubForm
'FormElements',
array('HtmlTag', array(
'tag' => 'ul',
- 'class' => 'assign-rule'
+ 'class' => 'assign-rule required'
)),
array('Fieldset', array(
'legend' => 'Assignment rules',
diff --git a/application/forms/AssignmentSubForm.php b/application/forms/AssignmentSubForm.php
index c719d494..d050a101 100644
--- a/application/forms/AssignmentSubForm.php
+++ b/application/forms/AssignmentSubForm.php
@@ -24,44 +24,13 @@ class AssignmentSubForm extends QuickSubForm
'class' => 'assign-type',
'value' => 'assign'
));
- $this->addElement('select', 'property', array(
- 'label' => $this->translate('Property'),
- 'class' => 'assign-property autosubmit',
- 'multiOptions' => $this->optionalEnum(IcingaHost::enumProperties($this->object->getConnection(), 'host.'))
- ));
- $this->addElement('select', 'operator', array(
- 'label' => $this->translate('Operator'),
- 'multiOptions' => array(
- '=' => '=',
- '!=' => '!=',
- '>' => '>',
- '>=' => '>=',
- '<=' => '<=',
- '<' => '<',
- ),
- 'required' => $this->valueIsEmpty($this->getValue('property')),
- 'value' => '=',
- 'class' => 'assign-operator',
+
+ $this->addElement('dataFilter', 'filter_string', array(
+ 'columns' => IcingaHost::enumProperties($this->db)
));
- $this->addElement('text', 'expression', array(
- 'label' => $this->translate('Expression'),
- 'placeholder' => $this->translate('Expression'),
- 'class' => 'assign-expression',
- 'required' => !$this->valueIsEmpty($this->getValue('property'))
- ));
-/*
- $this->addElement('submit', 'remove', array(
- 'label' => '-',
- 'ignore' => true
- ));
- $this->addElement('submit', 'add', array(
- 'label' => '+',
- 'ignore' => true
- ));
-*/
foreach ($this->getElements() as $el) {
- $el->setDecorators(array('ViewHelper'));
+ $el->setDecorators(array('ViewHelper', 'Errors'));
}
}
diff --git a/application/forms/IcingaHostGroupForm.php b/application/forms/IcingaHostGroupForm.php
index 96244359..1a16a4d1 100644
--- a/application/forms/IcingaHostGroupForm.php
+++ b/application/forms/IcingaHostGroupForm.php
@@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Forms;
+use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
class IcingaHostGroupForm extends DirectorObjectForm
@@ -23,12 +24,14 @@ class IcingaHostGroupForm extends DirectorObjectForm
protected function addAssignmentElements()
{
- $sub = new AssignListSubForm();
- $sub->setObject($this->object());
- $sub->setup();
- $sub->setOrder(30);
-
- $this->addSubForm($sub, 'assignlist');
+ $this->addAssignFilter(array(
+ 'columns' => IcingaHost::enumProperties($this->db, 'host.'),
+ 'required' => true,
+ 'description' => $this->translate(
+ 'This allows you to configure an assignment filter. Please feel'
+ . ' free to combine as many nested operators as you want'
+ )
+ ));
return $this;
}
diff --git a/application/forms/IcingaNotificationForm.php b/application/forms/IcingaNotificationForm.php
index 8a83ffac..d38d4003 100644
--- a/application/forms/IcingaNotificationForm.php
+++ b/application/forms/IcingaNotificationForm.php
@@ -2,6 +2,8 @@
namespace Icinga\Module\Director\Forms;
+use Icinga\Module\Director\Objects\IcingaHost;
+use Icinga\Module\Director\Objects\IcingaService;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
class IcingaNotificationForm extends DirectorObjectForm
@@ -41,31 +43,40 @@ class IcingaNotificationForm extends DirectorObjectForm
return $this;
}
- $this->addElement(
- 'select',
- 'apply_to',
- array(
- 'label' => $this->translate('Apply to'),
- 'description' => $this->translate(
- 'Whether this notification should affect hosts or services'
- ),
- 'required' => true,
- 'multiOptions' => $this->optionalEnum(
- array(
- 'host' => $this->translate('Hosts'),
- 'service' => $this->translate('Services'),
- )
+ $this->addElement('select', 'apply_to', array(
+ 'label' => $this->translate('Apply to'),
+ 'description' => $this->translate(
+ 'Whether this notification should affect hosts or services'
+ ),
+ 'required' => true,
+ 'class' => 'autosubmit',
+ 'multiOptions' => $this->optionalEnum(
+ array(
+ 'host' => $this->translate('Hosts'),
+ 'service' => $this->translate('Services'),
)
)
- );
+ ));
- $sub = new AssignListSubForm();
- $sub->setObject($this->getObject());
- $sub->setup();
- $sub->setOrder(30);
+ $applyTo = $this->getSentOrObjectValue('apply_to');
- $this->addSubForm($sub, 'assignlist');
+ if ($applyTo === 'host') {
+ $columns = IcingaHost::enumProperties($this->db, 'host.');
+ } elseif ($applyTo === 'service') {
+ // TODO: Also add host properties
+ $columns = IcingaService::enumProperties($this->db, 'service.');
+ } else {
+ return $this;
+ }
+ $this->addAssignFilter(array(
+ 'columns' => $columns,
+ 'required' => true,
+ 'description' => $this->translate(
+ 'This allows you to configure an assignment filter. Please feel'
+ . ' free to combine as many nested operators as you want'
+ )
+ ));
return $this;
}
diff --git a/application/forms/IcingaServiceForm.php b/application/forms/IcingaServiceForm.php
index 34acbf1b..9f28e38f 100644
--- a/application/forms/IcingaServiceForm.php
+++ b/application/forms/IcingaServiceForm.php
@@ -157,16 +157,14 @@ class IcingaServiceForm extends DirectorObjectForm
protected function addAssignmentElements()
{
- if (!$this->object || !$this->object->isApplyRule()) {
- return $this;
- }
-
- $sub = new AssignListSubForm();
- $sub->setObject($this->getObject());
- $sub->setup();
- $sub->setOrder(30);
-
- $this->addSubForm($sub, 'assignlist');
+ $this->addAssignFilter(array(
+ 'columns' => IcingaHost::enumProperties($this->db, 'host.'),
+ 'required' => true,
+ 'description' => $this->translate(
+ 'This allows you to configure an assignment filter. Please feel'
+ . ' free to combine as many nested operators as you want'
+ )
+ ));
return $this;
}
diff --git a/application/tables/IcingaNotificationTable.php b/application/tables/IcingaNotificationTable.php
index ded4025e..7205db31 100644
--- a/application/tables/IcingaNotificationTable.php
+++ b/application/tables/IcingaNotificationTable.php
@@ -47,7 +47,7 @@ class IcingaNotificationTable extends IcingaObjectTable
$htm .= ' ' . $v->qlink(
'Create apply-rule',
'director/notification/add',
- array('apply' => $row->notification),
+ array('apply' => $row->notification, 'type' => 'apply'),
array('class' => 'icon-plus')
);
@@ -72,23 +72,12 @@ class IcingaNotificationTable extends IcingaObjectTable
protected function appliedOnes($id)
{
- if ($this->connection()->isPgsql()) {
- $nameCol = "s.object_name || COALESCE(': ' || ARRAY_TO_STRING(ARRAY_AGG("
- . "a.assign_type || ' where ' || a.filter_string"
- . " ORDER BY a.assign_type, a.filter_string), ', '), '')";
- } else {
- $nameCol = "s.object_name || COALESCE(': ' || GROUP_CONCAT("
- . "a.assign_type || ' where ' || a.filter_string"
- . " ORDER BY a.assign_type, a.filter_string SEPARATOR ', '"
- . "), '')";
- }
-
$db = $this->connection()->getConnection();
$query = $db->select()->from(
array('s' => 'icinga_notification'),
array(
'id' => 's.id',
- 'objectname' => $nameCol,
+ 'objectname' => 's.object_name',
)
)->join(
array('i' => 'icinga_notification_inheritance'),
@@ -97,11 +86,6 @@ class IcingaNotificationTable extends IcingaObjectTable
)->where('i.parent_notification_id = ?', $id)
->where('s.object_type = ?', 'apply');
- $query->joinLeft(
- array('a' => 'icinga_notification_assignment'),
- 'a.notification_id = s.id',
- array()
- )->group('s.id');
return $db->fetchPairs($query);
}
diff --git a/application/tables/IcingaServiceTable.php b/application/tables/IcingaServiceTable.php
index 00736eab..30a8b4bd 100644
--- a/application/tables/IcingaServiceTable.php
+++ b/application/tables/IcingaServiceTable.php
@@ -2,6 +2,9 @@
namespace Icinga\Module\Director\Tables;
+use Icinga\Data\Filter\Filter;
+use Icinga\Exception\IcingaException;
+use Icinga\Module\Director\IcingaConfig\AssignRenderer;
use Icinga\Module\Director\Web\Table\QuickTable;
class IcingaServiceTable extends QuickTable
@@ -13,9 +16,9 @@ class IcingaServiceTable extends QuickTable
public function getColumns()
{
return array(
- 'id' => 's.id',
- 'service' => 's.object_name',
- 'object_type' => 's.object_type',
+ 'id' => 's.id',
+ 'service' => 's.object_name',
+ 'object_type' => 's.object_type',
'check_command_id' => 's.check_command_id',
);
}
@@ -47,21 +50,34 @@ class IcingaServiceTable extends QuickTable
if (empty($extra)) {
if ($row->check_command_id) {
$htm .= ' ' . $v->qlink(
- 'Create apply-rule',
- 'director/service/add',
- array('apply' => $row->service),
- array('class' => 'icon-plus')
- );
+ 'Create apply-rule',
+ 'director/service/add',
+ array('apply' => $row->service),
+ array('class' => 'icon-plus')
+ );
}
} else {
- $htm .= '. Related apply rules:
';
- foreach ($extra as $id => $service) {
- $htm .= '- '
- . $v->qlink($service, 'director/service', array('id' => $id))
- . '
';
+ $htm .= '. Related apply rules: ';
+ foreach ($extra as $service) {
+ $href = $v->url('director/service', array('id' => $service->id));
+ $htm .= "";
+
+ try {
+ $prettyFilter = AssignRenderer::forFilter(
+ Filter::fromQueryString($service->assign_filter)
+ )->renderAssign();
+ }
+ catch (IcingaException $e) {
+ // ignore errors in filter rendering
+ $prettyFilter = 'Error in Filter rendering: ' . $e->getMessage();
+ }
+
+ $htm .= "" . $service->object_name . ' | ';
+ $htm .= '' . $prettyFilter . ' | ';
+ $htm .= '
';
}
- $htm .= '';
+ $htm .= '
';
$htm .= $v->qlink(
'Add more',
'director/service/add',
@@ -109,23 +125,18 @@ class IcingaServiceTable extends QuickTable
$query = $db->select()->from(
array('s' => 'icinga_service'),
array(
- 'id' => 's.id',
- 'objectname' => $nameCol,
+ 'id' => 's.id',
+ 'object_name' => 's.object_name',
+ 'assign_filter' => 's.assign_filter',
)
)->join(
array('i' => 'icinga_service_inheritance'),
'i.service_id = s.id',
array()
)->where('i.parent_service_id = ?', $id)
- ->where('s.object_type = ?', 'apply');
+ ->where('s.object_type = ?', 'apply');
- $query->joinLeft(
- array('a' => 'icinga_service_assignment'),
- 'a.service_id = s.id',
- array()
- )->group('s.id');
-
- return $db->fetchPairs($query);
+ return $db->fetchAll($query);
}
public function getBaseQuery()
@@ -134,6 +145,6 @@ class IcingaServiceTable extends QuickTable
's.object_type IN (?)',
array('template')
)->order('CASE WHEN s.check_command_id IS NULL THEN 1 ELSE 0 END')
- ->order('s.object_name');
+ ->order('s.object_name');
}
}
diff --git a/application/views/helpers/FormDataFilter.php b/application/views/helpers/FormDataFilter.php
new file mode 100644
index 00000000..5f6e7617
--- /dev/null
+++ b/application/views/helpers/FormDataFilter.php
@@ -0,0 +1,453 @@
+_getInfo($name, $value, $attribs);
+ extract($info); // id, name, value, attribs, options, listsep, disable
+ if (array_key_exists('columns', $attribs)) {
+ $this->setColumns($attribs['columns']);
+ unset($attribs['columns']);
+ }
+
+ // TODO: check for columns in attribs, preserve & remove them from the
+ // array use attribs? class etc? disabled?
+ // override _getInfo?
+ $this->fieldName = $name;
+
+ if ($value === null) {
+ $value = $this->emptyExpression();
+ } elseif (is_string($value)) {
+ $value = Filter::fromQueryString($value);
+ }
+
+ return $this->beginRoot()
+ . $this->renderFilter($value)
+ . $this->endRoot();
+ }
+
+ protected function renderFilter(Filter $filter)
+ {
+ if ($filter instanceof FilterChain) {
+ return $this->renderFilterChain($filter);
+ } elseif ($filter instanceof FilterExpression) {
+ return $this->renderFilterExpression($filter);
+ } else {
+ throw new ProgrammingError('Got a Filter being neither expression nor chain');
+ }
+ }
+
+ protected function beginRoot()
+ {
+ return '';
+ }
+
+ protected function endRoot()
+ {
+ return '
';
+ }
+
+ protected function renderFilterChain(FilterChain $filter)
+ {
+ $parts = array();
+ foreach ($filter->filters() as $f) {
+ $parts[] = $this->renderFilter($f);
+ }
+
+ return $this->beginChain($filter)
+ . implode('', $parts)
+ . $this->endChain($filter);
+ }
+
+ protected function beginChain(FilterChain $filter)
+ {
+ $list = $filter->isEmpty() ? '' : '' . "\n";
+
+ return '- '
+ . $this->selectOperator($filter)
+ . $this->removeLink($filter)
+ . $this->addLink($filter)
+ . ($filter->count() === 1 ? $this->stripLink($filter) : '')
+ . $list;
+ }
+
+ protected function endChain(FilterChain $filter)
+ {
+ $list = $filter->isEmpty() ? '' : "
\n";
+ return $list . "\n";
+ }
+
+ protected function beginExpression(FilterExpression $filter)
+ {
+ return '' . "\n";
+ }
+
+ protected function endExpression(FilterExpression $filter)
+ {
+ return "
\n";
+ }
+
+ protected function beginElement(FilterExpression $filter)
+ {
+ return '' . "\n";
+ }
+
+ protected function endElement(FilterExpression $filter)
+ {
+ return "
\n";
+ }
+
+ protected function filterExpressionHtml(FilterExpression $filter)
+ {
+ return $this->selectColumn($filter)
+ . $this->selectSign($filter)
+ . $this->beginElement($filter)
+ . $this->element($filter)
+ . $this->endElement($filter)
+ . $this->removeLink($filter)
+ . $this->expandLink($filter);
+ }
+
+ protected function renderFilterExpression(FilterExpression $filter)
+ {
+ return $this->beginExpression($filter)
+ . $this->filterExpressionHtml($filter)
+ . $this->endExpression($filter);
+ }
+
+ protected function element(FilterExpression $filter = null)
+ {
+ if ($filter) {
+ // TODO: Make this configurable
+ $type = 'host';
+ $filter = clone($filter);
+
+ $filter->setExpression(json_decode($filter->getExpression()));
+ $dummy = IcingaObject::createByType($type);
+ $col = $filter->getColumn();
+ if ($dummy->hasProperty($col)) {
+ if ($dummy->propertyIsBoolean($col)) {
+ return $this->boolean($filter);
+ }
+ }
+
+ if ($col === 'groups' && $dummy->supportsGroups()) {
+ return $this->selectGroup($type, $filter);
+ }
+ }
+
+ return $this->text($filter);
+ }
+
+ protected function selectGroup($type, Filter $filter)
+ {
+ $available = IcingaObjectGroup::enumForType($type);
+
+ return $this->select(
+ $this->elementId('value', $filter),
+ $this->optionalEnum($available),
+ $filter->getExpression()
+ );
+ }
+
+ protected function boolean(Filter $filter = null)
+ {
+ $value = $filter === null ? '' : $filter->getExpression();
+
+ $el = new Icinga\Module\Director\Web\Form\Element\Boolean(
+ $this->elementId('value', $filter),
+ array(
+ 'value' => $value,
+ 'decorators' => array('ViewHelper'),
+ )
+ );
+
+ return $el;
+ }
+
+ protected function text(Filter $filter = null)
+ {
+ $value = $filter === null ? '' : $filter->getExpression();
+ if (is_array($value)) {
+ return $this->view->formExtensibleSet(
+ $this->elementId('value', $filter),
+ $value
+ );
+
+ $value = '(' . implode('|', $value) . ')';
+ }
+
+ return $this->view->formText(
+ $this->elementId('value', $filter),
+ $value
+ );
+ }
+
+ protected function emptyExpression()
+ {
+ return Filter::expression('', '=', '');
+ }
+
+ protected function arrayForSelect($array, $flip = false)
+ {
+ $res = array();
+ foreach ($array as $k => $v) {
+ if (is_int($k)) {
+ $res[$v] = ucwords(str_replace('_', ' ', $v));
+ } elseif ($flip) {
+ $res[$v] = $k;
+ } else {
+ $res[$k] = $v;
+ }
+ }
+ // sort($res);
+ return $res;
+ }
+
+ protected function elementId($field, Filter $filter = null)
+ {
+ $prefix = $this->fieldName . '[id_';
+ $suffix = '][' . $field . ']';
+
+ return $prefix . $filter->getId() . $suffix;
+ }
+
+ protected function selectOperator(Filter $filter = null)
+ {
+ $ops = array(
+ 'AND' => 'AND',
+ 'OR' => 'OR',
+ 'NOT' => 'NOT'
+ );
+
+ return $this->view->formSelect(
+ $this->elementId('operator', $filter),
+ $filter === null ? null : $filter->getOperatorName(),
+ array(
+ 'class' => 'operator autosubmit',
+ ),
+ $ops
+ );
+ return $this->select(
+ $this->elementId('operator', $filter),
+ $ops,
+ $filter === null ? null : $filter->getOperatorName(),
+ array('class' => 'operator autosubmit')
+ );
+ }
+
+ protected function selectSign(Filter $filter = null)
+ {
+ $signs = array(
+ '=' => '=',
+ '!=' => '!=',
+ '>' => '>',
+ '<' => '<',
+ '>=' => '>=',
+ '<=' => '<=',
+ 'in' => 'in',
+ 'true' => 'is true (or set)',
+ );
+
+ if ($filter === null) {
+ $sign = null;
+ } else {
+ if ($filter->getExpression() === true) {
+ $sign = 'true';
+ } elseif (is_array($filter->getExpression())) {
+ $sign = 'in';
+ } else {
+ $sign = $filter->getSign();
+ }
+ }
+
+ $class = 'sign autosubmit';
+ if (strlen($sign) > 3) {
+ $class .= ' wide';
+ }
+
+ return $this->select(
+ $this->elementId('sign', $filter),
+ $signs,
+ $sign,
+ array('class' => $class)
+ );
+ }
+
+ public function setColumns(array $columns = null)
+ {
+ $this->cachedColumnSelect = $columns ? $this->arrayForSelect($columns) : null;
+ return $this;
+ }
+
+ protected function selectColumn(Filter $filter = null)
+ {
+ $active = $filter === null ? null : $filter->getColumn();
+
+ if (! $this->hasColumnList()) {
+ return $this->view->formText(
+ $this->elementId('column', $filter),
+ $active
+ );
+ }
+
+ $cols = $this->getColumnList();
+ if ($active && !isset($cols[$active])) {
+ $cols[$active] = str_replace(
+ '_',
+ ' ',
+ ucfirst(ltrim($active, '_'))
+ ); // ??
+ }
+
+ $cols = $this->optionalEnum($cols);
+
+ return $this->select(
+ $this->elementId('column', $filter),
+ $cols,
+ $active,
+ array('class' => 'column autosubmit')
+ );
+ }
+
+ protected function optionalEnum($enum)
+ {
+ return array_merge(
+ array(null => $this->view->translate('- please choose -')),
+ $enum
+ );
+ }
+
+ protected function hasColumnList()
+ {
+ return $this->cachedColumnSelect !== null || $this->query !== null;
+ }
+
+ protected function getColumnList()
+ {
+ if ($this->cachedColumnSelect === null) {
+ $this->fetchColumnList();
+ }
+
+ return $this->cachedColumnSelect;
+ }
+
+ protected function fetchColumnList()
+ {
+ if ($this->query instanceof FilterColumns) {
+ $this->cachedColumnSelect = $this->arrayForSelect(
+ $this->query->getFilterColumns(),
+ true
+ );
+ asort($this->cachedColumnSelect);
+ } elseif ($this->cachedColumnSelect === null) {
+ throw new ProgrammingError('No columns set nor does the query provide any');
+ }
+ }
+
+ protected function select($name, $list, $selected, $attributes = null)
+ {
+ return $this->view->formSelect($name, $selected, $attributes, $list);
+ }
+
+ protected function removeLink(Filter $filter)
+ {
+ return $this->filterActionButton(
+ $filter,
+ 'cancel',
+ t('Remove this part of your filter')
+ );
+ }
+
+ protected function addLink(Filter $filter)
+ {
+ return $this->filterActionButton(
+ $filter,
+ 'plus',
+ t('Add another filter')
+ );
+ }
+
+ protected function expandLink(Filter $filter)
+ {
+ return $this->filterActionButton(
+ $filter,
+ 'angle-double-right',
+ t('Wrap this expression into an operator')
+ );
+ }
+
+ protected function stripLink(Filter $filter)
+ {
+ return $this->filterActionButton(
+ $filter,
+ 'minus',
+ t('Strip this operator, preserve child nodes')
+ );
+ }
+
+ protected function filterActionButton(Filter $filter, $action, $title)
+ {
+ return $this->iconButton(
+ $this->getActionButtonName($filter),
+ $action,
+ $title
+ );
+ }
+
+ protected function getActionButtonName(Filter $filter)
+ {
+ return sprintf(
+ '%s[id_%s][action]',
+ $this->fieldName,
+ $filter->getId()
+ );
+ }
+
+ protected function iconButton($name, $icon, $title)
+ {
+ return $this->view->formSubmit(
+ $name,
+ IconHelper::instance()->iconCharacter($icon),
+ array('class' => 'icon-button', 'title' => $title)
+ );
+ }
+}
diff --git a/library/Director/IcingaConfig/AssignRenderer.php b/library/Director/IcingaConfig/AssignRenderer.php
index 39baaeea..298f77f2 100644
--- a/library/Director/IcingaConfig/AssignRenderer.php
+++ b/library/Director/IcingaConfig/AssignRenderer.php
@@ -54,6 +54,23 @@ class AssignRenderer
}
}
+ protected function renderEquals($column, $expression)
+ {
+ if ($column === 'groups') {
+ return sprintf(
+ '%s in %s',
+ $expression,
+ $column
+ );
+ } else {
+ return sprintf(
+ '%s == %s',
+ $column,
+ $expression
+ );
+ }
+ }
+
protected function renderFilterExpression($filter)
{
$column = $filter->getColumn();
@@ -67,11 +84,7 @@ class AssignRenderer
} elseif ($filter instanceof FilterMatch) {
if (strpos($expression, '*') === false) {
- return sprintf(
- '%s == %s',
- $column,
- $expression
- );
+ return $this->renderEquals($column, $expression);
} else {
return sprintf(
'match(%s, %s)',
diff --git a/library/Director/Objects/IcingaHost.php b/library/Director/Objects/IcingaHost.php
index 81633e26..8b8765da 100644
--- a/library/Director/Objects/IcingaHost.php
+++ b/library/Director/Objects/IcingaHost.php
@@ -139,6 +139,8 @@ class IcingaHost extends IcingaObject
$properties[$props] = $hostProperties;
}
+ $properties['groups'] = 'Groups';
+
if (!empty($hostVars)) {
$properties[$vars] = $hostVars;
}
diff --git a/library/Director/Objects/IcingaNotification.php b/library/Director/Objects/IcingaNotification.php
index c5c5cb5a..0677fce2 100644
--- a/library/Director/Objects/IcingaNotification.php
+++ b/library/Director/Objects/IcingaNotification.php
@@ -25,6 +25,7 @@ class IcingaNotification extends IcingaObject
'notification_interval' => null,
'period_id' => null,
'zone_id' => null,
+ 'assign_filter' => null,
);
protected $supportsCustomVars = true;
diff --git a/library/Director/Objects/IcingaObject.php b/library/Director/Objects/IcingaObject.php
index 6d1a7cb4..7c68d14f 100644
--- a/library/Director/Objects/IcingaObject.php
+++ b/library/Director/Objects/IcingaObject.php
@@ -3,6 +3,7 @@
namespace Icinga\Module\Director\Objects;
use Icinga\Module\Director\CustomVariable\CustomVariables;
+use Icinga\Module\Director\IcingaConfig\AssignRenderer;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Db\Cache\PrefetchCache;
use Icinga\Module\Director\Db;
@@ -385,6 +386,38 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $this->supportsSets;
}
+ public function setAssignments($value)
+ {
+ return IcingaObjectLegacyAssignments::applyToObject($this, $value);
+ }
+
+ /**
+ * @codingStandardsIgnoreStart
+ */
+ public function setAssign_filter($filter)
+ {
+ if (! $this->supportsAssignments()) {
+ if ($this->hasProperty('object_type')) {
+ $type = $this->object_type;
+ } else {
+ $type = get_class($this);
+ }
+
+ throw new ProgrammingError(
+ 'I can only assign for applied objects or objects with native'
+ . ' support for assigments, got %s',
+ $type
+ );
+ }
+
+ // @codingStandardsIgnoreEnd
+ if ($filter instanceof Filter) {
+ $filter = $filter->toQueryString();
+ }
+
+ return $this->reallySet('assign_filter', $filter);
+ }
+
/**
* It sometimes makes sense to defer lookups for related properties. This
* kind of lazy-loading allows us to for example set host = 'localhost' and
@@ -440,10 +473,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return true;
}
- if ($this->supportsAssignments() && $this->assignments !== null && $this->assignments()->hasBeenModified()) {
- return true;
- }
-
foreach ($this->loadedRelatedSets as $set) {
if ($set->hasBeenModified()) {
return true;
@@ -626,21 +655,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $this->arguments()->toPlainObject();
}
- protected function setAssignments($value)
- {
- $this->assignments()->setValues($value);
- return $this;
- }
-
- public function assignments()
- {
- if ($this->assignments === null) {
- $this->assignments = new IcingaObjectAssignments($this);
- }
-
- return $this->assignments;
- }
-
protected function getRanges()
{
return $this->ranges()->getValues();
@@ -1213,11 +1227,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $fields;
}
- protected function getAssignments()
- {
- return $this->assignments()->getValues();
- }
-
public function hasProperty($key)
{
if ($this->propertyIsRelatedSet($key)) {
@@ -1264,8 +1273,7 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
->storeImports()
->storeRanges()
->storeRelatedSets()
- ->storeArguments()
- ->storeAssignments();
+ ->storeArguments();
}
protected function beforeStore()
@@ -1330,15 +1338,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $this;
}
- protected function storeAssignments()
- {
- if ($this->supportsAssignments()) {
- $this->assignments !== null && $this->assignments()->store();
- }
-
- return $this;
- }
-
protected function storeRelatedSets()
{
foreach ($this->loadedRelatedSets as $set) {
@@ -1895,15 +1894,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
);
}
- protected function renderAssignments()
- {
- if ($this->supportsAssignments()) {
- return $this->assignments()->toConfigString();
- } else {
- return '';
- }
- }
-
protected function renderLegacyObjectHeader()
{
$type = strtolower($this->getType());
@@ -1933,6 +1923,17 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $str;
}
+ /**
+ * @codingStandardsIgnoreStart
+ */
+ public function renderAssign_Filter()
+ {
+ // @codingStandardsIgnoreEnd
+ return ' ' . AssignRenderer::forFilter(
+ Filter::fromQueryString($this->assign_filter)
+ )->renderAssign() . "\n";
+ }
+
public function toLegacyConfigString()
{
$str = implode(array(
@@ -1946,7 +1947,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
//$this->renderMultiRelations(),
//$this->renderCustomExtensions(),
//$this->renderCustomVars(),
- //$this->renderAssignments(),
$this->renderLegacySuffix()
));
@@ -1993,7 +1993,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
$this->renderMultiRelations(),
$this->renderCustomExtensions(),
$this->renderCustomVars(),
- $this->renderAssignments(),
$this->renderSuffix()
));
@@ -2235,10 +2234,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
);
}
- if ($this->supportsAssignments()) {
- $props['assignments'] = $this->assignments()->getPlain();
- }
-
if ($this->supportsCustomVars()) {
if ($resolved) {
$props['vars'] = $this->getResolvedVars();
@@ -2414,10 +2409,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
}
}
- if ($this->supportsAssignments()) {
- $props['assignments'] = $this->assignments()->getUnmodifiedPlain();
- }
-
foreach ($this->relatedSets() as $property => $set) {
if ($set->isEmpty()) {
continue;
@@ -2465,7 +2456,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
unset($this->ranges);
unset($this->arguments);
-
parent::__destruct();
}
}
diff --git a/library/Director/Objects/IcingaObjectAssignments.php b/library/Director/Objects/IcingaObjectAssignments.php
deleted file mode 100644
index b3ab3930..00000000
--- a/library/Director/Objects/IcingaObjectAssignments.php
+++ /dev/null
@@ -1,313 +0,0 @@
-supportsAssignments()) {
- throw new ProgrammingError(
- 'I can only assign for applied objects, got %s',
- $object->object_type
- );
- }
-
- $this->object = $object;
- }
-
- public function store()
- {
- if ($this->hasBeenModified()) {
- $this->reallyStore();
- return true;
- }
-
- return false;
- }
-
- public function setValues($values)
- {
- if (is_string($values)) {
- return $this->setValues(array($values));
- }
-
- $this->current = array();
- if (is_object($values)) {
- $values = (array) $values;
- }
-
- ksort($values);
- foreach ((array) $values as $type => $value) {
- if (is_numeric($type)) {
- $this->addRule($value);
- } else {
- if (is_string($value)) {
- $this->addRule($value, $type);
- continue;
- }
-
- foreach ($value as $key => $strings) {
- $this->addRule($strings, $type);
- }
- }
- }
-
- return $this;
- }
-
- public function getFormValues()
- {
- $result = array();
- foreach ($this->getCurrent() as $rule) {
- $f = array(
- 'assign_type' => $rule['assign_type']
- );
-
- $filter = Filter::fromQueryString($rule['filter_string']);
- if (!$filter->isExpression()) {
- throw new IcingaException(
- 'We currently support only flat filters in our forms, got %',
- (string) $filter
- );
- }
-
- $f['property'] = $filter->getColumn();
- $f['operator'] = $filter->getSign();
- $f['expression'] = trim(stripcslashes($filter->getExpression()), '"');
-
- $result[] = $f;
- }
-
- return $result;
- }
-
- public function setFormValues($values)
- {
- $rows = array();
-
- foreach ($values as $key => $val) {
- if (! is_numeric($key)) {
- // Skip buttons or similar
- continue;
- }
-
- if (!array_key_exists($val['assign_type'], $rows)) {
- $rows[$val['assign_type']] = array();
- }
-
- if (empty($val['property'])) {
- continue;
- }
-
- if (is_numeric($val['expression'])) {
- $expression = $val['expression'];
- } else {
- $expression = '"' . addcslashes($val['expression'], '"') . '"';
- }
-
- $rows[$val['assign_type']][] = $this->rerenderFilter(
- implode('', array(
- $val['property'],
- $val['operator'],
- $expression,
- ))
- );
-
- }
-
- return $this->setValues($rows);
- }
-
- protected function addRule($string, $type = 'assign')
- {
- // TODO: validate
- $this->current[] = array(
- 'assign_type' => $type,
- 'filter_string' => $this->rerenderFilter($string)
- );
-
- return $this;
- }
-
- public function getValues()
- {
- return $this->getCurrent();
- }
-
- public function getUnmodifiedValues()
- {
- return $this->getStored();
- }
-
- public function toConfigString()
- {
- return $this->renderRules($this->getCurrent());
- }
-
- public function toUnmodifiedConfigString()
- {
- return $this->renderRules($this->getStored());
- }
-
- protected function renderRules($rules)
- {
- if (empty($rules)) {
- return '';
- }
-
- $filters = array();
-
- foreach ($rules as $rule) {
- $filters[] = AssignRenderer::forFilter(
- Filter::fromQueryString($rule['filter_string'])
- )->render($rule['assign_type']);
- }
-
- return "\n " . implode("\n ", $filters) . "\n";
- }
-
- public function getPlain()
- {
- if ($this->current === null) {
- if (! $this->object->hasBeenLoadedFromDb()) {
- return array();
- }
-
- $this->current = $this->getStored();
- }
-
- return $this->createPlain($this->current);
- }
-
- public function getUnmodifiedPlain()
- {
- if (! $this->object->hasBeenLoadedFromDb()) {
- return array();
- }
-
- return $this->createPlain($this->getStored());
- }
-
- public function hasBeenModified()
- {
- if ($this->current === null) {
- return false;
- }
-
- return json_encode($this->getCurrent()) !== json_encode($this->getStored());
- }
-
- protected function getCurrent()
- {
- if ($this->current === null) {
- $this->current = $this->getStored();
- }
-
- return $this->current;
- }
-
- protected function getStored()
- {
- if ($this->stored === null) {
- $this->stored = $this->loadFromDb();
- }
-
- return $this->stored;
- }
-
- protected function rerenderFilter($string)
- {
- return rawurldecode(Filter::fromQueryString($string)->toQueryString());
- }
-
- protected function createPlain($dbRows)
- {
- $result = array();
- foreach ($dbRows as $row) {
- if (! array_key_exists($row['assign_type'], $result)) {
- $result[$row['assign_type']] = array();
- }
-
- $result[$row['assign_type']][] = $row['filter_string'];
- }
-
- return $result;
- }
-
- protected function getDb()
- {
- return $this->object->getDb();
- }
-
- protected function loadFromDb()
- {
- $db = $this->getDb();
- $object = $this->object;
-
- $query = $db->select()->from(
- $this->getTableName(),
- array('assign_type', 'filter_string')
- )->where($this->createWhere())->order('assign_type', 'filter_string');
-
- $this->stored = array();
- foreach ($db->fetchAll($query) as $row) {
- $this->stored[] = (array) $row;
- }
-
- return $this->stored;
- }
-
- protected function createWhere()
- {
- return $this->getRelationColumn()
- . ' = '
- . $this->getObjectId();
- }
-
- protected function getObjectId()
- {
- return (int) $this->object->id;
- }
-
- protected function getRelationColumn()
- {
- return $this->object->getShortTableName() . '_id';
- }
-
- protected function getTableName()
- {
- return $this->object->getTableName() . '_assignment';
- }
-
- protected function reallyStore()
- {
- $db = $this->getDb();
- $table = $this->getTableName();
- $objectId = $this->object->id;
- $relationCol = $this->getRelationColumn();
-
- $db->delete($table, $this->createWhere());
-
- foreach ($this->getCurrent() as $row) {
- $data = (array) $row;
- $data[$relationCol] = $objectId;
- $db->insert($table, $data);
- }
-
- $this->stored = $this->current;
-
- return $this;
- }
-}
diff --git a/library/Director/Objects/IcingaObjectGroup.php b/library/Director/Objects/IcingaObjectGroup.php
index ff840876..b92a31ef 100644
--- a/library/Director/Objects/IcingaObjectGroup.php
+++ b/library/Director/Objects/IcingaObjectGroup.php
@@ -2,6 +2,9 @@
namespace Icinga\Module\Director\Objects;
+use Icinga\Application\Config;
+use Icinga\Exception\IcingaException;
+use Icinga\Module\Director\Db;
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
abstract class IcingaObjectGroup extends IcingaObject
@@ -9,15 +12,44 @@ abstract class IcingaObjectGroup extends IcingaObject
protected $supportsImports = true;
protected $defaultProperties = array(
- 'id' => null,
- 'object_name' => null,
- 'object_type' => null,
- 'disabled' => 'n',
- 'display_name' => null,
+ 'id' => null,
+ 'object_name' => null,
+ 'object_type' => null,
+ 'disabled' => 'n',
+ 'display_name' => null,
+ 'assign_filter' => null,
);
public function getRenderingZone(IcingaConfig $config = null)
{
return $this->connection->getDefaultGlobalZoneName();
}
+
+ public static function enumForType($type, Db $connection = null)
+ {
+ if ($connection === null) {
+ // TODO: not nice :(
+ $connection = Db::fromResourceName(
+ Config::module('director')->get('db', 'resource')
+ );
+ }
+
+ // Last resort defense against potentiall lousy checks:
+ if (! ctype_alpha($type)) {
+ throw new IcingaException(
+ 'Holy shit, you should never have reached this'
+ );
+ }
+
+ $db = $connection->getDbAdapter();
+ $select = $db->select()->from(
+ 'icinga_' . $type . 'group',
+ array(
+ 'name' => 'object_name',
+ 'display' => 'COALESCE(display_name, object_name)'
+ )
+ )->where('object_type = ?', 'object')->order('display');
+
+ return $db->fetchPairs($select);
+ }
}
diff --git a/library/Director/Objects/IcingaObjectLegacyAssignments.php b/library/Director/Objects/IcingaObjectLegacyAssignments.php
new file mode 100644
index 00000000..f30b06bb
--- /dev/null
+++ b/library/Director/Objects/IcingaObjectLegacyAssignments.php
@@ -0,0 +1,79 @@
+supportsAssignments()) {
+ throw new ProgrammingError(
+ 'I can only assign for applied objects, got %s',
+ $object->object_type
+ );
+ }
+
+ if ($values === null) {
+ return $object;
+ }
+
+ if (! is_array($values)) {
+ static::throwCompatError();
+ }
+
+ if (empty($values)) {
+ return $object;
+ }
+
+ $assigns = array();
+ $ignores = array();
+ foreach ($values as $type => $value) {
+ if (strpos($value, '|') !== false || strpos($value, '&' !== false)) {
+ $value = '(' . $value . ')';
+ }
+
+ if ($type === 'assign') {
+ $assigns[] = $value;
+ } elseif ($type === 'ignore') {
+ $ignores[] = $value;
+ } else {
+ static::throwCompatError();
+ }
+ }
+
+ $assign = implode('|', $assigns);
+ $ignore = implode('&', $ignores);
+ if (empty($assign)) {
+ $filter = $ignore;
+ } elseif (empty($ignore)) {
+ $filter = $assign;
+ } else {
+ if (count($assigns) === 1) {
+ $filter = $assign . '&' . $ignore;
+ } else {
+ $filter = '(' . $assign . ')&(' . $ignore . ')';
+ }
+ }
+
+ $object->assign_filter = $filter;
+
+ return $object;
+ }
+
+ protected static function throwCompatError()
+ {
+ throw new ProgrammingError(
+ 'You ran into an unexpected compatibility issue. Please report'
+ . ' this with details helping us to reproduce this to the'
+ . ' Icinga project'
+ );
+ }
+}
diff --git a/library/Director/Objects/IcingaService.php b/library/Director/Objects/IcingaService.php
index 3f59680b..1c29f010 100644
--- a/library/Director/Objects/IcingaService.php
+++ b/library/Director/Objects/IcingaService.php
@@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Objects;
+use Icinga\Data\Filter\Filter;
use Icinga\Exception\ProgrammingError;
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
@@ -41,6 +42,7 @@ class IcingaService extends IcingaObject
'use_agent' => null,
'apply_for' => null,
'use_var_overrides' => null,
+ 'assign_filter' => null,
);
protected $relations = array(
@@ -193,21 +195,6 @@ class IcingaService extends IcingaObject
return parent::renderObjectHeader();
}
- protected function renderAssignments()
- {
- if (! $this->hasBeenAssignedToHostTemplate()) {
- return parent::renderAssignments();
- }
-
- // TODO: use assignment renderer?
- $filter = sprintf(
- 'assign where %s in host.templates',
- c::renderString($this->host)
- );
-
- return "\n " . $filter . "\n";
- }
-
protected function hasBeenAssignedToHostTemplate()
{
return $this->host_id && $this->getRelatedObject(
@@ -238,18 +225,30 @@ class IcingaService extends IcingaObject
protected function renderCustomExtensions()
{
- // A hand-crafted command endpoint overrides use_agent
+ $output = '';
+
+ if ($this->hasBeenAssignedToHostTemplate()) {
+ // TODO: use assignment renderer?
+ $filter = sprintf(
+ 'assign where %s in host.templates',
+ c::renderString($this->host)
+ );
+
+ $output .= "\n " . $filter . "\n";
+ }
+
+ // A hand-crafted command endpoint overrides use_agent
if ($this->command_endpoint_id !== null) {
- return '';
+ return $output;
}
// In case use_agent isn't defined, do nothing
// TODO: what if we inherit use_agent and override it with 'n'?
if ($this->use_agent !== 'y') {
- return '';
+ return $output;
}
- return c::renderKeyValue('command_endpoint', 'host_name');
+ return $output . c::renderKeyValue('command_endpoint', 'host_name');
}
/**
diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php
index aaa81d77..8da99839 100644
--- a/library/Director/Web/Form/DirectorObjectForm.php
+++ b/library/Director/Web/Form/DirectorObjectForm.php
@@ -551,9 +551,6 @@ abstract class DirectorObjectForm extends QuickForm
$post = $this->getRequest()->getPost();
// ?? $this->populate($post);
- if (array_key_exists('assignlist', $post)) {
- $object->assignments()->setFormValues($post['assignlist']);
- }
foreach ($post as $key => $value) {
$el = $this->getElement($key);
@@ -564,10 +561,6 @@ abstract class DirectorObjectForm extends QuickForm
}
if ($object instanceof IcingaObject) {
- if ($object->supportsAssignments()) {
- $this->setElementValue('assignlist', $object->assignments()->getFormValues());
- }
-
$this->handleProperties($object, $values);
$this->handleCustomVars($object, $post);
$this->handleRanges($object, $values);
@@ -1136,6 +1129,71 @@ abstract class DirectorObjectForm extends QuickForm
return $this;
}
+ /**
+ * Add an assign_filter form element
+ *
+ * Forms should use this helper method for objects using the typical
+ * assign_filter column
+ *
+ * @param array $properties Form element properties
+ *
+ * @return self
+ */
+ protected function addAssignFilter($properties)
+ {
+ if (!$this->object || !$this->object->supportsAssignments()) {
+ return $this;
+ }
+
+ $this->addFilterElement('assign_filter', $properties);
+ $el = $this->getElement('assign_filter');
+
+ $this->addDisplayGroup(array($el), 'assign', array(
+ 'decorators' => array(
+ 'FormElements',
+ array('HtmlTag', array('tag' => 'dl')),
+ 'Fieldset',
+ ),
+ 'order' => 30,
+ 'legend' => $this->translate('Assign where')
+ ));
+
+ return $this;
+ }
+
+ /**
+ * Add a dataFilter element with fitting decorators
+ *
+ * TODO: Evaluate whether parts or all of this could be moved to the element
+ * class.
+ *
+ * @param string $name Element name
+ * @param array $properties Form element properties
+ *
+ * @return self
+ */
+ protected function addFilterElement($name, $properties)
+ {
+ $this->addElement('dataFilter', $name, $properties);
+ $el = $this->getElement($name);
+
+ $ddClass = 'full-width';
+ if (array_key_exists('required', $properties) && $properties['required']) {
+ $ddClass .= ' required';
+ }
+
+ $el->clearDecorators()
+ ->addDecorator('ViewHelper')
+ ->addDecorator('Errors')
+ ->addDecorator('Description', array('tag' => 'p', 'class' => 'description'))
+ ->addDecorator('HtmlTag', array(
+ 'tag' => 'dd',
+ 'class' => $ddClass,
+ ));
+
+ return $this;
+ }
+
protected function addEventFilterElements()
{
$this->addElement('extensibleSet', 'states', array(
diff --git a/library/Director/Web/Form/Element/DataFilter.php b/library/Director/Web/Form/Element/DataFilter.php
new file mode 100644
index 00000000..3b46cf9c
--- /dev/null
+++ b/library/Director/Web/Form/Element/DataFilter.php
@@ -0,0 +1,330 @@
+isEmpty($value)) {
+ $value = null;
+ }
+
+ return $value;
+ }
+
+ protected function isEmpty(Filter $filter)
+ {
+ return $filter->isEmpty() || $this->isEmptyExpression($filter);
+ }
+
+ protected function isEmptyExpression($filter)
+ {
+ return $filter->isExpression() &&
+ $filter->getColumn() === '' &&
+ $filter->getExpression() === '""'; // -> json_encode('')
+ }
+
+ /**
+ * @codingStandardsIgnoreStart
+ */
+ protected function _filterValue(&$value, &$key)
+ {
+ // @codingStandardsIgnoreEnd
+ try {
+ if ($value instanceof Filter) {
+ // OK
+ } elseif (is_string($value)) {
+ $value = Filter::fromQueryString($value);
+ } else {
+ $value = $this->arrayToFilter($value);
+ }
+
+ } catch (Exception $e) {
+ $value = null;
+ // TODO: getFile, getLine
+ // Hint: cannot addMessage at it would loop through getValue
+ $this->addErrorMessage($e->getMessage());
+ $this->_isErrorForced = true;
+ }
+ }
+
+ /**
+ * This method transforms filter form data into a filter
+ * and reacts on pressed buttons
+ */
+ protected function arrayToFilter($array)
+ {
+ if ($array === null) {
+ return null;
+ return Filter::matchAll();
+ }
+
+ $this->filter = null;
+ foreach ($array as $id => $entry) {
+ $filterId = $this->idToFilterId($id);
+ $sub = $this->entryToFilter($entry);
+ $this->checkEntryForActions($filterId, $entry);
+ $parentId = $this->parentIdFor($filterId);
+
+ if ($this->filter === null) {
+ $this->filter = $sub;
+ } else {
+ $this->filter->getById($parentId)->addFilter($sub);
+ }
+ }
+
+ $this->removeFilterIfRequested()
+ ->stripFilterIfRequested()
+ ->addNewFilterIfRequested()
+ ->fixNotsWithMultipleChildren();
+
+ return $this->filter;
+ }
+
+ protected function removeFilterIfRequested()
+ {
+ if ($this->removeFilter !== null) {
+ if ($this->filter->getById($this->removeFilter)->isRootNode()) {
+ $this->filter = $this->emptyExpression();
+ } else {
+ $this->filter->removeId($this->removeFilter);
+ }
+ }
+
+ return $this;
+ }
+
+
+ protected function stripFilterIfRequested()
+ {
+ if ($this->stripFilter !== null) {
+ $strip = $this->stripFilter;
+ $subId = $strip . '-1';
+ if ($this->filter->getId() === $strip) {
+ $this->filter = $this->filter->getById($strip . '-1');
+ } else {
+ $this->filter->replaceById($strip, $this->filter->getById($strip . '-1'));
+ }
+ }
+
+ return $this;
+ }
+
+ protected function addNewFilterIfRequested()
+ {
+ if ($this->addTo !== null) {
+ $parent = $this->filter->getById($this->addTo);
+
+ if ($parent->isChain()) {
+ if ($parent->isEmpty()) {
+ $parent->addFilter($this->emptyExpression());
+ } else {
+ $parent->addFilter($this->emptyExpression());
+ }
+ } else {
+ $replacement = Filter::matchAll(clone($parent));
+ if ($parent->isRootNode()) {
+ $this->filter = $replacement;
+ } else {
+ $this->filter->replaceById($parent->getId(), $replacement);
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ protected function fixNotsWithMultipleChildren(Filter $filter = null)
+ {
+ $this->filter = $this->fixNotsWithMultipleChildrenForFilter($this->filter);
+ return $this;
+ }
+
+ protected function fixNotsWithMultipleChildrenForFilter(Filter $filter)
+ {
+ if ($filter->isChain()) {
+ if ($filter->getOperatorName() === 'NOT') {
+ if ($filter->count() > 1) {
+ $filter = $this->notToNotAnd($filter);
+ }
+ }
+ foreach ($filter->filters() as $sub) {
+ $filter->replaceById(
+ $sub->getId(),
+ $this->fixNotsWithMultipleChildrenForFilter($sub)
+ );
+ }
+ }
+
+ return $filter;
+ }
+
+ protected function notToNotAnd(Filter $not)
+ {
+ $and = Filter::matchAll();
+ foreach ($not->filters() as $sub) {
+ $and->addFilter(clone($sub));
+ }
+
+ return Filter::not($and);
+ }
+
+ protected function emptyExpression()
+ {
+ return Filter::expression('', '=', '');
+ }
+
+ protected function parentIdFor($id)
+ {
+ if (false === ($pos = strrpos($id, '-'))) {
+ return '0';
+ } else {
+ return substr($id, 0, $pos);
+ }
+ }
+
+ protected function idToFilterId($id)
+ {
+ if (! preg_match('/^id_(new_)?(\d+(?:-\d+)*)$/', $id, $m)) {
+ die('nono' . $id);
+ }
+
+ return $m[2];
+ }
+
+ protected function checkEntryForActions($filterId, $entry)
+ {
+ switch ($this->entryAction($entry)) {
+ case 'cancel':
+ $this->removeFilter = $filterId;
+ break;
+
+ case 'minus':
+ $this->stripFilter = $filterId;
+ break;
+
+ case 'plus':
+ case 'angle-double-right':
+ $this->addTo = $filterId;
+ break;
+ }
+ }
+
+ /**
+ * Transforms a single submitted form component from an array
+ * into a Filter object
+ *
+ * @param Array $entry The array as submitted through the form
+ *
+ * @return Filter
+ */
+ protected function entryToFilter($entry)
+ {
+ if (array_key_exists('operator', $entry)) {
+ return Filter::chain($entry['operator']);
+ } else {
+ return $this->entryToFilterExpression($entry);
+ }
+ }
+
+ protected function entryToFilterExpression($entry)
+ {
+ if ($entry['sign'] === 'true') {
+ return Filter::expression(
+ $entry['column'],
+ '=',
+ json_encode(true)
+ );
+ } elseif ($entry['sign'] === 'in') {
+ if (array_key_exists('value', $entry)) {
+ if (is_array($entry['value'])) {
+ $value = array_filter($entry['value'], 'strlen');
+ } elseif (empty($entry['value'])) {
+ $value = array();
+ } else {
+ $value = array($entry['value']);
+ }
+ } else {
+ $value = array();
+ }
+ return Filter::expression(
+ $entry['column'],
+ '=',
+ json_encode($value)
+ );
+ } else {
+ $value = array_key_exists('value', $entry) ? $entry['value'] : null;
+
+ return Filter::expression(
+ $entry['column'],
+ $entry['sign'],
+ json_encode($value)
+ );
+ }
+ }
+
+ protected function entryAction($entry)
+ {
+ if (array_key_exists('action', $entry)) {
+ return IconHelper::instance()->characterIconName($entry['action']);
+ }
+
+ return null;
+ }
+
+ protected function hasIncompleteExpressions(Filter $filter)
+ {
+ if ($filter->isChain()) {
+ foreach ($filter->filters() as $sub) {
+ if ($this->hasIncompleteExpressions($sub)) {
+ return true;
+ }
+ }
+ } else {
+ if ($filter->isRootNode() && $this->isEmptyExpression($filter)) {
+ return false;
+ }
+
+ return $filter->getColumn() === '';
+ }
+ }
+
+ public function isValid($value, $context = null)
+ {
+ if (! $value instanceof Filter) {
+ // TODO: try, return false on E
+ $filter = $this->arrayToFilter($value);
+ $this->setValue($filter);
+ }
+
+ if ($this->hasIncompleteExpressions($filter)) {
+ $this->addError('The configured filter is incomplete');
+ return false;
+ }
+
+ return parent::isValid($value);
+ }
+}
diff --git a/library/Director/Web/Form/IconHelper.php b/library/Director/Web/Form/IconHelper.php
index 91259b55..1f7de580 100644
--- a/library/Director/Web/Form/IconHelper.php
+++ b/library/Director/Web/Form/IconHelper.php
@@ -22,11 +22,12 @@ use Icinga\Exception\ProgrammingError;
class IconHelper
{
private $icons = array(
- 'minus' => 'e806',
- 'trash' => 'e846',
- 'plus' => 'e805',
- 'cancel' => 'e804',
- 'help' => 'e85b',
+ 'minus' => 'e806',
+ 'trash' => 'e846',
+ 'plus' => 'e805',
+ 'cancel' => 'e804',
+ 'help' => 'e85b',
+ 'angle-double-right' => 'e87b',
);
private $mappedUtf8Icons;
diff --git a/public/css/module.less b/public/css/module.less
index 4628269c..eb132dc8 100644
--- a/public/css/module.less
+++ b/public/css/module.less
@@ -186,6 +186,7 @@ input, select, select option, textarea {
form ul.form-errors {
margin-bottom: 0.5em;
+
ul.errors li {
background: @color-critical;
font-weight: bold;
@@ -228,6 +229,10 @@ select option {
padding-top: 0.3em;
}
+select[multiple=multiple] {
+ height: auto;
+}
+
label {
line-height: 2em;
}
@@ -620,31 +625,6 @@ form dt label {
}
}
-ul.assign-rule {
- margin: 0;
- padding: 0;
- list-style-type: none;
- select, input[type=text] {
- min-width: auto;
- }
-
- select.assign-type {
- width: 8em;
- }
-
- select.assign-operator {
- width: 3em;
- }
-
- select.assign-property {
- width: 12em;
- }
-
- input.assign-expression {
- width: 12em;
- }
-}
-
form fieldset {
min-width: 36em;
}
@@ -689,6 +669,10 @@ form dt {
}
}
+form .errors label {
+ color: @color-critical;
+}
+
form dd {
display: inline-block;
width: 63%;
@@ -700,6 +684,11 @@ form dd {
border-color: @color-critical;
}
}
+
+ &.full-width {
+ padding: 0.5em;
+ width: 100%;
+ }
}
form dd:after {
@@ -898,25 +887,25 @@ table.icinga-objects {
}
table.assignment-table {
- ul.apply-rules {
+ table.apply-rules {
margin: 1em 0 1em 0;
padding: 0;
- border: 1px solid @gray-lighter;
+ width: 100%;
- li {
- display: block;
+ tr {
+ border-bottom: 1px solid @gray-lighter;
+ border-left: 5px solid transparent;
- a {
- display: block;
- float: none;
- font-weight: normal;
- background-color: white;
- padding: 0.3em 1.5em;
- &:hover {
- background-color: @icinga-blue;
- color: white;
- text-decoration: none;
- }
+ td {
+ padding: 0.5em 1em;
+ }
+
+ &:hover, &:active, &.active {
+ border-left: 5px solid @icinga-blue;
+ }
+
+ &:hover {
+ background: white;
}
}
}
@@ -1101,6 +1090,147 @@ table.config-diff {
}
}
+
+ul.assign-rule {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+ select, input[type=text] {
+ min-width: auto;
+ }
+
+ select.assign-type {
+ width: 8em;
+ }
+
+
+ ul {
+ list-style-type: none;
+ padding-left: 2em;
+
+ li::before {
+ // icon: down-dir
+ font-family: 'ifont';
+ content: '\e81d';
+ // icon: right-small
+ content: '\e877';
+ margin-left: -1em;
+ padding-top: 0em;
+ float: left;
+ color: inherit;
+ }
+ }
+}
+
+ul.filter-root {
+ margin-top: 0;
+ width: 100%;
+ padding-left: 0.5em;
+ list-style-type: none;
+
+ ul {
+ padding-left: 1.5em;
+ list-style-type: none;
+ width: 100%;
+ }
+
+ li.filter-chain, div.filter-expression {
+ width: 100%;
+ padding: 0.3em 0.5em;
+ min-width: 30em;
+ }
+
+ ul li.filter-chain::before, ul .filter-expression::before {
+ font-family: 'ifont';
+ // Formerly: icon-down-open: e821
+ // icon-right-small:
+ content: '\e877';
+ float: left;
+ margin-left: -1.5em;
+ margin-top: 0.5em;
+ }
+
+ ul.extensible-set {
+ padding-left: 0;
+ border: none;
+ display: inline-block;
+ vertical-align: top;
+ li::before {
+ content: none;
+ }
+ }
+
+ input[type=submit].icon-button {
+ display: none;
+ font-family: 'ifont';
+ font-weight: normal;
+ background: none;
+ border: none;
+ padding: 0.2em 0.4em 0.2em 0.4em;
+ margin: 0 0 0 0.2em;
+ }
+
+ .active input[type=submit].icon-button,
+ li:hover input[type=submit].icon-button,
+ div:hover input[type=submit].icon-button
+ {
+ display: inline;
+ }
+}
+
+.errors > ul.filter-root {
+ input[type=text], select {
+ border-color: transparent;
+ border-bottom-color: @gray-lighter;
+ }
+
+ select.column, select.operator {
+ border-left-color: @color-critical;
+ }
+}
+
+
+li.filter-chain > select.operator {
+ min-width: 5em;
+ max-width: 5em;
+ width: 5em;
+}
+
+div.filter-expression {
+ .column {
+ min-width: 7em;
+ max-width: 10em;
+ width: 10em;
+ }
+
+ .sign {
+ min-width: 4em;
+ max-width: 4em;
+ width: 4em;
+ margin: 0 0.3em;
+ &.wide {
+ min-width: 6em;
+ max-width: 6em;
+ width: 6em;
+ }
+ }
+
+ div.expression-wrapper {
+ display: inline-block;
+ }
+
+ div.expression-wrapper > input[type=text],
+ div.expression-wrapper > select {
+ min-width: 7em;
+ width: 10em;
+ max-width: 10em;
+ }
+}
+
+
+
+
+
.tree li a {
display: inline-block;
padding-left: 2.4em;
diff --git a/public/js/module.js b/public/js/module.js
index aaf3c767..0d5d2c21 100644
--- a/public/js/module.js
+++ b/public/js/module.js
@@ -188,7 +188,7 @@
}
var $li = $input.closest('li');
var $dt = $dd.prev();
- var $form = $dt.closest('form');
+ var $form = $dd.closest('form');
$form.find('dt, dd, li').removeClass('active');
$li.addClass('active');
diff --git a/schema/mysql-migrations/upgrade_120.sql b/schema/mysql-migrations/upgrade_120.sql
new file mode 100644
index 00000000..7fca2816
--- /dev/null
+++ b/schema/mysql-migrations/upgrade_120.sql
@@ -0,0 +1,184 @@
+ALTER TABLE icinga_service ADD COLUMN assign_filter TEXT;
+
+UPDATE icinga_service s JOIN (
+
+ SELECT
+ service_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa.filter_string
+ ELSE GROUP_CONCAT(sa.filter_string SEPARATOR '&') END AS filter_string
+ FROM (
+ SELECT
+ sa_not.service_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa_not.filter_string
+ ELSE '(' || GROUP_CONCAT(sa_not.filter_string SEPARATOR '&') || ')' END AS filter_string
+ FROM ( SELECT
+ sa.service_id,
+ '!' || sa.filter_string AS filter_string
+ FROM icinga_service_assignment sa
+ WHERE assign_type = 'ignore'
+ ) sa_not
+ GROUP BY service_id
+
+ UNION ALL
+
+ SELECT
+ sa_yes.service_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa_yes.filter_string
+ ELSE '(' || GROUP_CONCAT(sa_yes.filter_string SEPARATOR '|') || ')' END AS filter_string
+ FROM ( SELECT
+ sa.service_id,
+ sa.filter_string AS filter_string
+ FROM icinga_service_assignment sa
+ WHERE assign_type = 'assign'
+ ) sa_yes
+ GROUP BY service_id
+
+ ) sa GROUP BY service_id
+
+) flat_assign ON s.id = flat_assign.service_id SET s.assign_filter = flat_assign.filter_string;
+
+DROP TABLE icinga_service_assignment;
+
+ALTER TABLE icinga_service_set ADD COLUMN assign_filter TEXT;
+
+UPDATE icinga_service_set s JOIN (
+
+ SELECT
+ service_set_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa.filter_string
+ ELSE GROUP_CONCAT(sa.filter_string SEPARATOR '&') END AS filter_string
+ FROM (
+ SELECT
+ sa_not.service_set_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa_not.filter_string
+ ELSE '(' || GROUP_CONCAT(sa_not.filter_string SEPARATOR '&') || ')' END AS filter_string
+ FROM ( SELECT
+ sa.service_set_id,
+ '!' || sa.filter_string AS filter_string
+ FROM icinga_service_set_assignment sa
+ WHERE assign_type = 'ignore'
+ ) sa_not
+ GROUP BY service_set_id
+
+ UNION ALL
+
+ SELECT
+ sa_yes.service_set_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa_yes.filter_string
+ ELSE '(' || GROUP_CONCAT(sa_yes.filter_string SEPARATOR '|') || ')' END AS filter_string
+ FROM ( SELECT
+ sa.service_set_id,
+ sa.filter_string AS filter_string
+ FROM icinga_service_set_assignment sa
+ WHERE assign_type = 'assign'
+ ) sa_yes
+ GROUP BY service_set_id
+
+ ) sa GROUP BY service_set_id
+
+) flat_assign ON s.id = flat_assign.service_set_id SET s.assign_filter = flat_assign.filter_string;
+
+DROP TABLE icinga_service_set_assignment;
+
+
+ALTER TABLE icinga_notification ADD COLUMN assign_filter TEXT;
+
+UPDATE icinga_notification s JOIN (
+
+ SELECT
+ notification_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa.filter_string
+ ELSE GROUP_CONCAT(sa.filter_string SEPARATOR '&') END AS filter_string
+ FROM (
+ SELECT
+ sa_not.notification_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa_not.filter_string
+ ELSE '(' || GROUP_CONCAT(sa_not.filter_string SEPARATOR '&') || ')' END AS filter_string
+ FROM ( SELECT
+ sa.notification_id,
+ '!' || sa.filter_string AS filter_string
+ FROM icinga_notification_assignment sa
+ WHERE assign_type = 'ignore'
+ ) sa_not
+ GROUP BY notification_id
+
+ UNION ALL
+
+ SELECT
+ sa_yes.notification_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa_yes.filter_string
+ ELSE '(' || GROUP_CONCAT(sa_yes.filter_string SEPARATOR '|') || ')' END AS filter_string
+ FROM ( SELECT
+ sa.notification_id,
+ sa.filter_string AS filter_string
+ FROM icinga_notification_assignment sa
+ WHERE assign_type = 'assign'
+ ) sa_yes
+ GROUP BY notification_id
+
+ ) sa GROUP BY notification_id
+
+) flat_assign ON s.id = flat_assign.notification_id SET s.assign_filter = flat_assign.filter_string;
+
+DROP TABLE icinga_notification_assignment;
+
+ALTER TABLE icinga_hostgroup ADD COLUMN assign_filter TEXT;
+
+UPDATE icinga_hostgroup s JOIN (
+
+ SELECT
+ hostgroup_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa.filter_string
+ ELSE GROUP_CONCAT(sa.filter_string SEPARATOR '&') END AS filter_string
+ FROM (
+ SELECT
+ sa_not.hostgroup_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa_not.filter_string
+ ELSE '(' || GROUP_CONCAT(sa_not.filter_string SEPARATOR '&') || ')' END AS filter_string
+ FROM ( SELECT
+ sa.hostgroup_id,
+ '!' || sa.filter_string AS filter_string
+ FROM icinga_hostgroup_assignment sa
+ WHERE assign_type = 'ignore'
+ ) sa_not
+ GROUP BY hostgroup_id
+
+ UNION ALL
+
+ SELECT
+ sa_yes.hostgroup_id,
+ CASE WHEN COUNT(*) = 0 THEN NULL
+ WHEN COUNT(*) = 1 THEN sa_yes.filter_string
+ ELSE '(' || GROUP_CONCAT(sa_yes.filter_string SEPARATOR '|') || ')' END AS filter_string
+ FROM ( SELECT
+ sa.hostgroup_id,
+ sa.filter_string AS filter_string
+ FROM icinga_hostgroup_assignment sa
+ WHERE assign_type = 'assign'
+ ) sa_yes
+ GROUP BY hostgroup_id
+
+ ) sa GROUP BY hostgroup_id
+
+) flat_assign ON s.id = flat_assign.hostgroup_id SET s.assign_filter = flat_assign.filter_string;
+
+DROP TABLE icinga_hostgroup_assignment;
+
+
+ALTER TABLE icinga_servicegroup ADD COLUMN assign_filter TEXT;
+
+
+INSERT INTO director_schema_migration
+ (schema_version, migration_time)
+ VALUES (120, NOW());
diff --git a/test/php/library/Director/Objects/IcingaServiceTest.php b/test/php/library/Director/Objects/IcingaServiceTest.php
index bfc8101c..e66778b9 100644
--- a/test/php/library/Director/Objects/IcingaServiceTest.php
+++ b/test/php/library/Director/Objects/IcingaServiceTest.php
@@ -47,9 +47,7 @@ class IcingaServiceTest extends BaseTestCase
{
$service = $this->service();
$service->object_type = 'apply';
- $service->assignments = array(
- 'host.address="127.*"'
- );
+ $service->assign_filter = 'host.address="127.*"';
}
/**
@@ -58,9 +56,7 @@ class IcingaServiceTest extends BaseTestCase
public function testRefusesAssignRulesWhenNotBeingAnApply()
{
$service = $this->service();
- $service->assignments = array(
- 'host.address=127.*'
- );
+ $service->assign_filter = 'host.address=127.*';
}
public function testAcceptsAndRendersFlatAssignRules()
@@ -76,10 +72,7 @@ class IcingaServiceTest extends BaseTestCase
// Service apply rule rendering requires access to settings:
$service->setConnection($db);
$service->object_type = 'apply';
- $service->assignments = array(
- 'host.address="127.*"',
- 'host.vars.env="test"'
- );
+ $service->assign_filter = 'host.address="127.*"|host.vars.env="test"';
$this->assertEquals(
$this->loadRendered('service1'),
@@ -87,8 +80,8 @@ class IcingaServiceTest extends BaseTestCase
);
$this->assertEquals(
- 'host.address="127.*"',
- $service->toPlainObject()->assignments['assign'][0]
+ 'host.address="127.*"|host.vars.env="test"',
+ $service->assign_filter
);
}
@@ -104,10 +97,7 @@ class IcingaServiceTest extends BaseTestCase
// Service apply rule rendering requires access to settings:
$service->setConnection($db);
$service->object_type = 'apply';
- $service->assignments = array(
- 'host.address="127.*"',
- 'host.vars.env="test"'
- );
+ $service->assign_filter = 'host.address="127.*"|host.vars.env="test"';
$this->assertEquals(
$this->loadRendered('service1'),
@@ -115,8 +105,8 @@ class IcingaServiceTest extends BaseTestCase
);
$this->assertEquals(
- 'host.address="127.*"',
- $service->toPlainObject()->assignments['assign'][0]
+ 'host.address="127.*"|host.vars.env="test"',
+ $service->assign_filter = 'host.address="127.*"|host.vars.env="test"'
);
}
@@ -130,10 +120,7 @@ class IcingaServiceTest extends BaseTestCase
$service = $this->service();
$service->object_type = 'apply';
- $service->assignments = array(
- 'host.address="127.*"',
- 'host.vars.env="test"'
- );
+ $service->assign_filter = 'host.address="127.*"|host.vars.env="test"';
$service->store($db);
@@ -144,74 +131,8 @@ class IcingaServiceTest extends BaseTestCase
);
$this->assertEquals(
- 'host.address="127.*"',
- $service->toPlainObject()->assignments['assign'][0]
- );
-
- $service->delete();
- }
-
- public function testStaysUnmodifiedWhenSameFiltersAreSetInDifferentWays()
- {
- if ($this->skipForMissingDb()) {
- return;
- }
-
- $db = $this->getDb();
-
- $service = $this->service();
- $service->object_type = 'apply';
- $service->assignments = 'host.address="127.*"';
- $service->store($db);
- $this->assertFalse($service->hasBeenModified());
-
- $service->assignments = array(
- 'host.address="127.*"',
- );
- $this->assertFalse($service->hasBeenModified());
-
- $service->assignments = 'host.address="128.*"';
- $this->assertTrue($service->hasBeenModified());
-
- $service->store();
- $this->assertFalse($service->hasBeenModified());
-
- $service->assignments = array('assign' => 'host.address="128.*"');
- $this->assertFalse($service->hasBeenModified());
-
- $service->assignments = array(
- 'assign' => array(
- 'host.address="128.*"'
- )
- );
-
- $this->assertFalse($service->hasBeenModified());
-
- $service->assignments = array(
- 'assign' => array(
- 'host.address="128.*"'
- ),
- 'ignore' => 'host.name="localhost"'
- );
-
- $this->assertTrue($service->hasBeenModified());
-
- $service->store();
- $service = IcingaService::loadWithAutoIncId($service->id, $db);
-
- $this->assertEquals(
- 'host.address="128.*"',
- $service->toPlainObject()->assignments['assign'][0]
- );
-
- $this->assertEquals(
- 'host.name="localhost"',
- $service->toPlainObject()->assignments['ignore'][0]
- );
-
- $this->assertEquals(
- $this->loadRendered('service2'),
- (string) $service
+ 'host.address="127.*"|host.vars.env="test"',
+ $service->assign_filter
);
$service->delete();
@@ -247,9 +168,7 @@ class IcingaServiceTest extends BaseTestCase
$service->setConnection($db);
$service->object_type = 'apply';
$service->display_name = 'Service: $host.vars.replaced$';
- $service->assignments = array(
- 'host.address="127.*"',
- );
+ $service->assign_filter = 'host.address="127.*"';
$service->{'vars.custom_var'} = '$host.vars.replaced$';
$this->assertEquals(
@@ -290,9 +209,7 @@ class IcingaServiceTest extends BaseTestCase
$service = $this->service()->setConnection($db);
$service->object_type = 'apply';
$service->apply_for = 'host.vars.test1';
- $service->assignments = array(
- 'host.vars.env="test"'
- );
+ $service->assign_filter = 'host.vars.env="test"';
$this->assertEquals(
$this->loadRendered('service5'),
(string) $service
diff --git a/test/php/library/Director/Objects/rendered/service1.out b/test/php/library/Director/Objects/rendered/service1.out
index e3a46c6b..ba65b081 100644
--- a/test/php/library/Director/Objects/rendered/service1.out
+++ b/test/php/library/Director/Objects/rendered/service1.out
@@ -1,5 +1,6 @@
apply Service "___TEST___service" {
display_name = "Whatever service"
+ assign where match("127.*", host.address) || host.vars.env == "test"
vars.test1 = "string"
vars.test2 = 17
vars.test3 = false
@@ -8,9 +9,6 @@ apply Service "___TEST___service" {
@this = "is"
}
- assign where match("127.*", host.address)
- assign where host.vars.env == "test"
-
import DirectorOverrideTemplate
}
diff --git a/test/php/library/Director/Objects/rendered/service3.out b/test/php/library/Director/Objects/rendered/service3.out
index ad39128a..b69a935b 100644
--- a/test/php/library/Director/Objects/rendered/service3.out
+++ b/test/php/library/Director/Objects/rendered/service3.out
@@ -1,5 +1,6 @@
apply Service "___TEST___service_$not_replaced$" {
display_name = "Service: " + host.vars.replaced
+ assign where match("127.*", host.address)
vars.custom_var = host.vars.replaced
vars.test1 = "string"
vars.test2 = 17
@@ -9,8 +10,6 @@ apply Service "___TEST___service_$not_replaced$" {
@this = "is"
}
- assign where match("127.*", host.address)
-
import DirectorOverrideTemplate
}
diff --git a/test/php/library/Director/Objects/rendered/service5.out b/test/php/library/Director/Objects/rendered/service5.out
index d1b0573b..b05e6301 100644
--- a/test/php/library/Director/Objects/rendered/service5.out
+++ b/test/php/library/Director/Objects/rendered/service5.out
@@ -1,5 +1,6 @@
apply Service "___TEST___service" for (config in host.vars.test1) {
display_name = "Whatever service"
+ assign where host.vars.env == "test"
vars.test1 = "string"
vars.test2 = 17
vars.test3 = false
@@ -8,8 +9,6 @@ apply Service "___TEST___service" for (config in host.vars.test1) {
@this = "is"
}
- assign where host.vars.env == "test"
-
import DirectorOverrideTemplate
}
diff --git a/test/php/library/Director/Objects/rendered/service6.out b/test/php/library/Director/Objects/rendered/service6.out
index d41bd852..fdca11c4 100644
--- a/test/php/library/Director/Objects/rendered/service6.out
+++ b/test/php/library/Director/Objects/rendered/service6.out
@@ -1,6 +1,7 @@
apply Service for (config in host.vars.test1) {
name = "___TEST" + config + "___service " + host.var.bla
display_name = "Whatever service"
+ assign where host.vars.env == "test"
vars.test1 = "string"
vars.test2 = 17
vars.test3 = false
@@ -9,8 +10,6 @@ apply Service for (config in host.vars.test1) {
@this = "is"
}
- assign where host.vars.env == "test"
-
import DirectorOverrideTemplate
}
diff --git a/test/php/library/Director/Objects/rendered/service7.out b/test/php/library/Director/Objects/rendered/service7.out
index 96c3e498..c125ccce 100644
--- a/test/php/library/Director/Objects/rendered/service7.out
+++ b/test/php/library/Director/Objects/rendered/service7.out
@@ -1,5 +1,6 @@
apply Service for (config in host.vars.test1) {
display_name = "Whatever service"
+ assign where host.vars.env == "test"
vars.test1 = "string"
vars.test2 = 17
vars.test3 = false
@@ -8,8 +9,6 @@ apply Service for (config in host.vars.test1) {
@this = "is"
}
- assign where host.vars.env == "test"
-
import DirectorOverrideTemplate
}