diff --git a/application/forms/DeploymentLinkForm.php b/application/forms/DeploymentLinkForm.php index f163b548..6d158fc2 100644 --- a/application/forms/DeploymentLinkForm.php +++ b/application/forms/DeploymentLinkForm.php @@ -4,7 +4,7 @@ namespace Icinga\Module\Director\Forms; use Icinga\Authentication\Auth; use Icinga\Exception\IcingaException; -use Icinga\Module\Director\Core\CoreApi; +use Icinga\Module\Director\Core\DeploymentApiInterface; use Icinga\Module\Director\Db; use Icinga\Module\Director\Deployment\DeploymentInfo; use Icinga\Module\Director\IcingaConfig\IcingaConfig; @@ -20,7 +20,7 @@ class DeploymentLinkForm extends DirectorForm /** @var Auth */ protected $auth; - /** @var CoreApi */ + /** @var DeploymentApiInterface */ protected $api; /** @var Db */ @@ -31,7 +31,7 @@ class DeploymentLinkForm extends DirectorForm * @param Auth $auth * @return static */ - public static function create(Db $db, DeploymentInfo $info, Auth $auth, CoreApi $api) + public static function create(Db $db, DeploymentInfo $info, Auth $auth, DeploymentApiInterface $api) { $self = static::load(); $self->setAuth($auth); diff --git a/application/forms/IcingaHostForm.php b/application/forms/IcingaHostForm.php index e19945ee..b611195c 100644 --- a/application/forms/IcingaHostForm.php +++ b/application/forms/IcingaHostForm.php @@ -283,24 +283,7 @@ class IcingaHostForm extends DirectorObjectForm return []; } - $db = $this->getDb()->getDbAdapter(); - $query = $db->select()->from( - ['hghr' => 'icinga_hostgroup_host_resolved'], - ['hg.object_name'] - )->join( - ['hg' => 'icinga_hostgroup'], - 'hg.id = hghr.hostgroup_id', - [] - )->joinLeft( - ['hgh' => 'icinga_hostgroup_host'], - 'hgh.hostgroup_id = hghr.hostgroup_id', - [] - )->where( - 'hghr.host_id = ?', - $this->object()->get('id') - )->where('hgh.host_id IS NULL')->order('hg.object_name'); - - return $db->fetchCol($query); + return $this->object()->getAppliedGroups(); } protected function hasHostGroupRestriction() diff --git a/library/Director/Data/Db/DbObject.php b/library/Director/Data/Db/DbObject.php index 3242fc96..f593be34 100644 --- a/library/Director/Data/Db/DbObject.php +++ b/library/Director/Data/Db/DbObject.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Data\Db; +use Icinga\Exception\IcingaException; use Icinga\Exception\NotFoundError; use Icinga\Module\Director\Db; use Icinga\Module\Director\Exception\DuplicateKeyException; @@ -536,18 +537,22 @@ abstract class DbObject * * // TODO: may conflict with ->id * + * @throws IcingaException When key can not be calculated + * * @return string|array */ public function getId() { - // TODO: Doesn't work for array() / multicol key if (is_array($this->keyName)) { $id = array(); foreach ($this->keyName as $key) { - if (! isset($this->properties[$key])) { - return null; // Really? + if (isset($this->properties[$key])) { + $id[$key] = $this->properties[$key]; } - $id[$key] = $this->properties[$key]; + } + + if (empty($id)) { + throw new IcingaException('Could not evaluate id for multi-column object!'); } return $id; diff --git a/library/Director/Objects/Extension/FlappingSupport.php b/library/Director/Objects/Extension/FlappingSupport.php index 74b366a1..a86f10dd 100644 --- a/library/Director/Objects/Extension/FlappingSupport.php +++ b/library/Director/Objects/Extension/FlappingSupport.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Objects\Extension; use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c; +use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1; trait FlappingSupport { @@ -22,7 +23,6 @@ trait FlappingSupport */ protected function renderFlapping_threshold_low($value) { - // @codingStandardsIgnoreEnd return $this->renderFlappingThreshold('flapping_threshold_low', $value); } @@ -35,4 +35,20 @@ trait FlappingSupport c::renderKeyValue($key, c::renderFloat($value)) ); } + + protected function renderLegacyEnable_flapping($value) + { + return c1::renderKeyValue('flap_detection_enabled', c1::renderBoolean($value)); + } + + protected function renderLegacyFlapping_threshold_high($value) + { + return c1::renderKeyValue('high_flap_threshold', $value); + } + + protected function renderLegacyFlapping_threshold_low($value) + { + // @codingStandardsIgnoreEnd + return c1::renderKeyValue('low_flap_threshold', $value); + } } diff --git a/library/Director/Objects/IcingaHost.php b/library/Director/Objects/IcingaHost.php index d8c1eb00..db1ea00e 100644 --- a/library/Director/Objects/IcingaHost.php +++ b/library/Director/Objects/IcingaHost.php @@ -414,6 +414,12 @@ class IcingaHost extends IcingaObject return c1::renderKeyValue('display_name', $this->display_name); } + protected function renderLegacyVolatile() + { + // not available for hosts in Icinga 1.x + return; + } + protected function renderLegacyCustomExtensions() { $str = parent::renderLegacyCustomExtensions(); diff --git a/library/Director/Objects/IcingaHostGroup.php b/library/Director/Objects/IcingaHostGroup.php index b5cffafa..e11f672e 100644 --- a/library/Director/Objects/IcingaHostGroup.php +++ b/library/Director/Objects/IcingaHostGroup.php @@ -2,11 +2,6 @@ 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\IcingaLegacyConfigHelper as c1; - class IcingaHostGroup extends IcingaObjectGroup { protected $table = 'icinga_hostgroup'; @@ -19,15 +14,6 @@ class IcingaHostGroup extends IcingaObjectGroup return true; } - public function renderToLegacyConfig(IcingaConfig $config) - { - if ($this->get('assign_filter') !== null) { - $this->renderLegacyApplyToConfig($config); - } else { - parent::renderToLegacyConfig($config); - } - } - protected function getHostGroupMembershipResolver() { if ($this->hostgroupMembershipResolver === null) { @@ -53,100 +39,4 @@ class IcingaHostGroup extends IcingaObjectGroup return $this; } - - /** - * @param IcingaConfig $config - * - * @throws ProgrammingError When IcingaConfig deployment mode is not supported - */ - protected function renderLegacyApplyToConfig(IcingaConfig $config) - { - $conn = $this->getConnection(); - - $filter = Filter::fromQueryString($this->get('assign_filter')); - $hosts = HostApplyMatches::forFilter($filter, $conn); - $this->set('object_type', 'object'); - - $zoneMap = array(); - - foreach ($hosts as $hostname) { - $host = IcingaHost::load($hostname, $this->connection); - - if (($zoneId = $host->getResolvedProperty('zone_id')) !== null) { - $zoneMap[$zoneId][] = $hostname; - } else { - $zoneMap[0][] = $hostname; - } - } - - if (empty($zoneMap)) { - // no hosts matched - $file = $this->legacyZoneHostgroupFile($config); - $this->properties['members'] = array(); - $file->addLegacyObject($this); - } else { - $allMembers = array(); - - // make sure we write to all zones - // so host -> group relations are still possible - foreach (IcingaObject::loadAllByType('zone', $conn) as $zone) { - if (! array_key_exists($zone->id, $zoneMap)) { - $zoneMap[$zone->id] = array(); - } - } - - foreach ($zoneMap as $zoneId => $members) { - $file = $this->legacyZoneHostgroupFile($config, $zoneId); - $this->properties['members'] = $members; - $file->addLegacyObject($this); - - $allMembers = array_merge($allMembers, $members); - } - - $deploymentMode = $config->getDeploymentMode(); - if ($deploymentMode === 'active-passive') { - $this->properties['members'] = $allMembers; - $this->legacyZoneHostgroupFile($config, 0) - ->addLegacyObject($this); - } elseif ($deploymentMode == 'masterless') { - // nothing to add - } else { - throw new ProgrammingError('Unsupported deployment mode: %s' . $deploymentMode); - } - } - } - - protected function legacyZoneHostgroupFile(IcingaConfig $config, $zoneId = null) - { - if ($zoneId !== null) { - $zone = IcingaZone::load($zoneId, $this->getConnection())->getObjectName(); - } else { - $zone = $this->connection->getDefaultGlobalZoneName(); - } - return $config->configFile( - 'director/' . $zone . '/hostgroups', - '.cfg' - ); - } - - protected function renderLegacyMembers() - { - if (empty($this->properties['members'])) { - return ''; - } - return c1::renderKeyValue('members', join(',', $this->properties['members'])); - } - - /** - * Note: rendered with renderLegacyMembers() - * - * @return string - * - * @codingStandardsIgnoreStart - */ - protected function renderLegacyAssign_filter() - { - // @codingStandardsIgnoreEnd - return ''; - } } diff --git a/library/Director/Objects/IcingaObject.php b/library/Director/Objects/IcingaObject.php index b47944b1..0656fb27 100644 --- a/library/Director/Objects/IcingaObject.php +++ b/library/Director/Objects/IcingaObject.php @@ -853,6 +853,34 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this->groups->hasBeenModified(); } + + public function getAppliedGroups() + { + $this->assertGroupsSupport(); + if (! $this instanceof IcingaHost) { + throw new ProgrammingError('getAppliedGroups is only available for hosts currently!'); + } + + $type = strtolower($this->type); + $query = $this->db->select()->from( + ['gr' => "icinga_${type}group_${type}_resolved"], + ['g.object_name'] + )->join( + ['g' => "icinga_${type}group"], + "g.id = gr.${type}group_id", + [] + )->joinLeft( + ['go' => "icinga_${type}group_${type}"], + "go.${type}group_id = gr.${type}group_id", + [] + )->where( + "gr.${type}_id = ?", + $this->id + )->where("go.${type}_id IS NULL")->order('g.object_name'); + + return $this->db->fetchCol($query); + } + /** * @return IcingaTimePeriodRanges */ @@ -1819,13 +1847,17 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer /** * @codingStandardsIgnoreStart */ - protected function renderLegacyHost_id() + protected function renderLegacyHost_id($value) { - return $this->renderLegacyRelationProperty( - 'host', - $this->get('host_id'), - 'host_name' - ); + if (is_array($value)) { + return c1::renderKeyValue('host_name', c1::renderArray($value)); + } else { + return $this->renderLegacyRelationProperty( + 'host', + $this->get('host_id'), + 'host_name' + ); + } } /** @@ -2043,6 +2075,13 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer } } + if ($this->propertyIsInterval($key)) { + return c1::renderKeyValue( + $this->intervalProperties[$key], + c1::renderInterval($value) + ); + } + if (substr($key, -3) === '_id' && $this->hasRelation($relKey = substr($key, 0, -3)) ) { @@ -2113,8 +2152,12 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer */ protected function renderLegacyGroups() { - if ($this->supportsGroups()) { - return $this->groups()->toLegacyConfigString(); + if ($this->supportsGroups() && $this->hasBeenLoadedFromDb()) { + $applied = array(); + if ($this instanceof IcingaHost) { + $applied = $this->getAppliedGroups(); + } + return $this->groups()->toLegacyConfigString($applied); } else { return ''; } @@ -2323,12 +2366,27 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer */ public function renderAssign_Filter() { - // @codingStandardsIgnoreEnd return ' ' . AssignRenderer::forFilter( Filter::fromQueryString($this->get('assign_filter')) )->renderAssign() . "\n"; } + public function renderLegacyAssign_Filter() + { + // @codingStandardsIgnoreEnd + if ($this instanceof IcingaHostGroup) { + $c = " # resolved memberships are set via the individual object\n"; + } elseif ($this instanceof IcingaService) { + $c = " # resolved objects are listed here\n"; + } else { + $c = " # assign is not supported for " . $this->type . "\n"; + } + $c .= ' #' . AssignRenderer::forFilter( + Filter::fromQueryString($this->get('assign_filter')) + )->renderAssign() . "\n"; + return $c; + } + public function toLegacyConfigString() { $str = implode(array( @@ -2902,6 +2960,27 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer } } + protected function mapHostsToZones($names) + { + $map = array(); + + foreach ($names as $hostname) { + /** @var IcingaHost $host */ + $host = IcingaHost::load($hostname, $this->connection); + + $zone = $host->getRenderingZone(); + if (! array_key_exists($zone, $map)) { + $map[$zone] = array(); + } + + $map[$zone][] = $hostname; + } + + ksort($map); + + return $map; + } + public function getUrlParams() { $params = array(); diff --git a/library/Director/Objects/IcingaObjectGroups.php b/library/Director/Objects/IcingaObjectGroups.php index 7f79fad9..56d02280 100644 --- a/library/Director/Objects/IcingaObjectGroups.php +++ b/library/Director/Objects/IcingaObjectGroups.php @@ -348,9 +348,10 @@ class IcingaObjectGroups implements Iterator, Countable, IcingaConfigRenderer return c::renderKeyValue('groups', c::renderArray($groups)); } - public function toLegacyConfigString() + public function toLegacyConfigString($additionalGroups = array()) { - $groups = array_keys($this->groups); + $groups = array_merge(array_keys($this->groups), $additionalGroups); + $groups = array_unique($groups); if (empty($groups)) { return ''; diff --git a/library/Director/Objects/IcingaService.php b/library/Director/Objects/IcingaService.php index a57a4d0e..f3cedbc3 100644 --- a/library/Director/Objects/IcingaService.php +++ b/library/Director/Objects/IcingaService.php @@ -198,7 +198,6 @@ class IcingaService extends IcingaObject public function renderHost_id() { // @codingStandardsIgnoreEnd - if ($this->hasBeenAssignedToHostTemplate()) { return ''; } @@ -231,37 +230,16 @@ class IcingaService extends IcingaObject $assign_filter = $this->get('assign_filter'); $filter = Filter::fromQueryString($assign_filter); - $hosts = HostApplyMatches::forFilter($filter, $conn); + $hostnames = HostApplyMatches::forFilter($filter, $conn); + $this->set('object_type', 'object'); - $this->set('assign_filter', null); - foreach ($hosts as $hostname) { - $file = $this->legacyHostnameServicesFile($hostname, $config); - $this->set('host', $hostname); - $file->addLegacyObject($this); + foreach ($this->mapHostsToZones($hostnames) as $zone => $names) { + $this->set('host_id', $names); + + $config->configFile('director/' . $zone . '/service_apply', '.cfg') + ->addLegacyObject($this); } - - $this->set('host', null); - $this->set('object_type', 'apply'); - $this->set('assign_filter', $assign_filter); - } - - /** - * @param string $hostname - * @param IcingaConfig $config - * @return \Icinga\Module\Director\IcingaConfig\IcingaConfigFile - * @throws \Icinga\Exception\NotFoundError - */ - protected function legacyHostnameServicesFile($hostname, IcingaConfig $config) - { - return $config->configFile( - sprintf( - 'director/%s/service_apply', - IcingaHost::load($hostname, $this->getConnection()) - ->getRenderingZone($config) - ), - '.cfg' - ); } /** @@ -273,10 +251,6 @@ class IcingaService extends IcingaObject return ''; } - if ($this->isApplyRule()) { - throw new InvalidArgumentException('Apply Services can not be rendered directly.'); - } - $str = parent::toLegacyConfigString(); if (! $this->isDisabled() diff --git a/library/Director/Objects/IcingaServiceSet.php b/library/Director/Objects/IcingaServiceSet.php index 21988e19..6253f0da 100644 --- a/library/Director/Objects/IcingaServiceSet.php +++ b/library/Director/Objects/IcingaServiceSet.php @@ -223,49 +223,27 @@ class IcingaServiceSet extends IcingaObject // Delegating this to the service would look, but this way it's faster if ($filter = $this->get('assign_filter')) { $filter = Filter::fromQueryString($filter); - $hosts = HostApplyMatches::forFilter($filter, $conn); + + $hostnames = HostApplyMatches::forFilter($filter, $conn); + } else { + $hostnames = array($this->getRelated('host')->object_name); + } + + foreach ($this->mapHostsToZones($hostnames) as $zone => $names) { + $file = $config->configFile('director/' . $zone . '/servicesets', '.cfg'); + $file->addContent($this->getConfigHeaderComment($config)); + foreach ($this->getServiceObjects() as $service) { $service->set('object_type', 'object'); + $service->set('host_id', $names); + $this->copyVarsToService($service); - foreach ($hosts as $hostname) { - $file = $this->legacyHostnameServicesFile($hostname, $config); - $file->addContent($this->getConfigHeaderComment($config)); - $service->set('host', $hostname); - $file->addLegacyObject($service); - } - } - } else { - foreach ($this->getServiceObjects() as $service) { - $service->set('object_type', 'object'); - $service->set('host_id', $this->get('host_id')); - foreach ($this->vars() as $k => $var) { - $service->$k = $var; - } - $file = $this->legacyRelatedHostFile($service, $config); - $file->addContent($this->getConfigHeaderComment($config)); $file->addLegacyObject($service); } } } - protected function legacyHostnameServicesFile($hostname, IcingaConfig $config) - { - $host = IcingaHost::load($hostname, $this->getConnection()); - return $config->configFile( - 'director/' . $host->getRenderingZone($config) . '/servicesets', - '.cfg' - ); - } - - protected function legacyRelatedHostFile(IcingaService $service, IcingaConfig $config) - { - return $config->configFile( - 'director/' . $service->getRelated('host')->getRenderingZone($config) . '/servicesets', - '.cfg' - ); - } - public function getRenderingZone(IcingaConfig $config = null) { if ($this->get('host_id') === null) { diff --git a/library/Director/Objects/ObjectApplyMatches.php b/library/Director/Objects/ObjectApplyMatches.php index 85145d57..85560b4d 100644 --- a/library/Director/Objects/ObjectApplyMatches.php +++ b/library/Director/Objects/ObjectApplyMatches.php @@ -132,7 +132,7 @@ abstract class ObjectApplyMatches } $flat = $object->toPlainObject(true, false); - static::flattenVars($object); + static::flattenVars($flat); $objects[$object->getObjectName()] = $flat; } Benchmark::measure("ObjectApplyMatches: $type cache ready"); diff --git a/library/Director/Web/Widget/DeployedConfigInfoHeader.php b/library/Director/Web/Widget/DeployedConfigInfoHeader.php index f80a0d6b..96f2d674 100644 --- a/library/Director/Web/Widget/DeployedConfigInfoHeader.php +++ b/library/Director/Web/Widget/DeployedConfigInfoHeader.php @@ -3,7 +3,7 @@ namespace Icinga\Module\Director\Web\Widget; use dipl\Html\HtmlDocument; -use Icinga\Module\Director\Core\CoreApi; +use Icinga\Module\Director\Core\DeploymentApiInterface; use Icinga\Module\Director\Db; use Icinga\Module\Director\Forms\DeployConfigForm; use Icinga\Module\Director\IcingaConfig\IcingaConfig; @@ -25,13 +25,13 @@ class DeployedConfigInfoHeader extends HtmlDocument /** @var Db */ protected $db; - /** @var CoreApi */ + /** @var DeploymentApiInterface */ protected $api; public function __construct( IcingaConfig $config, Db $db, - CoreApi $api, + DeploymentApiInterface $api, $deploymentId = null ) { $this->config = $config;