From 4d050834db5461651f631ad39b3cd0ccbe051186 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 21 Sep 2023 14:02:52 +0200 Subject: [PATCH] IcingaConfig: render host templates to all... ...non-global zones, instead of the default global zone refs #2410 --- doc/82-Changelog.md | 1 + .../Director/IcingaConfig/IcingaConfig.php | 12 ++++++ library/Director/Objects/IcingaHost.php | 14 +++++++ library/Director/Objects/IcingaObject.php | 41 ++++++++++++++++--- library/Director/Objects/IcingaService.php | 18 +++++++- library/Director/Objects/IcingaServiceSet.php | 7 ++-- .../Director/Objects/IcingaHostTest.php | 8 +++- 7 files changed, 90 insertions(+), 11 deletions(-) diff --git a/doc/82-Changelog.md b/doc/82-Changelog.md index 014191c68..c1b903b29 100644 --- a/doc/82-Changelog.md +++ b/doc/82-Changelog.md @@ -26,6 +26,7 @@ This version hasn't been released yet ### Icinga Configuration * FEATURE: render fallback template for IfW 1.11 for Icinga < 2.14 (#2776) +* FEATURE: render host templates to all non-global zones per default (#2410) * FIX: render Set Services to individual zones where required (#1589, #2356) * FIX: special characters like & and | caused trouble in filters (#2667) diff --git a/library/Director/IcingaConfig/IcingaConfig.php b/library/Director/IcingaConfig/IcingaConfig.php index 93cfff5a7..a003eafb4 100644 --- a/library/Director/IcingaConfig/IcingaConfig.php +++ b/library/Director/IcingaConfig/IcingaConfig.php @@ -25,6 +25,9 @@ class IcingaConfig protected $zoneMap = array(); + /** @var ?array Exists for caching reasons at rendering time */ + protected $nonGlobalZones = null; + protected $lastActivityChecksum; /** @var \Zend_Db_Adapter_Abstract */ @@ -349,6 +352,15 @@ public function getZoneName($id) return $this->zoneMap[$id]; } + public function listNonGlobalZones(): array + { + if ($this->nonGlobalZones === null) { + $this->nonGlobalZones = array_values($this->connection->enumNonglobalZones()); + } + + return $this->nonGlobalZones; + } + /** * @return self */ diff --git a/library/Director/Objects/IcingaHost.php b/library/Director/Objects/IcingaHost.php index 4ad2334e8..7859324f3 100644 --- a/library/Director/Objects/IcingaHost.php +++ b/library/Director/Objects/IcingaHost.php @@ -309,6 +309,20 @@ public function getUniqueIdentifier() } } + protected function rendersConditionalTemplate(): bool + { + return $this->getRenderingZone() === self::ALL_NON_GLOBAL_ZONES; + } + + protected function getDefaultZone(IcingaConfig $config = null) + { + if ($this->isTemplate()) { + return self::ALL_NON_GLOBAL_ZONES; + } + + return parent::getDefaultZone(); + } + public function beforeDelete() { foreach ($this->fetchServices() as $service) { diff --git a/library/Director/Objects/IcingaObject.php b/library/Director/Objects/IcingaObject.php index 869ac2cde..3b6236dbb 100644 --- a/library/Director/Objects/IcingaObject.php +++ b/library/Director/Objects/IcingaObject.php @@ -27,6 +27,7 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer { const RESOLVE_ERROR = '(unable to resolve)'; + const ALL_NON_GLOBAL_ZONES = '(all non-global zones)'; protected $keyName = 'object_name'; @@ -1800,9 +1801,21 @@ public function renderToConfig(IcingaConfig $config) return; } - $config->configFile( - 'zones.d/' . $this->getRenderingZone($config) . '/' . $this->getRenderingFilename() - )->addObject($this); + foreach ($this->getRenderingZones($config) as $zone) { + $config->configFile( + 'zones.d/' . $zone . '/' . $this->getRenderingFilename() + )->addObject($this); + } + } + + protected function getRenderingZones(IcingaConfig $config): array + { + $zone = $this->getRenderingZone($config); + if ($zone === self::ALL_NON_GLOBAL_ZONES) { + return $config->listNonGlobalZones(); + } + + return [$zone]; } public function getRenderingFilename() @@ -2181,7 +2194,12 @@ protected function renderPropertyAsSeconds($key) protected function renderSuffix() { - return "}\n\n"; + $prefix = ''; + if ($this->rendersConditionalTemplate()) { + $prefix = '} '; + } + + return "$prefix}\n\n"; } protected function renderLegacySuffix() @@ -2406,14 +2424,25 @@ protected function renderLegacyCustomExtensions() protected function renderObjectHeader() { + $prefix = ''; + $renderedName = c::renderString($this->getObjectName()); + if ($this->rendersConditionalTemplate()) { + $prefix = sprintf('if (! get_template(%s, %s)) { ', $this->getType(), $renderedName); + } return sprintf( - "%s %s %s {\n", + "%s%s %s %s {\n", + $prefix, $this->getObjectTypeName(), $this->getType(), - c::renderString($this->getObjectName()) + $renderedName ); } + protected function rendersConditionalTemplate(): bool + { + return false; + } + public function getLegacyObjectType() { return strtolower($this->getType()); diff --git a/library/Director/Objects/IcingaService.php b/library/Director/Objects/IcingaService.php index ba9a96955..cbf9ca528 100644 --- a/library/Director/Objects/IcingaService.php +++ b/library/Director/Objects/IcingaService.php @@ -384,6 +384,11 @@ protected function getLegacyObjectKeyName() } } + protected function rendersConditionalTemplate(): bool + { + return $this->getRenderingZone() === self::ALL_NON_GLOBAL_ZONES; + } + /** * @return bool */ @@ -578,11 +583,22 @@ public function getOnDeleteUrl() protected function getDefaultZone(IcingaConfig $config = null) { + // Hint: this isn't possible yet, as we're unable to render dependent apply rules to multiple zones as well + // if ($this->isTemplate()) { + // return self::ALL_NON_GLOBAL_ZONES; + // } if ($this->get('host_id') === null) { return parent::getDefaultZone(); } else { - return $this->getRelatedObject('host', $this->get('host_id')) + $zone = $this->getRelatedObject('host', $this->get('host_id')) ->getRenderingZone($config); + + // Hint: this avoids problems with host templates rendered to all non-global zones + if ($zone === self::ALL_NON_GLOBAL_ZONES) { + $zone = $this->connection->getDefaultGlobalZoneName(); + } + + return $zone; } } diff --git a/library/Director/Objects/IcingaServiceSet.php b/library/Director/Objects/IcingaServiceSet.php index bee8e4b42..d15bae974 100644 --- a/library/Director/Objects/IcingaServiceSet.php +++ b/library/Director/Objects/IcingaServiceSet.php @@ -264,9 +264,10 @@ public function renderToConfig(IcingaConfig $config) } $this->copyVarsToService($service); - $zone = $service->getRenderingZone($config); - $file = $this->getConfigFileWithHeader($config, $zone, $files); - $file->addObject($service); + foreach ($service->getRenderingZones($config) as $serviceZone) { + $file = $this->getConfigFileWithHeader($config, $serviceZone, $files); + $file->addObject($service); + } } if (empty($files)) { diff --git a/test/php/library/Director/Objects/IcingaHostTest.php b/test/php/library/Director/Objects/IcingaHostTest.php index 97dfcc033..0fed94720 100644 --- a/test/php/library/Director/Objects/IcingaHostTest.php +++ b/test/php/library/Director/Objects/IcingaHostTest.php @@ -396,10 +396,16 @@ public function testRendersToTheCorrectZone() $host->object_type = 'template'; $host->zone_id = null; + $zone = $this->newObject('zone', '___TEST___zone2'); + $zone->store($db); + $config = new IcingaConfig($db); $host->renderToConfig($config); $this->assertEquals( - array('zones.d/director-global/host_templates.conf'), + [ + 'zones.d/___TEST___zone/host_templates.conf', + 'zones.d/___TEST___zone2/host_templates.conf', + ], $config->getFileNames() ); }