Prevent replication plugin start with invalid remotes
Allow the Gerrit admin to detect early a configuration
issue with the remotes. Implement the credentials validation
as first step; more validations to follow.
Change-Id: I128422677f9fa9e70aae539ca7a591bddc07008e
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java
index 8e21a81..132fa4f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java
@@ -79,4 +79,9 @@
private boolean needsReload() {
return config.getConfig().getBoolean("gerrit", "autoReload", false) && secureStore.isOutdated();
}
+
+ @Override
+ public boolean validate(String remoteConfigName) {
+ return secureCredentialsFactory.get().validate(remoteConfigName);
+ }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/CredentialsFactory.java b/src/main/java/com/googlesource/gerrit/plugins/replication/CredentialsFactory.java
index 3bb64ab..141fb2d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/CredentialsFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/CredentialsFactory.java
@@ -18,4 +18,8 @@
public interface CredentialsFactory {
CredentialsProvider create(String remoteName);
+
+ default boolean validate(String remoteConfigName) {
+ return true;
+ }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
index 6054a4a..08ed7cb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
@@ -97,6 +97,8 @@
private static final String PROJECT_NOT_AVAILABLE = "source project %s not available";
+ private final CredentialsFactory credentialsFactory;
+
public interface Factory {
Destination create(DestinationConfiguration config);
}
@@ -149,6 +151,7 @@
GroupIncludeCache groupIncludeCache,
DynamicItem<EventDispatcher> eventDispatcher,
Provider<ReplicationTasksStorage> rts,
+ CredentialsFactory credentialsFactory,
@Assisted DestinationConfiguration cfg) {
this.eventDispatcher = eventDispatcher;
gitManager = gitRepositoryManager;
@@ -157,6 +160,7 @@
this.projectCache = projectCache;
this.stateLog = stateLog;
this.replicationTasksStorage = rts;
+ this.credentialsFactory = credentialsFactory;
config = cfg;
CurrentUser remoteUser;
if (!cfg.getAuthGroupNames().isEmpty()) {
@@ -216,6 +220,10 @@
threadScoper = child.getInstance(PerThreadRequestScope.Scoper.class);
}
+ public boolean validate() {
+ return (credentialsFactory == null || credentialsFactory.validate(getRemoteConfigName()));
+ }
+
private void addRecursiveParents(
AccountGroup.UUID g,
ImmutableSet.Builder<AccountGroup.UUID> builder,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationsCollection.java b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationsCollection.java
index 8a41945..dc3b05e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationsCollection.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationsCollection.java
@@ -180,6 +180,12 @@
public synchronized void startup(WorkQueue workQueue) {
shuttingDown = false;
for (Destination cfg : destinations) {
+ if (!cfg.validate()) {
+ throw new IllegalStateException(
+ "Unable to start replication plugin because remote "
+ + cfg.getRemoteConfigName()
+ + " is not valid");
+ }
cfg.start(workQueue);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java b/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java
index 210c4d8..957744e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.replication;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.server.securestore.SecureStore;
import com.google.inject.Inject;
import java.util.Objects;
@@ -22,6 +23,7 @@
/** Looks up a remote's password in SecureStore */
class SecureCredentialsFactory implements CredentialsFactory {
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final SecureStore secureStore;
@Inject
@@ -35,4 +37,17 @@
String pass = Objects.toString(secureStore.get("remote", remoteName, "password"), "");
return new UsernamePasswordCredentialsProvider(user, pass);
}
+
+ @Override
+ public boolean validate(String remoteName) {
+ try {
+ String unused = secureStore.get("remote", remoteName, "username");
+ unused = secureStore.get("remote", remoteName, "password");
+ return true;
+ } catch (Throwable t) {
+ log.atSevere().withCause(t).log(
+ "Credentials for replication remote %s are invalid", remoteName);
+ return false;
+ }
+ }
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/AbstractConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/AbstractConfigTest.java
index 9244f87..935fdb4 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/AbstractConfigTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/AbstractConfigTest.java
@@ -57,7 +57,8 @@
public final DestinationConfiguration config;
protected FakeDestination(DestinationConfiguration config) {
- super(injectorMock(), null, null, null, null, null, null, null, null, null, null, config);
+ super(
+ injectorMock(), null, null, null, null, null, null, null, null, null, null, null, config);
this.config = config;
}