From c586b2c194fae00f963e29b6f185023f089d21e8 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Mon, 18 Jul 2022 11:35:46 +0200 Subject: [PATCH] ObjectCommand, Exporter: hosts with services fixes #2565 --- library/Director/Cli/ObjectCommand.php | 26 +++++++-- library/Director/Data/Exporter.php | 75 ++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/library/Director/Cli/ObjectCommand.php b/library/Director/Cli/ObjectCommand.php index 27cbc73f..401757dc 100644 --- a/library/Director/Cli/ObjectCommand.php +++ b/library/Director/Cli/ObjectCommand.php @@ -7,6 +7,7 @@ use Icinga\Exception\MissingParameterException; use Icinga\Module\Director\Data\Db\DbObject; use Icinga\Module\Director\Data\Exporter; use Icinga\Module\Director\IcingaConfig\IcingaConfig; +use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaObject; use InvalidArgumentException; @@ -49,17 +50,32 @@ class ObjectCommand extends Command { $db = $this->db(); $object = $this->getObject(); - if ($this->params->shift('resolved')) { - $object = $object::fromPlainObject($object->toPlainObject(true), $db); + $exporter = new Exporter($db); + $resolve = (bool) $this->params->shift('resolved'); + $withServices = (bool) $this->params->get('with-services'); + if ($withServices) { + if (!$object instanceof IcingaHost) { + $this->fail('--with-services is available for Hosts only'); + } + $exporter->enableHostServices(); } + $exporter->resolveObjects($resolve); + $exporter->showDefaults($this->params->shift('no-defaults', false)); + if ($this->params->shift('json')) { - $noDefaults = $this->params->shift('no-defaults', false); - $data = $object->toPlainObject(false, $noDefaults); - echo $this->renderJson($data, !$this->params->shift('no-pretty')); + echo $this->renderJson($exporter->export($object), !$this->params->shift('no-pretty')); } else { $config = new IcingaConfig($db); + if ($resolve) { + $object = $object::fromPlainObject($object->toPlainObject(true, false, null, false), $db); + } $object->renderToConfig($config); + if ($withServices) { + foreach ($exporter->fetchServicesForHost($object) as $service) { + $service->renderToConfig($config); + } + } foreach ($config->getFiles() as $filename => $content) { printf("/** %s **/\n\n", $filename); echo $content; diff --git a/library/Director/Data/Exporter.php b/library/Director/Data/Exporter.php index cb944a2c..cad75eb3 100644 --- a/library/Director/Data/Exporter.php +++ b/library/Director/Data/Exporter.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Data; use gipfl\ZfDb\Adapter\Adapter; +use gipfl\ZfDb\Select; use Icinga\Module\Director\Data\Db\DbObject; use Icinga\Module\Director\Data\Db\DbObjectWithSettings; use Icinga\Module\Director\Db; @@ -11,13 +12,17 @@ use Icinga\Module\Director\Objects\DirectorDatalist; use Icinga\Module\Director\Objects\DirectorDatalistEntry; use Icinga\Module\Director\Objects\DirectorJob; use Icinga\Module\Director\Objects\IcingaCommand; +use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaObject; +use Icinga\Module\Director\Objects\IcingaService; use Icinga\Module\Director\Objects\IcingaServiceSet; use Icinga\Module\Director\Objects\IcingaTemplateChoice; use Icinga\Module\Director\Objects\ImportRowModifier; use Icinga\Module\Director\Objects\ImportSource; use Icinga\Module\Director\Objects\InstantiatedViaHook; use Icinga\Module\Director\Objects\SyncRule; +use Icinga\Module\Director\Web\Table\ObjectsTableService; +use Ramsey\Uuid\Uuid; use RuntimeException; class Exporter @@ -52,8 +57,21 @@ class Exporter /** @var FieldReferenceLoader */ protected $fieldReferenceLoader; + /** @var bool */ + protected $exportHostServices = false; + + protected $showDefaults = false; + + protected $resolveObjects = false; + + /** + * @var Db + */ + protected $connection; + public function __construct(Db $connection) { + $this->connection = $connection; $this->db = $connection->getDbAdapter(); $this->fieldReferenceLoader = new FieldReferenceLoader($connection); } @@ -71,6 +89,24 @@ class Exporter return (object) $props; } + public function enableHostServices($enable = true) + { + $this->exportHostServices = $enable; + return $this; + } + + public function showDefaults($show = true) + { + $this->showDefaults = $show; + return $this; + } + + public function resolveObjects($resolve = true) + { + $this->resolveObjects = $resolve; + return $this; + } + protected function appendTypeSpecificRelations(array &$props, DbObject $object) { if ($object instanceof DirectorDatalist) { @@ -120,9 +156,36 @@ class Exporter $props['services'][$serviceObject->getObjectName()] = $this->export($serviceObject); } ksort($props['services']); + } elseif ($object instanceof IcingaHost) { + if ($this->exportHostServices) { + $services = []; + foreach ($this->fetchServicesForHost($object) as $service) { + $services[] = $this->export($service); + } + + $props['services'] = $services; + } } } + public function fetchServicesForHost(IcingaHost $host) + { + $table = (new ObjectsTableService($this->connection))->setHost($host); + $query = $table->getQuery(); + $query->reset(Select::LIMIT_COUNT); + $query->reset(Select::LIMIT_OFFSET); + $services = []; + foreach ($this->db->fetchAll($query) as $row) { + $service = IcingaService::loadWithUniqueId(Uuid::fromBytes($row->uuid), $this->connection); + if ($this->resolveObjects) { + $service = $service::fromPlainObject($service->toPlainObject(true), $this->connection); + } + $services[] = $service; + } + + return $services; + } + protected function loadTemplateName($table, $id) { $db = $this->db; @@ -158,7 +221,6 @@ class Exporter unset($props[$key]); } } - } protected function exportRowModifiers(ImportSource $object) @@ -172,7 +234,6 @@ class Exporter return $modifiers; } - public function exportSyncProperties(SyncRule $object) { $all = []; @@ -208,6 +269,14 @@ class Exporter $props['settings'] = (object) $object->getSettings(); // Already sorted } } + if (! $this->showDefaults) { + foreach ($props as $key => $value) { + // We assume NULL as a default value for all non-IcingaObject properties + if ($value === null) { + unset($props[$key]); + } + } + } return $props; } @@ -219,7 +288,7 @@ class Exporter */ protected function exportIcingaObject(IcingaObject $object) { - $props = (array) $object->toPlainObject(); + $props = (array) $object->toPlainObject($this->resolveObjects, !$this->showDefaults); if ($object->supportsFields()) { $props['fields'] = $this->fieldReferenceLoader->loadFor($object); }