summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaushik Lingarkar <kaushikl@qti.qualcomm.com>2025-11-11 15:52:55 -0800
committerKaushik Lingarkar <kaushikl@qti.qualcomm.com>2025-11-12 13:23:01 -0800
commit309e8c8861abd2324693a2a504d157b08926c6e1 (patch)
tree4d2ff2b3c30470c53e53a09a4ed8ecd70c58f7ac
parente085e360715fc0701441b1cb0ed42e5caf2ba134 (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
-rw-r--r--Documentation/cmd-migrate-externalids-to-insensitive.txt8
-rw-r--r--java/com/google/gerrit/server/account/externalids/storage/notedb/OnlineExternalIdCaseSensitivityMigrator.java6
-rw-r--r--java/com/google/gerrit/sshd/commands/ExternalIdCaseSensitivityMigrationCommand.java9
-rw-r--r--javatests/com/google/gerrit/acceptance/server/account/externalids/OnlineExternalIdCaseSensitivityMigratorIT.java59
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();