From 5419d4428c86c488a43124f85e5407d7cbae6541 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 14 Apr 2024 15:17:47 +0200 Subject: Adding upstream version 1.11.1. Signed-off-by: Daniel Baumann --- library/Director/Objects/IcingaServiceSet.php | 280 +++++++++++++------------- 1 file changed, 143 insertions(+), 137 deletions(-) (limited to 'library/Director/Objects/IcingaServiceSet.php') diff --git a/library/Director/Objects/IcingaServiceSet.php b/library/Director/Objects/IcingaServiceSet.php index 8217a59..252c52a 100644 --- a/library/Director/Objects/IcingaServiceSet.php +++ b/library/Director/Objects/IcingaServiceSet.php @@ -5,16 +5,14 @@ namespace Icinga\Module\Director\Objects; use Exception; use Icinga\Data\Filter\Filter; use Icinga\Module\Director\Data\Db\ServiceSetQueryBuilder; -use Icinga\Module\Director\Db; use Icinga\Module\Director\Db\Cache\PrefetchCache; -use Icinga\Module\Director\Db\DbUtil; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; use Icinga\Module\Director\Exception\DuplicateKeyException; use Icinga\Module\Director\IcingaConfig\IcingaConfig; use Icinga\Module\Director\Resolver\HostServiceBlacklist; use InvalidArgumentException; use Ramsey\Uuid\Uuid; -use RuntimeException; +use stdClass; class IcingaServiceSet extends IcingaObject implements ExportInterface { @@ -46,6 +44,33 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface 'host' => 'IcingaHost', ); + /** @var IcingaService[] Cached services */ + protected $cachedServices = []; + + /** @var IcingaService[]|null */ + private $services; + + /** + * Set the services to be cached + * + * @param $services IcingaService[] + * @return void + */ + public function setCachedServices($services) + { + $this->cachedServices = $services; + } + + /** + * Get the cached services + * + * @return IcingaService[] + */ + public function getCachedServices() + { + return $this->cachedServices; + } + public function isDisabled() { return false; @@ -79,6 +104,61 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface } /** + * @param stdClass[] $services + * @return void + */ + public function setServices(array $services) + { + $existing = $this->getServices(); + $uuidMap = []; + foreach ($existing as $service) { + $uuidMap[$service->getUniqueId()->getBytes()] = $service; + } + $this->services = []; + foreach ($services as $service) { + if (isset($service->uuid)) { + $uuid = Uuid::fromString($service->uuid)->getBytes(); + $current = $uuidMap[$uuid] ?? IcingaService::create([], $this->connection); + } else { + if (! is_object($service)) { + var_dump($service); + exit; + } + $current = $existing[$service->object_name] ?? IcingaService::create([], $this->connection); + } + $current->setProperties((array) $service); + $this->services[] = $current; + } + } + + protected function storeRelatedServices() + { + if ($this->services === null) { + $cachedServices = $this->getCachedServices(); + if ($cachedServices) { + $this->services = $cachedServices; + } else { + return; + } + } + + $seen = []; + /** @var IcingaService $service */ + foreach ($this->services as $service) { + $seen[$service->getUniqueId()->getBytes()] = true; + $service->set('service_set_id', $this->get('id')); + $service->store(); + } + + foreach ($this->fetchServices() as $service) { + if (!isset($seen[$service->getUniqueId()->getBytes()])) { + $service->delete(); + } + } + } + + /** + * @deprecated * @return IcingaService[] * @throws \Icinga\Exception\NotFoundError */ @@ -126,129 +206,9 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface return $this->getObjectName(); } - /** - * @return object - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @throws \Icinga\Exception\NotFoundError - */ - public function export() - { - if ($this->get('host_id')) { - $result = $this->exportSetOnHost(); - } else { - $result = $this->exportTemplate(); - } - - unset($result->uuid); - return $result; - } - - protected function exportSetOnHost() - { - // TODO. - throw new RuntimeException('Not yet'); - } - - /** - * @return object - * @deprecated - * @throws \Icinga\Exception\NotFoundError - */ - protected function exportTemplate() - { - $props = $this->getProperties(); - unset($props['id'], $props['host_id']); - $props['services'] = []; - foreach ($this->getServiceObjects() as $serviceObject) { - $props['services'][$serviceObject->getObjectName()] = $serviceObject->export(); - } - ksort($props); - - return (object) $props; - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return IcingaServiceSet - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - $name = $properties['object_name']; - if (isset($properties['services'])) { - $services = $properties['services']; - unset($properties['services']); - } else { - $services = []; - } - - if ($properties['object_type'] !== 'template') { - throw new InvalidArgumentException(sprintf( - 'Can import only Templates, got "%s" for "%s"', - $properties['object_type'], - $name - )); - } - if ($replace && static::exists($name, $db)) { - $object = static::load($name, $db); - } elseif (static::exists($name, $db)) { - throw new DuplicateKeyException( - 'Service Set "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - $object->setProperties($properties); - - // This is not how other imports work, but here we need an ID - if (! $object->hasBeenLoadedFromDb()) { - $object->store(); - } - - $setId = $object->get('id'); - $sQuery = $db->getDbAdapter()->select()->from( - ['s' => 'icinga_service'], - 's.*' - )->where('service_set_id = ?', $setId); - $existingServices = IcingaService::loadAll($db, $sQuery, 'object_name'); - $serviceNames = []; - foreach ($services as $service) { - if (isset($service->fields)) { - unset($service->fields); - } - $name = $service->object_name; - $serviceNames[] = $name; - if (isset($existingServices[$name])) { - $existing = $existingServices[$name]; - $existing->setProperties((array) $service); - $existing->set('service_set_id', $setId); - if ($existing->hasBeenModified()) { - $existing->store(); - } - } else { - $new = IcingaService::create((array) $service, $db); - $new->set('service_set_id', $setId); - $new->store(); - } - } - - foreach ($existingServices as $existing) { - if (!in_array($existing->getObjectName(), $serviceNames)) { - $existing->delete(); - } - } - - return $object; - } - public function beforeDelete() { + $this->setCachedServices($this->getServices()); // check if this is a template, or directly assigned to a host if ($this->get('host_id') === null) { // find all host sets and delete them @@ -295,8 +255,8 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface */ public function renderToConfig(IcingaConfig $config) { - // always print the header, so you have minimal info present - $file = $this->getConfigFileWithHeader($config); + $files = []; + $zone = $this->getRenderingZone($config) ; if ($this->get('assign_filter') === null && $this->isTemplate()) { return; @@ -334,7 +294,15 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface } $this->copyVarsToService($service); - $file->addObject($service); + foreach ($service->getRenderingZones($config) as $serviceZone) { + $file = $this->getConfigFileWithHeader($config, $serviceZone, $files); + $file->addObject($service); + } + } + + if (empty($files)) { + // always print the header, so you have minimal info present + $this->getConfigFileWithHeader($config, $zone, $files); } } @@ -355,14 +323,18 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface return $lookup->getBlacklistedHostnamesForService($service); } - protected function getConfigFileWithHeader(IcingaConfig $config) + protected function getConfigFileWithHeader(IcingaConfig $config, $zone, &$files = []) { - $file = $config->configFile( - 'zones.d/' . $this->getRenderingZone($config) . '/servicesets' - ); + if (!isset($files[$zone])) { + $file = $config->configFile( + 'zones.d/' . $zone . '/servicesets' + ); - $file->addContent($this->getConfigHeaderComment($config)); - return $file; + $file->addContent($this->getConfigHeaderComment($config)); + $files[$zone] = $file; + } + + return $files[$zone]; } protected function getConfigHeaderComment(IcingaConfig $config) @@ -372,13 +344,13 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface if ($config->isLegacy()) { if ($assign !== null) { - return "## applied Service Set '${name}'\n\n"; + return "## applied Service Set '{$name}'\n\n"; } else { - return "## Service Set '${name}' on this host\n\n"; + return "## Service Set '{$name}' on this host\n\n"; } } else { $comment = [ - "Service Set: ${name}", + "Service Set: {$name}", ]; if (($host = $this->get('host')) !== null) { @@ -505,7 +477,23 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface /** * @return IcingaService[] */ - public function fetchServices() + public function getServices(): array + { + if ($this->services !== null) { + return $this->services; + } + + if ($this->hasBeenLoadedFromDb()) { + return $this->fetchServices(); + } + + return []; + } + + /** + * @return IcingaService[] + */ + public function fetchServices(): array { if ($store = self::$dbObjectStore) { $uuid = $store->getBranch()->getUuid(); @@ -569,6 +557,24 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface } } + public function onStore() + { + $this->storeRelatedServices(); + } + + public function hasBeenModified() + { + if ($this->services !== null) { + foreach ($this->services as $service) { + if ($service->hasBeenModified()) { + return true; + } + } + } + + return parent::hasBeenModified(); + } + public function toSingleIcingaConfig() { $config = parent::toSingleIcingaConfig(); -- cgit v1.2.3