summaryrefslogtreecommitdiffstats
path: root/modules/migrate/application
diff options
context:
space:
mode:
Diffstat (limited to 'modules/migrate/application')
-rw-r--r--modules/migrate/application/clicommands/ConfigCommand.php119
-rw-r--r--modules/migrate/application/clicommands/NavigationCommand.php20
-rw-r--r--modules/migrate/application/clicommands/PreferencesCommand.php131
3 files changed, 270 insertions, 0 deletions
diff --git a/modules/migrate/application/clicommands/ConfigCommand.php b/modules/migrate/application/clicommands/ConfigCommand.php
new file mode 100644
index 0000000..a5be144
--- /dev/null
+++ b/modules/migrate/application/clicommands/ConfigCommand.php
@@ -0,0 +1,119 @@
+<?php
+/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Migrate\Clicommands;
+
+use Icinga\Cli\Command;
+use Icinga\Module\Migrate\Config\UserDomainMigration;
+use Icinga\User;
+use Icinga\Util\StringHelper;
+
+class ConfigCommand extends Command
+{
+ /**
+ * Rename users and user configurations according to a given domain
+ *
+ * The following configurations are taken into account:
+ * - Announcements
+ * - Preferences
+ * - Dashboards
+ * - Custom navigation items
+ * - Role configuration
+ * - Users and group memberships in database backends, if configured
+ *
+ * USAGE:
+ *
+ * icingacli migrate config users [options]
+ *
+ * OPTIONS:
+ *
+ * --to-domain=<to-domain> The new domain for the users
+ *
+ * --from-domain=<from-domain> Migrate only the users with the given domain.
+ * Use this switch in combination with --to-domain.
+ *
+ * --user=<user> Migrate only the given user in the format <user> or <user@domain>
+ *
+ * --map-file=<mapfile> File to use for renaming users
+ *
+ * --separator=<separator> Separator for the map file
+ *
+ * EXAMPLES:
+ *
+ * icingacli migrate config users ...
+ *
+ * Add the domain "icinga.com" to all users:
+ *
+ * --to-domain icinga.com
+ *
+ * Set the domain "example.com" on all users that have the domain "icinga.com":
+ *
+ * --to-domain example.com --from-domain icinga.com
+ *
+ * Set the domain "icinga.com" on the user "icingaadmin":
+ *
+ * --to-domain icinga.com --user icingaadmin
+ *
+ * Set the domain "icinga.com" on the users "icingaadmin@icinga.com"
+ *
+ * --to-domain example.com --user icingaadmin@icinga.com
+ *
+ * Rename users according to a map file:
+ *
+ * --map-file /path/to/mapfile --separator :
+ *
+ * MAPFILE:
+ *
+ * You may rename users according to a given map file. The map file must be separated by newlines. Each line then
+ * is specified in the format <from><separator><to>. The separator is specified with the --separator switch.
+ *
+ * Example content:
+ *
+ * icingaadmin:icingaadmin@icinga.com
+ * jdoe@example.com:jdoe@icinga.com
+ * rroe@icinga:rroe@icinga.com
+ */
+ public function usersAction()
+ {
+ if ($this->params->has('map-file')) {
+ $mapFile = $this->params->get('map-file');
+ $separator = $this->params->getRequired('separator');
+
+ $source = trim(file_get_contents($mapFile));
+ $source = StringHelper::trimSplit($source, "\n");
+
+ $map = array();
+
+ array_walk($source, function ($item) use ($separator, &$map) {
+ list($from, $to) = StringHelper::trimSplit($item, $separator, 2);
+ $map[$from] = $to;
+ });
+
+ $migration = UserDomainMigration::fromMap($map);
+ } else {
+ $toDomain = $this->params->getRequired('to-domain');
+ $fromDomain = $this->params->get('from-domain');
+ $user = $this->params->get('user');
+
+ if ($user === null) {
+ $migration = UserDomainMigration::fromDomains($toDomain, $fromDomain);
+ } else {
+ if ($fromDomain !== null) {
+ $this->fail(
+ "Ambiguous arguments: Can't use --user in combination with --from-domain."
+ . " Please use the user@domain syntax for the --user switch instead."
+ );
+ }
+
+ $user = new User($user);
+
+ $migrated = clone $user;
+ $migrated->setDomain($toDomain);
+
+ $migration = UserDomainMigration::fromMap(array($user->getUsername() => $migrated->getUsername()));
+ }
+ }
+
+ $migration->migrate();
+ }
+}
diff --git a/modules/migrate/application/clicommands/NavigationCommand.php b/modules/migrate/application/clicommands/NavigationCommand.php
new file mode 100644
index 0000000..28ae8a1
--- /dev/null
+++ b/modules/migrate/application/clicommands/NavigationCommand.php
@@ -0,0 +1,20 @@
+<?php
+
+/* Icinga Web 2 | (c) 2021 Icinga GmbH | GPLv2+ */
+
+namespace Icinga\Module\Migrate\Clicommands;
+
+use Icinga\Application\Logger;
+use Icinga\Cli\Command;
+
+class NavigationCommand extends Command
+{
+ /**
+ * Deprecated. Use `icingacli icingadb migrate navigation` instead.
+ */
+ public function indexAction(): void
+ {
+ Logger::error('Deprecated. Use `icingacli icingadb migrate navigation` instead.');
+ exit(1);
+ }
+}
diff --git a/modules/migrate/application/clicommands/PreferencesCommand.php b/modules/migrate/application/clicommands/PreferencesCommand.php
new file mode 100644
index 0000000..11d1edb
--- /dev/null
+++ b/modules/migrate/application/clicommands/PreferencesCommand.php
@@ -0,0 +1,131 @@
+<?php
+/* Icinga Web 2 | (c) 2021 Icinga GmbH | GPLv2+ */
+
+namespace Icinga\Module\Migrate\Clicommands;
+
+use Icinga\Application\Config;
+use Icinga\Application\Logger;
+use Icinga\Cli\Command;
+use Icinga\Data\ConfigObject;
+use Icinga\Data\ResourceFactory;
+use Icinga\Exception\NotReadableError;
+use Icinga\Exception\NotWritableError;
+use Icinga\File\Ini\IniParser;
+use Icinga\User;
+use Icinga\User\Preferences\PreferencesStore;
+use Icinga\Util\DirectoryIterator;
+
+class PreferencesCommand extends Command
+{
+ /**
+ * Migrate local INI user preferences to a database
+ *
+ * USAGE
+ *
+ * icingacli migrate preferences [options]
+ *
+ * OPTIONS:
+ *
+ * --resource=<resource-name> The resource to use, if no current database config backend is configured.
+ * --no-set-config-backend Do not set the given resource as config backend automatically
+ */
+ public function indexAction()
+ {
+ $resource = Config::app()->get('global', 'config_resource');
+ if (empty($resource)) {
+ $resource = $this->params->getRequired('resource');
+ }
+
+ $resourceConfig = ResourceFactory::getResourceConfig($resource);
+ if ($resourceConfig->db === 'mysql') {
+ $resourceConfig->charset = 'utf8mb4';
+ }
+
+ $connection = ResourceFactory::createResource($resourceConfig);
+
+ $preferencesPath = Config::resolvePath('preferences');
+ if (! file_exists($preferencesPath)) {
+ Logger::info('There are no local user preferences to migrate');
+ return;
+ }
+
+ $rc = 0;
+
+ $preferenceDirs = new DirectoryIterator($preferencesPath);
+ foreach ($preferenceDirs as $preferenceDir) {
+ if (! is_dir($preferenceDir)) {
+ continue;
+ }
+
+ $userName = basename($preferenceDir);
+
+ Logger::info('Migrating INI preferences for user "%s" to database...', $userName);
+
+ $dbStore = new PreferencesStore(new ConfigObject(['connection' => $connection]), new User($userName));
+
+ try {
+ $dbStore->load();
+ $dbStore->save(
+ new User\Preferences(
+ $this->loadIniFile($preferencesPath, (new User($userName))->getUsername())
+ )
+ );
+ } catch (NotReadableError $e) {
+ if ($e->getPrevious() !== null) {
+ Logger::error('%s: %s', $e->getMessage(), $e->getPrevious()->getMessage());
+ } else {
+ Logger::error($e->getMessage());
+ }
+
+ $rc = 128;
+ } catch (NotWritableError $e) {
+ Logger::error('%s: %s', $e->getMessage(), $e->getPrevious()->getMessage());
+ $rc = 256;
+ }
+ }
+
+ if ($rc > 0) {
+ Logger::error('Failed to migrate some user preferences');
+ exit($rc);
+ }
+
+ if ($this->params->has('resource') && ! $this->params->has('no-set-config-backend')) {
+ $appConfig = Config::app();
+ $globalConfig = $appConfig->getSection('global');
+ $globalConfig['config_resource'] = $resource;
+
+ try {
+ $appConfig->saveIni();
+ } catch (NotWritableError $e) {
+ Logger::error('Failed to update general configuration: %s', $e->getMessage());
+ exit(256);
+ }
+ }
+
+ Logger::info('Successfully migrated all local user preferences to database');
+ }
+
+ private function loadIniFile(string $filePath, string $username): array
+ {
+ $preferences = [];
+ $preferencesFile = sprintf(
+ '%s/%s/config.ini',
+ $filePath,
+ strtolower($username)
+ );
+
+ if (file_exists($preferencesFile)) {
+ if (! is_readable($preferencesFile)) {
+ throw new NotReadableError(
+ 'Preferences INI file %s for user %s is not readable',
+ $preferencesFile,
+ $username
+ );
+ } else {
+ $preferences = IniParser::parseIniFile($preferencesFile)->toArray();
+ }
+ }
+
+ return $preferences;
+ }
+}