Merge "Allow to run Gerrit in replica mode"
diff --git a/operator/README.md b/operator/README.md
index 6ea2313..beeb79a 100644
--- a/operator/README.md
+++ b/operator/README.md
@@ -331,6 +331,9 @@
## Port used for SSH requests (optional; if unset, SSH access is disabled)
sshPort: null
+ ## Whether to run Gerrit in replica mode
+ isReplica: true
+
## Configuration concerning the Gerrit site
site:
## Size of the volume used to persist not otherwise persisted site components
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritConfigMapDependentResource.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritConfigMapDependentResource.java
index 26bbde2..829eab8 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritConfigMapDependentResource.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritConfigMapDependentResource.java
@@ -16,6 +16,7 @@
import com.google.gerrit.k8s.operator.cluster.GerritCluster;
import com.google.gerrit.k8s.operator.cluster.GerritIngress;
+import com.google.gerrit.k8s.operator.gerrit.GerritSpec.GerritMode;
import com.google.gerrit.k8s.operator.gerrit.config.GerritConfigBuilder;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
@@ -58,6 +59,8 @@
GerritConfigBuilder gerritConfigBuilder =
new GerritConfigBuilder().withConfig(configFiles.get("gerrit.config"));
+ gerritConfigBuilder.useReplicaMode(gerrit.getSpec().getMode().equals(GerritMode.REPLICA));
+
if (gerritCluster.getSpec().getIngress().isEnabled()) {
gerritConfigBuilder.withUrl(
GerritIngress.getFullHostname(ServiceDependentResource.getName(gerrit), gerritCluster));
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritSpec.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritSpec.java
index dbda4af..56643b8 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritSpec.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/GerritSpec.java
@@ -48,6 +48,7 @@
private List<GerritPlugin> plugins = List.of();
private Map<String, String> configFiles = Map.of();
private Set<String> secrets = Set.of();
+ private GerritMode mode = GerritMode.PRIMARY;
public String getCluster() {
return cluster;
@@ -185,4 +186,17 @@
public void setSecrets(Set<String> secrets) {
this.secrets = secrets;
}
+
+ public GerritMode getMode() {
+ return mode;
+ }
+
+ public void setMode(GerritMode mode) {
+ this.mode = mode;
+ }
+
+ public enum GerritMode {
+ PRIMARY,
+ REPLICA
+ }
}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilder.java b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilder.java
index ceb8f00..a35fe83 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilder.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/gerrit/config/GerritConfigBuilder.java
@@ -62,6 +62,11 @@
return this;
}
+ public GerritConfigBuilder useReplicaMode(boolean isReplica) {
+ this.requiredOptions.add(new RequiredOption<Boolean>("container", "replica", isReplica));
+ return this;
+ }
+
public Config build() {
GerritConfigValidator configValidator = new GerritConfigValidator(requiredOptions);
configValidator.check(cfg);
diff --git a/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/GerritE2E.java b/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/GerritE2E.java
index 2e0b2f9..670368a 100644
--- a/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/GerritE2E.java
+++ b/operator/src/test/java/com/google/gerrit/k8s/operator/gerrit/GerritE2E.java
@@ -30,6 +30,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.k8s.operator.gerrit.GerritSpec.GerritMode;
import com.google.gerrit.k8s.operator.test.AbstractGerritOperatorE2ETest;
import com.urswolfer.gerrit.client.rest.GerritAuthData;
import com.urswolfer.gerrit.client.rest.GerritRestApiFactory;
@@ -84,78 +85,16 @@
+ " javaOptions = -Xmx4g";
@Test
- void testGerritStatefulSetCreated() throws Exception {
+ void testPrimaryGerritIsCreated() throws Exception {
gerritCluster.setIngressEnabled(true);
Secret secureConfig = createSecureConfig();
client.resource(secureConfig).createOrReplace();
- Gerrit gerrit = createGerritCR();
+ Gerrit gerrit = createGerritCR(GerritMode.PRIMARY);
client.resource(gerrit).createOrReplace();
- logger.atInfo().log("Waiting max 1 minutes for the configmaps to be created.");
- await()
- .atMost(1, MINUTES)
- .untilAsserted(
- () -> {
- assertThat(
- client
- .configMaps()
- .inNamespace(operator.getNamespace())
- .withName(GerritConfigMapDependentResource.getName(gerrit))
- .get(),
- is(notNullValue()));
- assertThat(
- client
- .configMaps()
- .inNamespace(operator.getNamespace())
- .withName(GerritInitConfigMapDependentResource.getName(gerrit))
- .get(),
- is(notNullValue()));
- });
-
- logger.atInfo().log("Waiting max 1 minutes for the Gerrit StatefulSet to be created.");
- await()
- .atMost(1, MINUTES)
- .untilAsserted(
- () -> {
- assertThat(
- client
- .apps()
- .statefulSets()
- .inNamespace(operator.getNamespace())
- .withName(gerrit.getMetadata().getName())
- .get(),
- is(notNullValue()));
- });
-
- logger.atInfo().log("Waiting max 1 minutes for the Gerrit Service to be created.");
- await()
- .atMost(1, MINUTES)
- .untilAsserted(
- () -> {
- assertThat(
- client
- .services()
- .inNamespace(operator.getNamespace())
- .withName(ServiceDependentResource.getName(gerrit))
- .get(),
- is(notNullValue()));
- });
-
- logger.atInfo().log("Waiting max 2 minutes for the Gerrit StatefulSet to be ready.");
- await()
- .atMost(2, MINUTES)
- .untilAsserted(
- () -> {
- assertTrue(
- client
- .apps()
- .statefulSets()
- .inNamespace(operator.getNamespace())
- .withName(gerrit.getMetadata().getName())
- .isReady());
- });
+ waitForGerritReadiness(gerrit);
logger.atInfo().log("Waiting max 2 minutes for the Ingress to have an external IP.");
await()
@@ -197,11 +136,31 @@
}
@Test
+ void testGerritReplicaIsCreated() throws Exception {
+ Secret secureConfig = createSecureConfig();
+ client.resource(secureConfig).createOrReplace();
+
+ Gerrit gerrit = createGerritCR(GerritMode.REPLICA);
+ client.resource(gerrit).createOrReplace();
+
+ waitForGerritReadiness(gerrit);
+
+ assertTrue(
+ client
+ .pods()
+ .inNamespace(operator.getNamespace())
+ .withName(gerrit.getMetadata().getName() + "-0")
+ .inContainer("gerrit")
+ .getLog()
+ .contains("Gerrit Code Review [replica]"));
+ }
+
+ @Test
void testRestartHandlingOnConfigChange() {
Secret secureConfig = createSecureConfig();
client.resource(secureConfig).createOrReplace();
- Gerrit gerrit = createGerritCR();
+ Gerrit gerrit = createGerritCR(GerritMode.PRIMARY);
client.resource(gerrit).createOrReplace();
logger.atInfo().log("Waiting max 2 minutes for the Gerrit StatefulSet to be ready.");
@@ -270,7 +229,7 @@
});
}
- private Gerrit createGerritCR() {
+ private Gerrit createGerritCR(GerritMode mode) {
Gerrit gerrit = new Gerrit();
ObjectMeta gerritMeta =
new ObjectMetaBuilder().withName("gerrit").withNamespace(operator.getNamespace()).build();
@@ -279,6 +238,7 @@
gerritSpec.setCluster(CLUSTER_NAME);
GerritSite site = new GerritSite();
site.setSize(new Quantity("1Gi"));
+ gerritSpec.setMode(mode);
gerritSpec.setSite(site);
gerritSpec.setResources(
new ResourceRequirementsBuilder()
@@ -306,4 +266,70 @@
.getBytes())))
.build();
}
+
+ private void waitForGerritReadiness(Gerrit gerrit) {
+ logger.atInfo().log("Waiting max 1 minutes for the configmaps to be created.");
+ await()
+ .atMost(1, MINUTES)
+ .untilAsserted(
+ () -> {
+ assertThat(
+ client
+ .configMaps()
+ .inNamespace(operator.getNamespace())
+ .withName(GerritConfigMapDependentResource.getName(gerrit))
+ .get(),
+ is(notNullValue()));
+ assertThat(
+ client
+ .configMaps()
+ .inNamespace(operator.getNamespace())
+ .withName(GerritInitConfigMapDependentResource.getName(gerrit))
+ .get(),
+ is(notNullValue()));
+ });
+
+ logger.atInfo().log("Waiting max 1 minutes for the Gerrit StatefulSet to be created.");
+ await()
+ .atMost(1, MINUTES)
+ .untilAsserted(
+ () -> {
+ assertThat(
+ client
+ .apps()
+ .statefulSets()
+ .inNamespace(operator.getNamespace())
+ .withName(gerrit.getMetadata().getName())
+ .get(),
+ is(notNullValue()));
+ });
+
+ logger.atInfo().log("Waiting max 1 minutes for the Gerrit Service to be created.");
+ await()
+ .atMost(1, MINUTES)
+ .untilAsserted(
+ () -> {
+ assertThat(
+ client
+ .services()
+ .inNamespace(operator.getNamespace())
+ .withName(ServiceDependentResource.getName(gerrit))
+ .get(),
+ is(notNullValue()));
+ });
+
+ logger.atInfo().log("Waiting max 2 minutes for the Gerrit StatefulSet to be ready.");
+ await()
+ .atMost(2, MINUTES)
+ .untilAsserted(
+ () -> {
+ assertTrue(
+ client
+ .apps()
+ .statefulSets()
+ .inNamespace(operator.getNamespace())
+ .withName(gerrit.getMetadata().getName())
+ .isReady());
+ });
+ }
}