diff options
| author | Kaushik Lingarkar <kaushikl@qti.qualcomm.com> | 2025-11-11 15:52:55 -0800 |
|---|---|---|
| committer | Kaushik Lingarkar <kaushikl@qti.qualcomm.com> | 2025-11-12 13:23:01 -0800 |
| commit | 309e8c8861abd2324693a2a504d157b08926c6e1 (patch) | |
| tree | 4d2ff2b3c30470c53e53a09a4ed8ecd70c58f7ac | |
| parent | e085e360715fc0701441b1cb0ed42e5caf2ba134 (diff) | |
Add option to preserve migration mode during online external-ids migrationupstream/stable-3.10
Introduce a `--preserve-migration-mode` flag to the SSH command
`migrate-externalids-to-insensitive`. When enabled, this option skips
setting `auth.userNameCaseInsensitiveMigrationMode` to `false` after the
migration completes.
This change allows admins of multi-primary and/or IaC environments to
update the configuration across all primaries and/or with tooling like
Chef/Ansible after migration, rather than having it modified
automatically by the command on one primary.
Release-Notes: Add --preserve-migration-mode option to online external-ids migration
Change-Id: I3d6915e36b878b5c353d78045a99459b669c3814
4 files changed, 72 insertions, 10 deletions
diff --git a/Documentation/cmd-migrate-externalids-to-insensitive.txt b/Documentation/cmd-migrate-externalids-to-insensitive.txt index b0230894ec..6458303f34 100644 --- a/Documentation/cmd-migrate-externalids-to-insensitive.txt +++ b/Documentation/cmd-migrate-externalids-to-insensitive.txt @@ -7,6 +7,7 @@ gerrit migrate-externalids-to-insensitive - Migrate external-ids to case insensi [verse] -- _ssh_ -p <port> <host> _gerrit migrate-externalids-to-insensitive_ + [--preserve-migration-mode] -- == DESCRIPTION @@ -29,6 +30,13 @@ Caller must be a member of the privileged 'Administrators' group. == SCRIPTING This command is intended to be used in scripts. +== OPTIONS +--preserve-migration-mode:: + Skip setting `auth.userNameCaseInsensitiveMigrationMode` to `false` after the + migration completes successfully. This option is useful in multi-primary and + IaC setups where admins may prefer to update the migration mode config on all + primaries and/or using IaC tooling after the migration completes. + == EXAMPLES Start the online external ids migration: diff --git a/java/com/google/gerrit/server/account/externalids/storage/notedb/OnlineExternalIdCaseSensitivityMigrator.java b/java/com/google/gerrit/server/account/externalids/storage/notedb/OnlineExternalIdCaseSensitivityMigrator.java index f72cfa937c..e4416811a5 100644 --- a/java/com/google/gerrit/server/account/externalids/storage/notedb/OnlineExternalIdCaseSensitivityMigrator.java +++ b/java/com/google/gerrit/server/account/externalids/storage/notedb/OnlineExternalIdCaseSensitivityMigrator.java @@ -70,7 +70,7 @@ public class OnlineExternalIdCaseSensitivityMigrator { globalConfig.getBoolean("auth", "userNameCaseInsensitive", false); } - public void migrate() { + public void migrate(boolean preserveMigrationMode) { if (!isUserNameCaseInsensitive || !isUserNameCaseInsensitiveMigrationMode) { logger.atSevere().log( "External IDs online migration requires auth.userNameCaseInsensitive and" @@ -91,7 +91,9 @@ public class OnlineExternalIdCaseSensitivityMigrator { monitor.endTask(); } try { - updateGerritConfig(); + if (!preserveMigrationMode) { + updateGerritConfig(); + } monitor.beginTask("Reindex accounts", ProgressMonitor.UNKNOWN); @SuppressWarnings("unused") diff --git a/java/com/google/gerrit/sshd/commands/ExternalIdCaseSensitivityMigrationCommand.java b/java/com/google/gerrit/sshd/commands/ExternalIdCaseSensitivityMigrationCommand.java index 5c38dd72be..0fded1b09b 100644 --- a/java/com/google/gerrit/sshd/commands/ExternalIdCaseSensitivityMigrationCommand.java +++ b/java/com/google/gerrit/sshd/commands/ExternalIdCaseSensitivityMigrationCommand.java @@ -22,12 +22,19 @@ import com.google.gerrit.sshd.CommandMetaData; import com.google.gerrit.sshd.SshCommand; import com.google.inject.Inject; import org.eclipse.jgit.lib.Config; +import org.kohsuke.args4j.Option; @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) @CommandMetaData( name = "migrate-externalids-to-insensitive", description = "Migrate external-ids to case insensitive") public class ExternalIdCaseSensitivityMigrationCommand extends SshCommand { + @Option( + name = "--preserve-migration-mode", + usage = + "Skip setting auth.userNameCaseInsensitiveMigrationMode " + + "to false after the migration finishes successfully.") + private boolean preserveMigrationMode; @Inject OnlineExternalIdCaseSensitivityMigrator onlineExternalIdCaseSensitivityMigrator; @Inject @GerritServerConfig private Config globalConfig; @@ -45,7 +52,7 @@ public class ExternalIdCaseSensitivityMigrationCommand extends SshCommand { + " auth.userNameCaseInsensitiveMigrationMode to be set to true. Cannot start" + " migration!"); } - onlineExternalIdCaseSensitivityMigrator.migrate(); + onlineExternalIdCaseSensitivityMigrator.migrate(preserveMigrationMode); stdout.println( "External ids case insensitivity migration started. To check if it's completed look for" + " \"External IDs migration completed!\" message in the Gerrit server logs"); diff --git a/javatests/com/google/gerrit/acceptance/server/account/externalids/OnlineExternalIdCaseSensitivityMigratorIT.java b/javatests/com/google/gerrit/acceptance/server/account/externalids/OnlineExternalIdCaseSensitivityMigratorIT.java index 987965712c..3fb9d4ea58 100644 --- a/javatests/com/google/gerrit/acceptance/server/account/externalids/OnlineExternalIdCaseSensitivityMigratorIT.java +++ b/javatests/com/google/gerrit/acceptance/server/account/externalids/OnlineExternalIdCaseSensitivityMigratorIT.java @@ -31,6 +31,7 @@ import com.google.gerrit.server.account.externalids.OnlineExternalIdCaseSensitiv import com.google.gerrit.server.account.externalids.storage.notedb.ExternalIdCaseSensitivityMigrator; import com.google.gerrit.server.account.externalids.storage.notedb.ExternalIdNotes; import com.google.gerrit.server.account.externalids.storage.notedb.OnlineExternalIdCaseSensitivityMigrator; +import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.git.meta.MetaDataUpdate; import com.google.inject.AbstractModule; import com.google.inject.Inject; @@ -42,6 +43,8 @@ import java.util.concurrent.ExecutorService; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.eclipse.jgit.util.FS; import org.junit.Test; public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTest { @@ -52,6 +55,7 @@ public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTes @Inject private ExternalIdKeyFactory externalIdKeyFactory; @Inject private ExternalIdFactory externalIdFactory; @Inject private OnlineExternalIdCaseSensitivityMigrator objectUnderTest; + @Inject private SitePaths sitePaths; @Override public Module createModule() { @@ -85,7 +89,7 @@ public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTes assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "JonDoe").isPresent()).isTrue(); assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "jondoe").isPresent()).isFalse(); - objectUnderTest.migrate(); + objectUnderTest.migrate(false); extIdNotes = externalIdNotesFactory.load(allUsersRepo); assertThat(getExactExternalId(extIdNotes, SCHEME_GERRIT, "JonDoe").isPresent()).isFalse(); @@ -93,6 +97,47 @@ public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTes assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "JonDoe").isPresent()).isFalse(); assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "jondoe").isPresent()).isTrue(); + + FileBasedConfig cfg = new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.detect()); + cfg.load(); + assertThat(cfg.getBoolean("auth", null, "userNameCaseInsensitiveMigrationMode", true)) + .isFalse(); + } + } + + @Test + @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true") + @GerritConfig(name = "auth.userNameCaseInsensitiveMigrationMode", value = "true") + public void shouldMigrateExternalIdWithPreserveMigrationMode() + throws IOException, ConfigInvalidException { + try (Repository allUsersRepo = repoManager.openRepository(allUsers); + MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) { + ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo); + + createExternalId( + md, extIdNotes, SCHEME_GERRIT, "JonDoe", accountId, isUserNameCaseInsensitive); + createExternalId( + md, extIdNotes, SCHEME_USERNAME, "JonDoe", accountId, isUserNameCaseInsensitive); + + assertThat(getExactExternalId(extIdNotes, SCHEME_GERRIT, "JonDoe").isPresent()).isTrue(); + assertThat(getExactExternalId(extIdNotes, SCHEME_GERRIT, "jondoe").isPresent()).isFalse(); + + assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "JonDoe").isPresent()).isTrue(); + assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "jondoe").isPresent()).isFalse(); + + objectUnderTest.migrate(true); + + extIdNotes = externalIdNotesFactory.load(allUsersRepo); + assertThat(getExactExternalId(extIdNotes, SCHEME_GERRIT, "JonDoe").isPresent()).isFalse(); + assertThat(getExactExternalId(extIdNotes, SCHEME_GERRIT, "jondoe").isPresent()).isTrue(); + + assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "JonDoe").isPresent()).isFalse(); + assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "jondoe").isPresent()).isTrue(); + + FileBasedConfig cfg = new FileBasedConfig(sitePaths.gerrit_config.toFile(), FS.detect()); + cfg.load(); + assertThat(cfg.getBoolean("auth", null, "userNameCaseInsensitiveMigrationMode", true)) + .isTrue(); } } @@ -118,7 +163,7 @@ public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTes assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "JonDoe").isPresent()).isFalse(); assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "jondoe").isPresent()).isTrue(); - objectUnderTest.migrate(); + objectUnderTest.migrate(false); } } @@ -157,7 +202,7 @@ public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTes assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "JonDoe").get().email()) .isEqualTo("test@email.com"); - objectUnderTest.migrate(); + objectUnderTest.migrate(false); extIdNotes = externalIdNotesFactory.load(allUsersRepo); assertThat(getExactExternalId(extIdNotes, SCHEME_GERRIT, "JonDoe").isPresent()).isFalse(); @@ -187,7 +232,7 @@ public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTes assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "JonDoe").isPresent()).isTrue(); assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "jondoe").isPresent()).isFalse(); - objectUnderTest.migrate(); + objectUnderTest.migrate(false); extIdNotes = externalIdNotesFactory.load(allUsersRepo); assertThat( @@ -215,7 +260,7 @@ public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTes assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "JonDoe").isPresent()).isTrue(); assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "jondoe").isPresent()).isTrue(); - assertThrows(DuplicateExternalIdKeyException.class, () -> objectUnderTest.migrate()); + assertThrows(DuplicateExternalIdKeyException.class, () -> objectUnderTest.migrate(false)); } } @@ -235,7 +280,7 @@ public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTes assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "JonDoe").isPresent()).isTrue(); assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "jondoe").isPresent()).isFalse(); - objectUnderTest.migrate(); + objectUnderTest.migrate(false); extIdNotes = externalIdNotesFactory.load(allUsersRepo); @@ -257,7 +302,7 @@ public class OnlineExternalIdCaseSensitivityMigratorIT extends AbstractDaemonTes createExternalId( md, extIdNotes, SCHEME_USERNAME, "JonDoe", accountId, isUserNameCaseInsensitive); - objectUnderTest.migrate(); + objectUnderTest.migrate(false); extIdNotes = externalIdNotesFactory.load(allUsersRepo); assertThat(getExactExternalId(extIdNotes, SCHEME_USERNAME, "jondoe").isPresent()).isFalse(); |
