From 0dcb7636f651a1738bf17bf3c00bdf622b62832d Mon Sep 17 00:00:00 2001 From: raviks789 <33730024+raviks789@users.noreply.github.com> Date: Wed, 25 Oct 2023 14:54:50 +0200 Subject: [PATCH] ToicingadbCommand: Migrate legacy wildcard filters in Icinga DB Web actions --- .../clicommands/ToicingadbCommand.php | 243 +++++++++++++----- 1 file changed, 172 insertions(+), 71 deletions(-) diff --git a/modules/migrate/application/clicommands/ToicingadbCommand.php b/modules/migrate/application/clicommands/ToicingadbCommand.php index 3b25ef6a4f..b174d428c6 100644 --- a/modules/migrate/application/clicommands/ToicingadbCommand.php +++ b/modules/migrate/application/clicommands/ToicingadbCommand.php @@ -16,15 +16,28 @@ use Icinga\Web\Request; use ipl\Web\Filter\QueryString; use ipl\Web\Url; +use ipl\Stdlib\Filter; class ToicingadbCommand extends Command { public function init(): void { - if (! Icinga::app()->getModuleManager()->hasEnabled('icingadb')) { + $moduleManager = Icinga::app()->getModuleManager(); + if (! $moduleManager->hasEnabled('icingadb')) { Logger::error('Icinga DB module is not enabled. Please verify that the module is installed and enabled.'); exit; } + + $icingadbVersion = $moduleManager->getModule('icingadb')->getVersion(); + if (version_compare($icingadbVersion, '1.1.0', '<')) { + Logger::error( + 'Required Icinga DB Web version 1.1.0 or greater to run this migration. ' + . 'Please upgrade your Icinga DB Web module.' + ); + exit; + } + + Logger::getInstance()->setLevel(Logger::INFO); } /** @@ -69,19 +82,38 @@ public function navigationAction(): void $hostActions = $this->readFromIni($directory . '/host-actions.ini', $rc); $serviceActions = $this->readFromIni($directory . '/service-actions.ini', $rc); + $icingadbHostActions = $this->readFromIni($directory . '/icingadb-host-actions.ini', $rc); + $icingadbServiceActions = $this->readFromIni($directory . '/icingadb-service-actions.ini', $rc); + + Logger::info( + 'Transforming legacy wildcard filters of existing Icinga DB Web actions for user "%s"', + $username + ); + + if (! $icingadbServiceActions->isEmpty()) { + $this->migrateNavigationItems($icingadbHostActions, false, $rc); + } + + if (! $icingadbServiceActions->isEmpty()) { + $this->migrateNavigationItems( + $icingadbServiceActions, + false, + $rc + ); + } Logger::info('Migrating monitoring navigation items for user "%s" to the Icinga DB Web actions', $username); if (! $hostActions->isEmpty()) { - $this->migrateNavigationItems($hostActions, $directory . '/icingadb-host-actions.ini', false, $rc); + $this->migrateNavigationItems($hostActions, false, $rc, $directory . '/icingadb-host-actions.ini'); } if (! $serviceActions->isEmpty()) { $this->migrateNavigationItems( $serviceActions, - $directory . '/icingadb-service-actions.ini', false, - $rc + $rc, + $directory . '/icingadb-service-actions.ini' ); } } @@ -89,19 +121,35 @@ public function navigationAction(): void // Start migrating shared navigation items $hostActions = $this->readFromIni($sharedNavigation . '/host-actions.ini', $rc); $serviceActions = $this->readFromIni($sharedNavigation . '/service-actions.ini', $rc); + $icingadbHostActions = $this->readFromIni($sharedNavigation . '/icingadb-host-actions.ini', $rc); + $icingadbServiceActions = $this->readFromIni($sharedNavigation . '/icingadb-service-actions.ini', $rc); + + Logger::info('Transforming legacy wildcard filters of existing shared Icinga DB Web actions'); + + if (! $icingadbServiceActions->isEmpty()) { + $this->migrateNavigationItems($icingadbHostActions, true, $rc); + } + + if (! $icingadbServiceActions->isEmpty()) { + $this->migrateNavigationItems( + $icingadbServiceActions, + true, + $rc + ); + } Logger::info('Migrating shared monitoring navigation items to the Icinga DB Web actions'); if (! $hostActions->isEmpty()) { - $this->migrateNavigationItems($hostActions, $sharedNavigation . '/icingadb-host-actions.ini', true, $rc); + $this->migrateNavigationItems($hostActions, true, $rc, $sharedNavigation . '/icingadb-host-actions.ini'); } if (! $serviceActions->isEmpty()) { $this->migrateNavigationItems( $serviceActions, - $sharedNavigation . '/icingadb-service-actions.ini', true, - $rc + $rc, + $sharedNavigation . '/icingadb-service-actions.ini' ); } @@ -117,89 +165,113 @@ public function navigationAction(): void * Migrate the given config to the given new config path * * @param Config $config - * @param string $path + * @param ?string $path * @param bool $shared * @param int $rc */ - private function migrateNavigationItems($config, $path, $shared, &$rc): void + private function migrateNavigationItems($config, $shared, &$rc, $path = null): void { - $deleteLegacyFiles = $this->params->get('delete'); - $override = $this->params->get('override'); - $newConfig = $this->readFromIni($path, $rc); - - /** @var ConfigObject $configObject */ - foreach ($config->getConfigObject() as $configObject) { - // Change the config type from "host-action" to icingadb's new action - if (strpos($path, 'icingadb-host-actions') !== false) { - $configObject->type = 'icingadb-host-action'; - } else { - $configObject->type = 'icingadb-service-action'; - } - - /** @var ?string $urlString */ - $urlString = $configObject->get('url'); - if ($urlString !== null) { - $url = Url::fromPath($urlString, [], new Request()); - - try { - $urlString = UrlMigrator::transformUrl($url)->getAbsoluteUrl(); - $configObject->url = rawurldecode($urlString); - } catch (\InvalidArgumentException $err) { - // Do nothing + if ($path === null) { + $newConfig = $config; + /** @var ConfigObject $newConfigObject */ + foreach ($newConfig->getConfigObject() as $section => $newConfigObject) { + /** @var ?string $legacyFilter */ + $legacyFilter = $newConfigObject->get('filter'); + if ($legacyFilter !== null) { + $filter = QueryString::parse($legacyFilter); + $filter = $this->transformLegacyWildcardFilter($filter); + if ($filter) { + $filter = rawurldecode(QueryString::render($filter)); + $newConfigObject->filter = $filter; + $newConfig->setSection($section, $newConfigObject); + Logger::info( + 'Wildcard filter "%s" of Icinga DB Web action "%s" is transformed to "%s"', + $legacyFilter, + $section, + $filter + ); + } } } - - /** @var ?string $legacyFilter */ - $legacyFilter = $configObject->get('filter'); - if ($legacyFilter !== null) { - $filter = QueryString::parse($legacyFilter); - $filter = UrlMigrator::transformFilter($filter); - if ($filter !== false) { - $configObject->filter = rawurldecode(QueryString::render($filter)); + } else { + $deleteLegacyFiles = $this->params->get('delete'); + $override = $this->params->get('override'); + $newConfig = $this->readFromIni($path, $rc); + + /** @var ConfigObject $configObject */ + foreach ($config->getConfigObject() as $configObject) { + // Change the config type from "host-action" to icingadb's new action + if (strpos($path, 'icingadb-host-actions') !== false) { + $configObject->type = 'icingadb-host-action'; } else { - unset($configObject->filter); + $configObject->type = 'icingadb-service-action'; + } + + /** @var ?string $urlString */ + $urlString = $configObject->get('url'); + if ($urlString !== null) { + $url = Url::fromPath($urlString, [], new Request()); + + try { + $urlString = UrlMigrator::transformUrl($url)->getAbsoluteUrl(); + $configObject->url = rawurldecode($urlString); + } catch (\InvalidArgumentException $err) { + // Do nothing + } } - } - $section = $config->key(); - - if (! $newConfig->hasSection($section) || $override) { - /** @var string $owner */ - $owner = $configObject->get('owner'); - /** @var string $type */ - $type = $configObject->get('type'); - $oldPath = $shared - ? sprintf( - '%s/%s/%ss.ini', - Config::resolvePath('preferences'), - $owner, - $type - ) - : sprintf( - '%s/%ss.ini', - Config::resolvePath('navigation'), - $type - ); - - $oldConfig = $this->readFromIni($oldPath, $rc); - - if ($override && $oldConfig->hasSection($section)) { - $oldConfig->removeSection($section); - $oldConfig->saveIni(); + /** @var ?string $legacyFilter */ + $legacyFilter = $configObject->get('filter'); + if ($legacyFilter !== null) { + $filter = QueryString::parse($legacyFilter); + $filter = UrlMigrator::transformFilter($filter); + if ($filter !== false) { + $configObject->filter = rawurldecode(QueryString::render($filter)); + } else { + unset($configObject->filter); + } } - if (! $oldConfig->hasSection($section)) { - $newConfig->setSection($section, $configObject); + $section = $config->key(); + + if (!$newConfig->hasSection($section) || $override) { + /** @var string $owner */ + $owner = $configObject->get('owner'); + /** @var string $type */ + $type = $configObject->get('type'); + $oldPath = $shared + ? sprintf( + '%s/%s/%ss.ini', + Config::resolvePath('preferences'), + $owner, + $type + ) + : sprintf( + '%s/%ss.ini', + Config::resolvePath('navigation'), + $type + ); + + $oldConfig = $this->readFromIni($oldPath, $rc); + + if ($override && $oldConfig->hasSection($section)) { + $oldConfig->removeSection($section); + $oldConfig->saveIni(); + } + + if (!$oldConfig->hasSection($section)) { + $newConfig->setSection($section, $configObject); + } } } } try { - if (! $newConfig->isEmpty()) { + if (!$newConfig->isEmpty()) { $newConfig->saveIni(); // Remove the legacy file only if explicitly requested - if ($deleteLegacyFiles) { + if ($path !== null && $deleteLegacyFiles) { unlink($config->getConfigFile()); } } @@ -234,4 +306,33 @@ private function readFromIni($path, &$rc) return $config; } + + /** + * Transform given legacy wirldcard filters + * + * @param $filter Filter\Rule + * + * @return Filter\Chain|Filter\Condition|null + */ + private function transformLegacyWildcardFilter(Filter\Rule $filter) + { + if ($filter instanceof Filter\Chain) { + foreach ($filter as $child) { + $newChild = $this->transformLegacyWildcardFilter($child); + if ($newChild !== null) { + $filter->replace($child, $newChild); + } + } + + return $filter; + } elseif ($filter instanceof Filter\Equal) { + if (is_string($filter->getValue()) && strpos($filter->getValue(), '*') !== false) { + return Filter::like($filter->getColumn(), $filter->getValue()); + } + } elseif ($filter instanceof Filter\Unequal) { + if (is_string($filter->getValue()) && strpos($filter->getValue(), '*') !== false) { + return Filter::unlike($filter->getColumn(), $filter->getValue()); + } + } + } }