From 6a45d9507dbcee6d1748665ede2c4d5915d44856 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 13 Oct 2016 08:59:50 +0000 Subject: [PATCH 01/18] IcingaServiceSet: remove legacy resolving methods They have been used once we had no imports --- library/Director/Objects/IcingaServiceSet.php | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/library/Director/Objects/IcingaServiceSet.php b/library/Director/Objects/IcingaServiceSet.php index 4e40741f..1aa86214 100644 --- a/library/Director/Objects/IcingaServiceSet.php +++ b/library/Director/Objects/IcingaServiceSet.php @@ -146,26 +146,6 @@ class IcingaServiceSet extends IcingaObject } } - protected function resolve($what) - { - return array(); - } - - protected function getResolved($what) - { - return array(); - } - - protected function getInherited($what) - { - return array(); - } - - protected function getOrigins($what) - { - return array(); - } - public function getRenderingZone(IcingaConfig $config = null) { return $this->connection->getDefaultGlobalZoneName(); From 696e63b4eccc4cd6fb291c383f69e17b1afe602a Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 13 Oct 2016 09:13:21 +0000 Subject: [PATCH 02/18] Servicesset: add controller, form and table --- .../controllers/ServicesetController.php | 42 +++++++++++ application/forms/IcingaServiceSetForm.php | 71 +++++++++++++++++++ application/tables/IcingaServiceSetTable.php | 62 ++++++++++++++++ library/Director/Objects/IcingaObject.php | 2 + .../Web/Controller/ObjectController.php | 7 +- .../Web/Controller/ObjectsController.php | 28 ++++++++ 6 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 application/controllers/ServicesetController.php create mode 100644 application/forms/IcingaServiceSetForm.php create mode 100644 application/tables/IcingaServiceSetTable.php diff --git a/application/controllers/ServicesetController.php b/application/controllers/ServicesetController.php new file mode 100644 index 00000000..2f230f1a --- /dev/null +++ b/application/controllers/ServicesetController.php @@ -0,0 +1,42 @@ +params->get('host')) { + $this->host = IcingaHost::load($host, $this->db()); + } + + parent::init(); + } + + protected function loadObject() + { + if ($this->object === null) { + if ($name = $this->params->get('name')) { + $params = array('object_name' => $name); + $db = $this->db(); + + if ($this->host) { + $this->view->host = $this->host; + $params['host_id'] = $this->host->id; + } + + $this->object = IcingaServiceSet::load($params, $db); + } else { + parent::loadObject(); + } + } + + return $this->object; + } +} diff --git a/application/forms/IcingaServiceSetForm.php b/application/forms/IcingaServiceSetForm.php new file mode 100644 index 00000000..a843de19 --- /dev/null +++ b/application/forms/IcingaServiceSetForm.php @@ -0,0 +1,71 @@ +addImportsElement(); + + $this->addElement('text', 'object_name', array( + 'label' => $this->translate('Service set name'), + 'description' => $this->translate( + 'A short name identifying this set of ser' + ), + 'required' => true, + )); + + $this->addElement('textarea', 'description', array( + 'label' => $this->translate('Description'), + 'description' => $this->translate( + 'A meaningful description explaining your users what to expect' + . ' when assigning this set of services' + ), + 'rows' => '3', + 'required' => ! $this->isTemplate(), + )); + + + if ($this->host === null) { + $this->addHidden('object_type', 'object'); + + $this->addElement('multiselect', 'service', array( + 'label' => $this->translate('Services'), + 'description' => $this->translate( + 'Services in this set' + ), + 'rows' => '5', + 'multiOptions' => $this->enumServices(), + 'required' => true, + )); + } else { + $this->addHidden('object_type', 'object'); + $this->addHidden('host_id', $this->host->id); + } + + $this->setButtons(); + } + + public function setHost(IcingaHost $host) + { + $this->host = $host; + return $this; + } + + protected function enumServices() + { + $db = $this->db->getDbAdapter(); + $query = $db->select() + ->from('icinga_service', 'object_name') + ->where('object_type = ?', 'template'); + $names = $db->fetchCol($query); + + return array_combine($names, $names); + } +} diff --git a/application/tables/IcingaServiceSetTable.php b/application/tables/IcingaServiceSetTable.php new file mode 100644 index 00000000..bd612d56 --- /dev/null +++ b/application/tables/IcingaServiceSetTable.php @@ -0,0 +1,62 @@ + 'sset.id', + 'name' => 'sset.object_name', + 'object_type' => 'sset.object_type', + 'description' => 'sset.description', + 'host_name' => 'h.object_name', + ); + } + + public function getTitles() + { + $view = $this->view(); + return array( + 'name' => $view->translate('Service set'), + ); + } + + protected function getActionUrl($row) + { + // TODO: Remove once we got a separate apply table + if ($row->object_type === 'apply') { + $params['id'] = $row->id; + } else { + $params = array('name' => $row->name); + if ($row->host_name) { + $params['host'] = $row->host_name; + } + } + + return $this->url('director/serviceset', $params); + } + + protected function getUnfilteredQuery() + { + $db = $this->connection()->getConnection(); + $query = $db->select()->from( + array('sset' => 'icinga_service_set'), + array() + )->joinLeft( + array('h' => 'icinga_host'), + 'h.id = sset.host_id', + array() + )->order('sset.object_name'); + + return $query; + } + + public function getBaseQuery() + { + return $this->getUnfilteredQuery(); + } +} diff --git a/library/Director/Objects/IcingaObject.php b/library/Director/Objects/IcingaObject.php index 438eceb7..ff4d0628 100644 --- a/library/Director/Objects/IcingaObject.php +++ b/library/Director/Objects/IcingaObject.php @@ -2071,6 +2071,8 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer $type = 'timePeriod'; } elseif ($type === 'servicegroup') { $type = 'serviceGroup'; + } elseif ($type === 'service_set') { + $type = 'serviceSet'; } elseif ($type === 'apiuser') { $type = 'apiUser'; } diff --git a/library/Director/Web/Controller/ObjectController.php b/library/Director/Web/Controller/ObjectController.php index e97bdda5..ff157a32 100644 --- a/library/Director/Web/Controller/ObjectController.php +++ b/library/Director/Web/Controller/ObjectController.php @@ -26,7 +26,7 @@ abstract class ObjectController extends ActionController { parent::init(); - $type = $this->getType(); + $type = strtolower($this->getType()); if ($object = $this->loadObject()) { $this->beforeTabs(); @@ -61,7 +61,6 @@ abstract class ObjectController extends ActionController 'label' => $this->translate('Fields') )); } - } else { $this->beforeTabs(); $this->getTabs()->add('add', array( @@ -301,8 +300,8 @@ abstract class ObjectController extends ActionController { // Strip final 's' and upcase an eventual 'group' return preg_replace( - array('/group$/', '/period$/', '/argument$/', '/apiuser$/'), - array('Group', 'Period', 'Argument', 'ApiUser'), + array('/group$/', '/period$/', '/argument$/', '/apiuser$/', '/set$/'), + array('Group', 'Period', 'Argument', 'ApiUser', 'Set'), $this->getRequest()->getControllerName() ); } diff --git a/library/Director/Web/Controller/ObjectsController.php b/library/Director/Web/Controller/ObjectsController.php index 79fbac09..6020c288 100644 --- a/library/Director/Web/Controller/ObjectsController.php +++ b/library/Director/Web/Controller/ObjectsController.php @@ -67,6 +67,13 @@ abstract class ObjectsController extends ActionController )); } + if ($object->supportsSets() || $object->isGroup() /** Bullshit, need base object, wrong on users */) { + $tabs->add('sets', array( + 'url' => sprintf('director/%ss/sets', $type), + 'label' => $this->translate('Sets') + )); + } + $tabs->add('tree', array( 'url' => sprintf('director/%ss/templatetree', $type), 'label' => $this->translate('Tree'), @@ -246,6 +253,27 @@ abstract class ObjectsController extends ActionController $this->setViewScript('objects/tree'); } + public function setsAction() + { + $this->view->title = $this->translate('Service sets'); + $this->view->table = $this + ->loadTable('IcingaServiceSet') + ->setConnection($this->db()); + + $this->view->addLink = $this->view->qlink( + $this->translate('Add'), + 'director/serviceset/add', + null, + array( + 'class' => 'icon-plus', + 'data-base-target' => '_next' + ) + ); + + $this->getTabs()->activate('sets'); + $this->setViewScript('objects/table'); + } + protected function dummyObject() { if ($this->dummy === null) { From 6bb74966d51179f1c5aae86629f933b5e81c8cf4 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 13 Oct 2016 14:04:53 +0000 Subject: [PATCH 03/18] CustomVariables: add _set table to delete/countAll --- library/Director/CustomVariable/CustomVariables.php | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Director/CustomVariable/CustomVariables.php b/library/Director/CustomVariable/CustomVariables.php index 3bec8924..17317a05 100644 --- a/library/Director/CustomVariable/CustomVariables.php +++ b/library/Director/CustomVariable/CustomVariables.php @@ -25,6 +25,7 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer 'icinga_command_var', 'icinga_host_var', 'icinga_notification_var', + 'icinga_service_set_var', 'icinga_service_var', 'icinga_user_var', ); From 09e9b7aa10c5b75175083edcc3f57b5e3267e2a7 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 01:52:59 +0000 Subject: [PATCH 04/18] css: auto-height for multiselect elements --- public/css/module.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/css/module.less b/public/css/module.less index eb132dc8..6c81c6aa 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -224,6 +224,10 @@ input[type=text], input[type=password], textarea, select { } } +select[multiple] { + height: auto; +} + select option { height: 2em; padding-top: 0.3em; From 00f21f838bd3b7905f0f21153a76525fc5046a11 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 02:11:13 +0000 Subject: [PATCH 05/18] DirectorObjectForm: simplify inhertance code --- .../Director/Web/Form/DirectorObjectForm.php | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php index 8da99839..329127c4 100644 --- a/library/Director/Web/Form/DirectorObjectForm.php +++ b/library/Director/Web/Form/DirectorObjectForm.php @@ -236,23 +236,20 @@ abstract class DirectorObjectForm extends QuickForm $this->setDefaults($props); - if (! $object instanceof IcingaObject) { - return $this; - } - if ($resolve) { - $inherited = $object->getInheritedProperties(); - $origins = $object->getOriginsProperties(); - } else { - $inherited = (object) array(); - $origins = (object) array(); + $this->showInheritedProperties($object); } + } - foreach ($props as $k => $v) { - $this->setElementValue($k, $v); - if ($k !== 'object_name' && property_exists($inherited, $k)) { + protected function showInheritedProperties($object) + { + $inherited = $object->getInheritedProperties(); + $origins = $object->getOriginsProperties(); + + foreach ($inherited as $k => $v) { + if ($v !== null && $k !== 'object_name') { $el = $this->getElement($k); - if ($el && $resolve) { + if ($el) { $this->setInheritedValue($el, $inherited->$k, $origins->$k); } } From 0db659cc4e04a816ad353983f9e1f4c8baaece14 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 02:50:55 +0000 Subject: [PATCH 06/18] IcingaObjectFieldLoader: check for fields support --- library/Director/Web/Form/IcingaObjectFieldLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Director/Web/Form/IcingaObjectFieldLoader.php b/library/Director/Web/Form/IcingaObjectFieldLoader.php index eaad9a70..1f9e69da 100644 --- a/library/Director/Web/Form/IcingaObjectFieldLoader.php +++ b/library/Director/Web/Form/IcingaObjectFieldLoader.php @@ -25,7 +25,7 @@ class IcingaObjectFieldLoader public function addFieldsToForm(QuickForm $form) { - if ($this->object->supportsCustomVars()) { + if ($this->object->supportsFields()) { $this->attachFieldsToForm($form); } From bed122d9063c60949b80aa9cba1551e7c8b4fe6f Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 02:56:19 +0000 Subject: [PATCH 07/18] IcingaServiceSetForm: complete description --- application/forms/IcingaServiceSetForm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/forms/IcingaServiceSetForm.php b/application/forms/IcingaServiceSetForm.php index a843de19..a3cbc8cd 100644 --- a/application/forms/IcingaServiceSetForm.php +++ b/application/forms/IcingaServiceSetForm.php @@ -16,7 +16,7 @@ class IcingaServiceSetForm extends DirectorObjectForm $this->addElement('text', 'object_name', array( 'label' => $this->translate('Service set name'), 'description' => $this->translate( - 'A short name identifying this set of ser' + 'A short name identifying this set of services' ), 'required' => true, )); From f87e80989dc9f43c68058ab9c58028495b1dec98 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 04:26:37 +0000 Subject: [PATCH 08/18] DirectorObjectForm: persist the field loader --- library/Director/Web/Form/DirectorObjectForm.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php index 329127c4..ae66161a 100644 --- a/library/Director/Web/Form/DirectorObjectForm.php +++ b/library/Director/Web/Form/DirectorObjectForm.php @@ -33,6 +33,8 @@ abstract class DirectorObjectForm extends QuickForm protected $preferredObjectType; + protected $fieldLoader; + private $allowsExperimental; private $api; @@ -259,12 +261,23 @@ abstract class DirectorObjectForm extends QuickForm protected function handleCustomVars($object, & $values) { if ($this->assertResolvedImports()) { - $loader = new IcingaObjectFieldLoader($object); + $loader = $this->fieldLoader($object); $loader->addFieldsToForm($this); if ($values) { $loader->setValues($values, 'var_'); } } + + return $this; + } + + protected function fieldLoader($object) + { + if ($this->fieldLoader === null) { + $this->fieldLoader = new IcingaObjectFieldLoader($object); + } + + return $this->fieldLoader; } protected function isNew() From c41009992ed94a146dadda91ad113828c0b455e9 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 04:27:43 +0000 Subject: [PATCH 09/18] IcingaObjectFieldLoader: allow to combine objects --- .../Web/Form/IcingaObjectFieldLoader.php | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/library/Director/Web/Form/IcingaObjectFieldLoader.php b/library/Director/Web/Form/IcingaObjectFieldLoader.php index 1f9e69da..acf860e9 100644 --- a/library/Director/Web/Form/IcingaObjectFieldLoader.php +++ b/library/Director/Web/Form/IcingaObjectFieldLoader.php @@ -25,13 +25,36 @@ class IcingaObjectFieldLoader public function addFieldsToForm(QuickForm $form) { - if ($this->object->supportsFields()) { + if ($this->fields || $this->object->supportsFields()) { $this->attachFieldsToForm($form); } return $this; } + public function loadFieldsForMultipleObjects($objects) + { + $fields = array(); + foreach ($objects as $object) { + foreach ($this->prepareObjectFields($object) as $varname => $field) { + $varname = $field->varname; + if (array_key_exists($varname, $fields)) { + if ($field->datatype !== $fields[$varname]->datatype) { + unset($fields[$varname]); + } + + continue; + } + + $fields[$field->varname] = $field; + } + } + + $this->fields = $fields; + + return $this; + } + /** * Set a list of values * From dedaea0319564243e5da17b355e0159aafe741da Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 04:29:23 +0000 Subject: [PATCH 10/18] IcingaServiceSetForm: prepare custom fields --- application/forms/IcingaServiceSetForm.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/application/forms/IcingaServiceSetForm.php b/application/forms/IcingaServiceSetForm.php index a3cbc8cd..efd9c1be 100644 --- a/application/forms/IcingaServiceSetForm.php +++ b/application/forms/IcingaServiceSetForm.php @@ -2,7 +2,8 @@ namespace Icinga\Module\Director\Forms; -use Icinga\Module\Director\Object\IcingaHost; +use Icinga\Module\Director\Objects\IcingaHost; +use Icinga\Module\Director\Objects\IcingaService; use Icinga\Module\Director\Web\Form\DirectorObjectForm; class IcingaServiceSetForm extends DirectorObjectForm @@ -43,12 +44,26 @@ class IcingaServiceSetForm extends DirectorObjectForm 'rows' => '5', 'multiOptions' => $this->enumServices(), 'required' => true, + 'class' => 'autosubmit', )); } else { $this->addHidden('object_type', 'object'); $this->addHidden('host_id', $this->host->id); } + $services = array(); + foreach ($this->getSentOrObjectValue('service') as $name) { + $services[] = IcingaService::load(array( + 'object_name' => $name, + 'object_type' => 'template' + ), $this->db); + } + + if ($this->assertResolvedImports()) { + $loader = $this->fieldLoader($this->object); + $loader->loadFieldsForMultipleObjects($services); + } + $this->setButtons(); } @@ -63,7 +78,8 @@ class IcingaServiceSetForm extends DirectorObjectForm $db = $this->db->getDbAdapter(); $query = $db->select() ->from('icinga_service', 'object_name') - ->where('object_type = ?', 'template'); + ->where('object_type = ?', 'template') + ->order('object_name'); $names = $db->fetchCol($query); return array_combine($names, $names); From 354d12946adaf5d6adf8c7c40cf418cf1872672e Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 07:14:54 +0000 Subject: [PATCH 11/18] IcingaServiceSet: render custom vars --- library/Director/Objects/IcingaServiceSet.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/Director/Objects/IcingaServiceSet.php b/library/Director/Objects/IcingaServiceSet.php index 1aa86214..09dbc1e2 100644 --- a/library/Director/Objects/IcingaServiceSet.php +++ b/library/Director/Objects/IcingaServiceSet.php @@ -101,6 +101,7 @@ class IcingaServiceSet extends IcingaObject $service->setAssignments($this->getAssignments()); } + $service->vars = $this->vars; $service->host_id = $this->host_id; $file->addObject($service); } @@ -142,6 +143,7 @@ class IcingaServiceSet extends IcingaObject foreach ($this->getServiceObjects() as $service) { $service->object_type = 'object'; $service->host_id = $this->host_id; + $service->vars = $this->vars; $file->addLegacyObject($service); } } From 4929f6b228841c0f5e613111eef5260652ca4cef Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 07:15:42 +0000 Subject: [PATCH 12/18] Host: show a related service set list --- application/controllers/HostController.php | 13 +++ .../tables/IcingaHostServiceSetTable.php | 79 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 application/tables/IcingaHostServiceSetTable.php diff --git a/application/controllers/HostController.php b/application/controllers/HostController.php index 997b46da..bc6368af 100644 --- a/application/controllers/HostController.php +++ b/application/controllers/HostController.php @@ -69,6 +69,11 @@ class HostController extends ObjectController 'director/service/add', array('host' => $host->object_name), array('class' => 'icon-plus') + ) . ' ' . $this->view->qlink( + $this->translate('Add service set'), + 'director/serviceset/add', + array('host' => $host->object_name), + array('class' => 'icon-plus') ); $this->getTabs()->activate('services'); @@ -120,6 +125,14 @@ class HostController extends ObjectController $tables[$title] = $table->setTitle($title); } + $title = $this->translate('Service sets'); + $table = $this->loadTable('IcingaHostServiceSet') + ->setHost($host) + ->setTitle($title) + ->setConnection($db); + + $tables[$title] = $table; + $this->view->tables = $tables; } diff --git a/application/tables/IcingaHostServiceSetTable.php b/application/tables/IcingaHostServiceSetTable.php new file mode 100644 index 00000000..60197096 --- /dev/null +++ b/application/tables/IcingaHostServiceSetTable.php @@ -0,0 +1,79 @@ + 'sset.id', + 'name' => 'sset.object_name', + 'object_type' => 'sset.object_type', + 'description' => 'sset.description', + 'host_name' => 'h.object_name', + ); + } + + public function getTitles() + { + $view = $this->view(); + return array( + 'name' => $view->translate('Service set'), + ); + } + + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + public function setHost(IcingaHost $host) + { + $this->host = $host; + return $this; + } + + protected function getActionUrl($row) + { + // TODO: Remove once we got a separate apply table + if ($row->object_type === 'apply') { + $params['id'] = $row->id; + } else { + $params = array('name' => $row->name); + if ($row->host_name) { + $params['host'] = $row->host_name; + } + } + + return $this->url('director/serviceset', $params); + } + + protected function getUnfilteredQuery() + { + $db = $this->connection()->getConnection(); + $query = $db->select()->from( + array('sset' => 'icinga_service_set'), + array() + )->joinLeft( + array('h' => 'icinga_host'), + 'h.id = sset.host_id', + array() + )->where('sset.host_id = ?', $this->host->id)->order('sset.object_name'); + + return $query; + } + + public function getBaseQuery() + { + return $this->getUnfilteredQuery(); + } +} From 1724a78da5bf44e38324b3c958e258211ce62557 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 07:19:44 +0000 Subject: [PATCH 13/18] DirectorObjectForm: do not set null values --- library/Director/Web/Form/DirectorObjectForm.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php index ae66161a..117f7650 100644 --- a/library/Director/Web/Form/DirectorObjectForm.php +++ b/library/Director/Web/Form/DirectorObjectForm.php @@ -236,7 +236,7 @@ abstract class DirectorObjectForm extends QuickForm unset($props['vars']); } - $this->setDefaults($props); + $this->setDefaults($this->removeNullProperties($props)); if ($resolve) { $this->showInheritedProperties($object); @@ -258,6 +258,18 @@ abstract class DirectorObjectForm extends QuickForm } } + protected function removeNullProperties($props) + { + $result = array(); + foreach ($props as $k => $v) { + if ($v !== null && $v !== '') { + $result[$k] = $v; + } + } + + return $result; + } + protected function handleCustomVars($object, & $values) { if ($this->assertResolvedImports()) { From 7f34e4bdf352a09235055e8a63b2be63a6b540c2 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 07:22:08 +0000 Subject: [PATCH 14/18] IcingaServiceSet: improve work with imports --- application/controllers/ServicesetController.php | 10 ++++++++++ application/tables/IcingaServiceSetTable.php | 2 +- .../Director/Objects/IcingaObjectMultiRelations.php | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/application/controllers/ServicesetController.php b/application/controllers/ServicesetController.php index 2f230f1a..dbafac33 100644 --- a/application/controllers/ServicesetController.php +++ b/application/controllers/ServicesetController.php @@ -19,6 +19,16 @@ class ServicesetController extends ObjectController parent::init(); } + public function loadForm($name) + { + $form = parent::loadForm($name); + if ($name === 'icingaServiceSet' && $this->host) { + $form->setHost($this->host); + } + + return $form; + } + protected function loadObject() { if ($this->object === null) { diff --git a/application/tables/IcingaServiceSetTable.php b/application/tables/IcingaServiceSetTable.php index bd612d56..5a33b7b8 100644 --- a/application/tables/IcingaServiceSetTable.php +++ b/application/tables/IcingaServiceSetTable.php @@ -50,7 +50,7 @@ class IcingaServiceSetTable extends IcingaObjectTable array('h' => 'icinga_host'), 'h.id = sset.host_id', array() - )->order('sset.object_name'); + )->where('sset.object_type = ?', 'template')->order('sset.object_name'); return $query; } diff --git a/library/Director/Objects/IcingaObjectMultiRelations.php b/library/Director/Objects/IcingaObjectMultiRelations.php index 5a5593a6..5413d75a 100644 --- a/library/Director/Objects/IcingaObjectMultiRelations.php +++ b/library/Director/Objects/IcingaObjectMultiRelations.php @@ -40,6 +40,11 @@ class IcingaObjectMultiRelations implements Iterator, Countable, IcingaConfigRen $this->relatedObjectClass = $relatedObjectClass; } + public function getObjects() + { + return $this->relations; + } + public function count() { return count($this->relations); From 5de24c6ec439c3b49fd730519361e1e024c35eb9 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 07:22:56 +0000 Subject: [PATCH 15/18] IcingaServiceSetForm: restructure the form --- application/forms/IcingaServiceSetForm.php | 132 ++++++++++++++------- 1 file changed, 92 insertions(+), 40 deletions(-) diff --git a/application/forms/IcingaServiceSetForm.php b/application/forms/IcingaServiceSetForm.php index efd9c1be..d21370c3 100644 --- a/application/forms/IcingaServiceSetForm.php +++ b/application/forms/IcingaServiceSetForm.php @@ -12,8 +12,36 @@ class IcingaServiceSetForm extends DirectorObjectForm public function setup() { - $this->addImportsElement(); + if ($this->host === null) { + $this->setupTemplate(); + } else { + $this->setupHost(); + } + $this->setupFields() + ->setButtons(); + } + + protected function setupFields() + { + $object = $this->object(); + + $this->assertResolvedImports(); + + if ($this->hasBeenSent() && $services = $this->getSentValue('service')) { + $object->service = $services; + } + + if ($this->assertResolvedImports()) { + $this->fieldLoader($object) + ->loadFieldsForMultipleObjects($object->getServiceObjects()); + } + + return $this; + } + + protected function setupTemplate() + { $this->addElement('text', 'object_name', array( 'label' => $this->translate('Service set name'), 'description' => $this->translate( @@ -21,7 +49,69 @@ class IcingaServiceSetForm extends DirectorObjectForm ), 'required' => true, )); - + + $this->addHidden('object_type', 'template'); + $this->addDescriptionElement(); + + $this->addElement('multiselect', 'service', array( + 'label' => $this->translate('Services'), + 'description' => $this->translate( + 'Services in this set' + ), + 'rows' => '5', + 'multiOptions' => $this->enumServices(), + 'required' => true, + 'class' => 'autosubmit', + )); + } + + protected function setupHost() + { + $object = $this->object(); + if ($this->hasBeenSent()) { + $object->object_name = $object->imports = $this->getSentValue('imports'); + } + + if (! $object->hasBeenLoadedFromDb()) { + $this->addSingleImportsElement(); + } + + if (count($object->imports)) { + $this->addHtmlHint( + $this->getView()->escape( + $object->getResolvedProperty('description') + ) + ); + } + + $this->addHidden('object_type', 'object'); + $this->addHidden('host_id', $this->host->id); + } + + public function setHost(IcingaHost $host) + { + $this->host = $host; + return $this; + } + protected function addSingleImportsElement() + { + $enum = $this->enumAllowedTemplates(); + + $this->addElement('select', 'imports', array( + 'label' => $this->translate('Service set'), + 'description' => $this->translate( + 'The service set that should be assigned to this host' + ), + 'required' => true, + 'multiOptions' => $this->optionallyAddFromEnum($enum), + 'class' => 'autosubmit' + )); + + return $this; + } + + protected function addDescriptionElement() + { $this->addElement('textarea', 'description', array( 'label' => $this->translate('Description'), 'description' => $this->translate( @@ -32,44 +122,6 @@ class IcingaServiceSetForm extends DirectorObjectForm 'required' => ! $this->isTemplate(), )); - - if ($this->host === null) { - $this->addHidden('object_type', 'object'); - - $this->addElement('multiselect', 'service', array( - 'label' => $this->translate('Services'), - 'description' => $this->translate( - 'Services in this set' - ), - 'rows' => '5', - 'multiOptions' => $this->enumServices(), - 'required' => true, - 'class' => 'autosubmit', - )); - } else { - $this->addHidden('object_type', 'object'); - $this->addHidden('host_id', $this->host->id); - } - - $services = array(); - foreach ($this->getSentOrObjectValue('service') as $name) { - $services[] = IcingaService::load(array( - 'object_name' => $name, - 'object_type' => 'template' - ), $this->db); - } - - if ($this->assertResolvedImports()) { - $loader = $this->fieldLoader($this->object); - $loader->loadFieldsForMultipleObjects($services); - } - - $this->setButtons(); - } - - public function setHost(IcingaHost $host) - { - $this->host = $host; return $this; } From f09560a89e4f5b0613310629cb38c62fe93d789b Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 20 Oct 2016 07:23:49 +0000 Subject: [PATCH 16/18] IcingaServiceSet: simplify code --- library/Director/Objects/IcingaServiceSet.php | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/library/Director/Objects/IcingaServiceSet.php b/library/Director/Objects/IcingaServiceSet.php index 09dbc1e2..e0afd2f2 100644 --- a/library/Director/Objects/IcingaServiceSet.php +++ b/library/Director/Objects/IcingaServiceSet.php @@ -50,29 +50,21 @@ class IcingaServiceSet extends IcingaObject */ public function getServiceObjects() { - if (! $this->hasBeenLoadedFromDb()) { - return array(); + if ($this->host_id) { + $imports = $this->imports; + if (empty($imports)) { + return array(); + } + + $base = IcingaServiceSet::load(array( + 'object_name' => array_shift($imports), + 'object_type' => 'template' + ), $this->getConnection()); + } else { + $base = $this; } - $conn = $this->getConnection(); - $db = $conn->getDbAdapter(); - - $query = $db->select()->from( - array('s' => 'icinga_service'), - '*' - )->join( - array('sset' => 'icinga_service_set_service'), - 'sset.service_id = s.id', - array() - )->where( - $db->quoteInto( - 'sset.service_set_id = ?', - (int) $this->id - ) - )->order('s.object_name'); - - // TODO: This cannot be prefetched - return IcingaService::loadAll($conn, $query, 'object_name'); + return $base->getMultiRelation('service')->getObjects(); } public function renderToConfig(IcingaConfig $config) From 3f7a184d2f38f76ad874dcaec1e43490d3aa6ce2 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Tue, 25 Oct 2016 22:57:10 +0000 Subject: [PATCH 17/18] schema: get rid of service_set_service, introduce ...a service_set_id column directly on the service --- schema/mysql-migrations/upgrade_121.sql | 8 ++++++++ schema/mysql.sql | 19 ++----------------- schema/pgsql-migrations/upgrade_121.sql | 8 ++++++++ schema/pgsql.sql | 20 ++------------------ 4 files changed, 20 insertions(+), 35 deletions(-) create mode 100644 schema/mysql-migrations/upgrade_121.sql create mode 100644 schema/pgsql-migrations/upgrade_121.sql diff --git a/schema/mysql-migrations/upgrade_121.sql b/schema/mysql-migrations/upgrade_121.sql new file mode 100644 index 00000000..24c307aa --- /dev/null +++ b/schema/mysql-migrations/upgrade_121.sql @@ -0,0 +1,8 @@ +ALTER TABLE icinga_service + ADD COLUMN service_set_id INT(10) UNSIGNED DEFAULT NULL AFTER host_id; + +DROP TABLE icinga_service_set_service; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (121, NOW()); diff --git a/schema/mysql.sql b/schema/mysql.sql index c6a4932f..a6e46ed5 100644 --- a/schema/mysql.sql +++ b/schema/mysql.sql @@ -535,6 +535,7 @@ CREATE TABLE icinga_service ( disabled ENUM('y', 'n') NOT NULL DEFAULT 'n', display_name VARCHAR(255) DEFAULT NULL, host_id INT(10) UNSIGNED DEFAULT NULL, + service_set_id INT(10) UNSIGNED DEFAULT NULL, check_command_id INT(10) UNSIGNED DEFAULT NULL, max_check_attempts MEDIUMINT UNSIGNED DEFAULT NULL, check_period_id INT(10) UNSIGNED DEFAULT NULL, @@ -670,22 +671,6 @@ CREATE TABLE icinga_service_set ( UNIQUE KEY object_key (object_name, host_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE icinga_service_set_service ( - service_set_id INT(10) UNSIGNED NOT NULL, - service_id INT(10) UNSIGNED NOT NULL, - PRIMARY KEY (service_set_id, service_id), - CONSTRAINT service_set_set - FOREIGN KEY service_set (service_set_id) - REFERENCES icinga_service_set (id) - ON DELETE CASCADE - ON UPDATE CASCADE, - CONSTRAINT service_set_service - FOREIGN KEY service (service_id) - REFERENCES icinga_service (id) - ON DELETE RESTRICT - ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - CREATE TABLE icinga_service_set_inheritance ( service_set_id INT(10) UNSIGNED NOT NULL, parent_service_set_id INT(10) UNSIGNED NOT NULL, @@ -1369,4 +1354,4 @@ CREATE TABLE sync_run ( INSERT INTO director_schema_migration (schema_version, migration_time) - VALUES (120, NOW()); + VALUES (121, NOW()); diff --git a/schema/pgsql-migrations/upgrade_121.sql b/schema/pgsql-migrations/upgrade_121.sql new file mode 100644 index 00000000..f6a1050a --- /dev/null +++ b/schema/pgsql-migrations/upgrade_121.sql @@ -0,0 +1,8 @@ +ALTER TABLE icinga_service + ADD COLUMN service_set_id integer DEFAULT NULL; + +DROP TABLE icinga_service_set_service; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (121, NOW()); diff --git a/schema/pgsql.sql b/schema/pgsql.sql index 2f2cea04..84fd2ac3 100644 --- a/schema/pgsql.sql +++ b/schema/pgsql.sql @@ -677,6 +677,7 @@ CREATE TABLE icinga_service ( disabled enum_boolean DEFAULT 'n', display_name character varying(255) DEFAULT NULL, host_id INTEGER DEFAULT NULL, + service_set_id integer DEFAULT NULL, check_command_id integer DEFAULT NULL, max_check_attempts integer DEFAULT NULL, check_period_id integer DEFAULT NULL, @@ -838,23 +839,6 @@ CREATE TABLE icinga_service_set ( CREATE UNIQUE INDEX service_set_name ON icinga_service_set (object_name, host_id); -CREATE TABLE icinga_service_set_service ( - service_set_id serial, - service_id serial, - PRIMARY KEY (service_set_id, service_id), - CONSTRAINT icinga_service_set_set - FOREIGN KEY (service_set_id) - REFERENCES icinga_service_set (id) - ON DELETE CASCADE - ON UPDATE CASCADE, - CONSTRAINT icinga_service_set_service - FOREIGN KEY (service_id) - REFERENCES icinga_service (id) - ON DELETE RESTRICT - ON UPDATE CASCADE -); - - CREATE TABLE icinga_service_set_inheritance ( service_set_id integer NOT NULL, parent_service_set_id integer NOT NULL, @@ -1597,4 +1581,4 @@ CREATE UNIQUE INDEX notification_inheritance ON icinga_notification_inheritance INSERT INTO director_schema_migration (schema_version, migration_time) - VALUES (120, NOW()); + VALUES (121, NOW()); From d59604bd93b879637341722b33dfd8bc41128322 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Tue, 25 Oct 2016 23:01:18 +0000 Subject: [PATCH 18/18] ServiceSet: rework sets, allow for vars and... ...all other service properties when adding services to a set --- application/controllers/ServiceController.php | 43 ++++++++-- .../controllers/ServicesetController.php | 45 +++++++++++ application/controllers/ShowController.php | 2 +- application/forms/IcingaServiceForm.php | 45 ++++++++++- application/forms/IcingaServiceSetForm.php | 33 +++----- .../tables/IcingaServiceSetServiceTable.php | 73 +++++++++++++++++ library/Director/Objects/IcingaObject.php | 9 +++ library/Director/Objects/IcingaService.php | 6 +- library/Director/Objects/IcingaServiceSet.php | 81 +++++++++++++------ .../Director/Web/Form/DirectorObjectForm.php | 8 +- 10 files changed, 286 insertions(+), 59 deletions(-) create mode 100644 application/tables/IcingaServiceSetServiceTable.php diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index 738cf73c..855b67d7 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Controllers; use Icinga\Module\Director\Exception\NestingError; use Icinga\Module\Director\Web\Controller\ObjectController; +use Icinga\Module\Director\Objects\IcingaServiceSet; use Icinga\Module\Director\Objects\IcingaService; use Icinga\Module\Director\Objects\IcingaHost; @@ -11,6 +12,8 @@ class ServiceController extends ObjectController { protected $host; + protected $set; + protected $apply; protected function beforeTabs() @@ -28,9 +31,9 @@ class ServiceController extends ObjectController { if ($host = $this->params->get('host')) { $this->host = IcingaHost::load($host, $this->db()); - } - - if ($apply = $this->params->get('apply')) { + } elseif ($set = $this->params->get('set')) { + $this->set = IcingaServiceSet::load(array('object_name' => $set), $this->db()); + } elseif ($apply = $this->params->get('apply')) { $this->apply = IcingaService::load( array('object_name' => $apply, 'object_type' => 'template'), $this->db() @@ -45,6 +48,10 @@ class ServiceController extends ObjectController $tab->getUrl()->setParam('host', $this->host->object_name); } } + + if (! $this->set && $this->object->service_set_id) { + $this->set = $this->object->getRelated('service_set'); + } } if ($this->host) { @@ -53,6 +60,12 @@ class ServiceController extends ObjectController 'urlParams' => array('name' => $this->host->object_name), 'label' => $this->translate('Services'), )); + } elseif ($this->host) { + $this->getTabs()->add('services', array( + 'url' => 'director/serviceset/services', + 'urlParams' => array('name' => $this->set->object_name), + 'label' => $this->translate('Services'), + )); } } @@ -61,9 +74,12 @@ class ServiceController extends ObjectController parent::addAction(); if ($this->host) { $this->view->title = $this->host->object_name . ': ' . $this->view->title; - } - - if ($this->apply) { + } elseif ($this->set) { + $this->view->title = sprintf( + $this->translate('Add a service to "%s"'), + $this->set->object_name + ); + } elseif ($this->apply) { $this->view->title = sprintf( $this->translate('Apply "%s"'), $this->apply->object_name @@ -147,8 +163,15 @@ class ServiceController extends ObjectController public function loadForm($name) { $form = parent::loadForm($name); - if ($name === 'icingaService' && $this->host) { - $form->setHost($this->host); + if ($name === 'icingaService') { + if ($this->host) { + $form->setHost($this->host); + } elseif ($this->set) { + $form->setServiceSet($this->set)->setSuccessUrl( + 'director/serviceset/services', + array('name' => $this->set->object_name) + ); + } } return $form; @@ -166,6 +189,10 @@ class ServiceController extends ObjectController $params['host_id'] = $this->host->id; } + if ($this->set) { + $this->view->set = $this->set; + $params['service_set_id'] = $this->set->id; + } $this->object = IcingaService::load($params, $db); } else { parent::loadObject(); diff --git a/application/controllers/ServicesetController.php b/application/controllers/ServicesetController.php index dbafac33..88c2a65d 100644 --- a/application/controllers/ServicesetController.php +++ b/application/controllers/ServicesetController.php @@ -17,6 +17,14 @@ class ServicesetController extends ObjectController } parent::init(); + if ($this->object) { + $tabs = $this->getTabs(); + $tabs->add('services', array( + 'url' => 'director/serviceset/services', + 'urlParams' => array('name' => $this->object->object_name), + 'label' => 'Services' + )); + } } public function loadForm($name) @@ -29,6 +37,43 @@ class ServicesetController extends ObjectController return $form; } + public function addAction() + { + parent::addAction(); + if ($this->host) { + $this->view->title = sprintf( + $this->translate('Add a service set to "%s"'), + $this->host->object_name + ); + } + } + + public function servicesAction() + { + $db = $this->db(); + $set = $this->object; + + $this->view->addLink = $this->view->qlink( + $this->translate('Add service'), + 'director/service/add', + array('set' => $set->object_name), + array('class' => 'icon-plus') + ); + $this->view->stayHere = true; + + $this->getTabs()->activate('services'); + $this->view->title = sprintf( + $this->translate('Services in this set: %s'), + $set->object_name + ); + + $this->view->table = $this->loadTable('IcingaServiceSetService') + ->setServiceSet($set) + ->setConnection($db); + + $this->setViewScript('objects/table'); + } + protected function loadObject() { if ($this->object === null) { diff --git a/application/controllers/ShowController.php b/application/controllers/ShowController.php index 87f62c81..90b66e51 100644 --- a/application/controllers/ShowController.php +++ b/application/controllers/ShowController.php @@ -17,7 +17,7 @@ class ShowController extends ActionController protected function objectKey($entry) { - if ($entry->object_type === 'icinga_service') { + if ($entry->object_type === 'icinga_service' || $entry->object_type === 'icinga_service_set') { // TODO: this is not correct. Activity needs to get (multi) key support return array('name' => $entry->object_name); } diff --git a/application/forms/IcingaServiceForm.php b/application/forms/IcingaServiceForm.php index 9f28e38f..d4aabf68 100644 --- a/application/forms/IcingaServiceForm.php +++ b/application/forms/IcingaServiceForm.php @@ -7,11 +7,14 @@ use Icinga\Module\Director\Exception\NestingError; use Icinga\Module\Director\Web\Form\DirectorObjectForm; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaService; +use Icinga\Module\Director\Objects\IcingaServiceSet; class IcingaServiceForm extends DirectorObjectForm { private $host; + private $set; + private $apply; private $hostGenerated = false; @@ -52,7 +55,9 @@ class IcingaServiceForm extends DirectorObjectForm // ignore for the form to load } - if ($this->host === null) { + if ($this->set !== null) { + $this->setupSetRelatedElements(); + } elseif ($this->host === null) { $this->setupServiceElements(); } else { $this->setupHostRelatedElements(); @@ -206,6 +211,44 @@ class IcingaServiceForm extends DirectorObjectForm return $this; } + protected function setupSetRelatedElements() + { + $this->addHidden('service_set_id', $this->set->id); + $this->addHidden('object_type', 'apply'); + $this->addImportsElement(); + $imports = $this->getSentOrObjectValue('imports'); + + if ($this->hasBeenSent()) { + $imports = $this->getElement('imports')->setValue($imports)->getValue(); + } + + if ($this->isNew() && empty($imports)) { + return $this->groupMainProperties(); + } + + $this->addNameElement() + ->addDisabledElement() + ->groupMainProperties() + ->addCheckCommandElements(true) + ->addCheckExecutionElements(true) + ->addExtraInfoElements() + ->setButtons(); + + if ($this->hasBeenSent()) { + $name = $this->getSentOrObjectValue('object_name'); + if (!strlen($name)) { + $this->setElementValue('object_name', end($imports)); + $this->object->object_name = end($imports); + } + } + } + + public function setServiceSet(IcingaServiceSet $set) + { + $this->set = $set; + return $this; + } + protected function addNameElement() { $this->addElement('text', 'object_name', array( diff --git a/application/forms/IcingaServiceSetForm.php b/application/forms/IcingaServiceSetForm.php index d21370c3..986bed22 100644 --- a/application/forms/IcingaServiceSetForm.php +++ b/application/forms/IcingaServiceSetForm.php @@ -51,18 +51,8 @@ class IcingaServiceSetForm extends DirectorObjectForm )); $this->addHidden('object_type', 'template'); - $this->addDescriptionElement(); - - $this->addElement('multiselect', 'service', array( - 'label' => $this->translate('Services'), - 'description' => $this->translate( - 'Services in this set' - ), - 'rows' => '5', - 'multiOptions' => $this->enumServices(), - 'required' => true, - 'class' => 'autosubmit', - )); + $this->addDescriptionElement() + ->addAssignmentElements(); } protected function setupHost() @@ -125,15 +115,18 @@ class IcingaServiceSetForm extends DirectorObjectForm return $this; } - protected function enumServices() + protected function addAssignmentElements() { - $db = $this->db->getDbAdapter(); - $query = $db->select() - ->from('icinga_service', 'object_name') - ->where('object_type = ?', 'template') - ->order('object_name'); - $names = $db->fetchCol($query); + $this->addAssignFilter(array( + 'columns' => IcingaHost::enumProperties($this->db, 'host.'), + 'description' => $this->translate( + 'This allows you to configure an assignment filter. Please feel' + . ' free to combine as many nested operators as you want. You' + . ' might also want to skip this, define it later and/or just' + . ' add this set of services to single hosts' + ) + )); - return array_combine($names, $names); + return $this; } } diff --git a/application/tables/IcingaServiceSetServiceTable.php b/application/tables/IcingaServiceSetServiceTable.php new file mode 100644 index 00000000..d95905b6 --- /dev/null +++ b/application/tables/IcingaServiceSetServiceTable.php @@ -0,0 +1,73 @@ + 's.id', + 'service_set_id' => 's.service_set_id', + 'service_set' => 'ss.object_name', + 'service' => 's.object_name', + 'object_type' => 's.object_type', + ); + } + + public function setServiceSet(IcingaServiceSet $set) + { + $this->set = $set; + return $this; + } + + protected function getActionUrl($row) + { + $params = array( + 'name' => $row->service, + 'set' => $row->service_set + ); + + return $this->url('director/service', $params); + } + + public function getTitles() + { + $view = $this->view(); + return array( + 'service' => $view->translate('Servicename'), + ); + } + + public function getUnfilteredQuery() + { + $db = $this->connection()->getConnection(); + $query = $db->select()->from( + array('s' => 'icinga_service'), + array() + )->joinLeft( + array('ss' => 'icinga_service_set'), + 'ss.id = s.service_set_id', + array() + )->order('s.object_name'); + + return $query; + } + + public function getBaseQuery() + { + return $this->getUnfilteredQuery()->where( + 's.service_set_id = ?', + $this->set->id + ); + } +} diff --git a/library/Director/Objects/IcingaObject.php b/library/Director/Objects/IcingaObject.php index ff4d0628..0f6d4556 100644 --- a/library/Director/Objects/IcingaObject.php +++ b/library/Director/Objects/IcingaObject.php @@ -274,6 +274,11 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this->relations[$property]; } + public function getRelated($property) + { + return $this->getRelatedObject($property, $this->{$property . '_id'}); + } + protected function getRelatedObjectName($property, $id) { return $this->getRelatedObject($property, $id)->object_name; @@ -2337,6 +2342,10 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer if ($this->hasProperty('service_id') && $this->service_id) { $params['service'] = $this->service; } + + if ($this->hasProperty('service_set_id') && $this->service_set_id) { + $params['set'] = $this->service_set; + } } return $params; diff --git a/library/Director/Objects/IcingaService.php b/library/Director/Objects/IcingaService.php index 1c29f010..862fe1d3 100644 --- a/library/Director/Objects/IcingaService.php +++ b/library/Director/Objects/IcingaService.php @@ -18,6 +18,7 @@ class IcingaService extends IcingaObject 'disabled' => 'n', 'display_name' => null, 'host_id' => null, + 'service_set_id' => null, 'check_command_id' => null, 'max_check_attempts' => null, 'check_period_id' => null, @@ -47,6 +48,7 @@ class IcingaService extends IcingaObject protected $relations = array( 'host' => 'IcingaHost', + 'service_set' => 'IcingaServiceSet', 'check_command' => 'IcingaCommand', 'event_command' => 'IcingaCommand', 'check_period' => 'IcingaTimePeriod', @@ -83,7 +85,7 @@ class IcingaService extends IcingaObject protected $supportsSets = true; - protected $keyName = array('host_id', 'object_name'); + protected $keyName = array('host_id', 'service_set_id', 'object_name'); protected $prioritizedProperties = array('host_id'); @@ -123,7 +125,7 @@ class IcingaService extends IcingaObject if (is_int($key)) { $this->id = $key; } elseif (is_array($key)) { - foreach (array('id', 'host_id', 'object_name') as $k) { + foreach (array('id', 'host_id', 'service_set_id', 'object_name') as $k) { if (array_key_exists($k, $key)) { $this->set($k, $key[$k]); } diff --git a/library/Director/Objects/IcingaServiceSet.php b/library/Director/Objects/IcingaServiceSet.php index e0afd2f2..7de95e13 100644 --- a/library/Director/Objects/IcingaServiceSet.php +++ b/library/Director/Objects/IcingaServiceSet.php @@ -17,6 +17,7 @@ class IcingaServiceSet extends IcingaObject 'object_name' => null, 'object_type' => null, 'description' => null, + 'assign_filter' => null, ); protected $keyName = array('host_id', 'object_name'); @@ -31,10 +32,6 @@ class IcingaServiceSet extends IcingaObject 'host' => 'IcingaHost', ); - protected $multiRelations = array( - 'service' => 'IcingaService', - ); - public function isDisabled() { return false; @@ -51,25 +48,45 @@ class IcingaServiceSet extends IcingaObject public function getServiceObjects() { if ($this->host_id) { - $imports = $this->imports; + $imports = $this->imports()->getObjects(); if (empty($imports)) { return array(); } - - $base = IcingaServiceSet::load(array( - 'object_name' => array_shift($imports), - 'object_type' => 'template' - ), $this->getConnection()); + return $this->getServiceObjectsForSet(array_shift($imports)); } else { - $base = $this; + return $this->getServiceObjectsForSet($this); + } + } + + protected function getServiceObjectsForSet(IcingaServiceSet $set) + { + if ($set->id === null) { + return array(); } - return $base->getMultiRelation('service')->getObjects(); + $connection = $this->getConnection(); + $db = $this->getDb(); + $ids = $db->fetchCol( + $db->select()->from('icinga_service', 'id') + ->where('service_set_id = ?', $set->id) + ); + + $services = array(); + foreach ($ids as $id) { + $service = IcingaService::load(array( + 'id' => $id, + 'object_type' => 'template' + ), $connection); + + $services[$service->object_name] = $service; + } + + return $services; } public function renderToConfig(IcingaConfig $config) { - if ($this->isTemplate()) { + if ($this->assign_filter === null && $this->isTemplate()) { return; } @@ -77,20 +94,22 @@ class IcingaServiceSet extends IcingaObject return $this->renderToLegacyConfig($config); } + $file = $this->getConfigFileWithHeader($config); + // Loop over all services belonging to this set // add our assign rules and then add the service to the config // eventually clone them beforehand to not get into trouble with caches // figure out whether we might need a zone property - $file = $config->configFile( - 'zones.d/' . $this->getRenderingZone($config) . '/servicesets' - ); - - $file->prepend($this->getConfigHeaderComment($config)); - foreach ($this->getServiceObjects() as $service) { - $service->object_type = $this->object_type; - if ($this->isApplyRule()) { - $service->setAssignments($this->getAssignments()); + // TODO: make them REAL applies + if ($this->assign_filter) { + $service->object_type = 'apply'; + $service->assign_filter = $this->assign_filter; + } else { + $service->object_type = $this->object_type; + if ($this->isApplyRule()) { + $service->assign_filter = $this->assign_filter; + } } $service->vars = $this->vars; @@ -99,6 +118,16 @@ class IcingaServiceSet extends IcingaObject } } + protected function getConfigFileWithHeader(IcingaConfig $config) + { + $file = $config->configFile( + 'zones.d/' . $this->getRenderingZone($config) . '/servicesets' + ); + + $file->prepend($this->getConfigHeaderComment($config)); + return $file; + } + protected function getConfigHeaderComment(IcingaConfig $config) { if ($config->isLegacy()) { @@ -142,6 +171,12 @@ class IcingaServiceSet extends IcingaObject public function getRenderingZone(IcingaConfig $config = null) { - return $this->connection->getDefaultGlobalZoneName(); + if ($this->host_id === null) { + return $this->connection->getDefaultGlobalZoneName(); + } else { + $host = $this->getRelatedObject('host', $this->host_id); + return $host->getRenderingZone($config); + } + return $zone; } } diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php index 117f7650..5f05048f 100644 --- a/library/Director/Web/Form/DirectorObjectForm.php +++ b/library/Director/Web/Form/DirectorObjectForm.php @@ -929,9 +929,9 @@ abstract class DirectorObjectForm extends QuickForm return $this; } - protected function addCheckCommandElements() + protected function addCheckCommandElements($force = false) { - if (! $this->isTemplate()) { + if (! $force && ! $this->isTemplate()) { return $this; } @@ -958,9 +958,9 @@ abstract class DirectorObjectForm extends QuickForm return $this; } - protected function addCheckExecutionElements() + protected function addCheckExecutionElements($force = false) { - if (! $this->isTemplate()) { + if (! $force && ! $this->isTemplate()) { return $this; }