From d59604bd93b879637341722b33dfd8bc41128322 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Tue, 25 Oct 2016 23:01:18 +0000 Subject: [PATCH] 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; }