Merge branch 'stable-3.12' into stable-3.13 * stable-3.12: Reduce HTTP check internal to 1s in Docker tests Use healthcheck plugin for Docker tests Change-Id: I83572cf9efff6c0e08c2c1b6962f68354743e41a
diff --git a/BUILD b/BUILD index 3735cb3..4beff6e 100644 --- a/BUILD +++ b/BUILD
@@ -21,7 +21,6 @@ resources = glob(["src/main/resources/**/*"]), deps = [ ":global-refdb-neverlink", - "@auto-value//jar", "@failsafe//jar", "@jgroups-kubernetes//jar", "@jgroups//jar",
diff --git a/README.md b/README.md index fcf0566..11a33b2 100644 --- a/README.md +++ b/README.md
@@ -1,7 +1,7 @@ # Gerrit high-availability plugin -This plugin allows deploying a cluster of multiple Gerrit primaries -on the same data-center sharing the same Git repositories. +This plugin allows deploying a cluster of multiple Gerrit primary servers +in the same data-center sharing the same Git repositories. Requirements for the Gerrit primaries are: @@ -17,6 +17,18 @@ Refer to the [build instructions in the plugin documentation](src/main/resources/Documentation/build.md). +## Installation + +Install + +- the `high-availability` plugin in the Gerrit site's `plugins` folder. + +> **NOTE** the `global-refdb` lib module in the Gerrit site's `lib` folder, even if it is not used or referenced as libModule in the `gerrit.config`, because of a bug in the high-availability plugin initialisation sequence. + +In active-active deployments with multiple Gerrit primaries, installation of a global-refdb +implementation is needed to maintain consistent ref updates across all +Gerrit primary sites. + ## Sample configuration for two Gerrit primaries in high-availability Assuming that the Gerrit primaries in the clusters are `gerrit-01.mycompany.com` and @@ -76,7 +88,11 @@ It is the simplest and safest configuration, where only one Gerrit primary at a time serves the incoming requests. +<<<<<<< HEAD +In case of failure of the active primary, the traffic is forwarded to the backup. +======= In case of failure of the primary, the traffic is forwarded to the backup. +>>>>>>> stable-3.12 Assuming a load-balancing implemented using [HAProxy](http://www.haproxy.org/) associated with the domain name `gerrit.mycompany.com`, exposing Gerrit cluster nodes
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java index 9229d01..c770092 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java
@@ -26,9 +26,6 @@ import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRefUpdate; import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRepository; import com.gerritforge.gerrit.globalrefdb.validation.SharedRefLogger; -import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.CustomSharedRefEnforcementByProject; -import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.DefaultSharedRefEnforcement; -import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.SharedRefEnforcement; import com.google.gerrit.extensions.config.FactoryModule; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.server.ExceptionHook; @@ -60,14 +57,6 @@ bind(GitRepositoryManager.class).to(SharedRefDbGitRepositoryManager.class); - if (configuration.sharedRefDb().getSharedRefDb().getEnforcementRules().isEmpty()) { - bind(SharedRefEnforcement.class).to(DefaultSharedRefEnforcement.class).in(Scopes.SINGLETON); - } else { - bind(SharedRefEnforcement.class) - .to(CustomSharedRefEnforcementByProject.class) - .in(Scopes.SINGLETON); - } - DynamicSet.bind(binder(), ExceptionHook.class).to(SharedRefDbExceptionHook.class); } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java index baf512f..ac6ea4c 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java
@@ -26,7 +26,7 @@ @Singleton class CachePatternMatcher { private static final List<String> DEFAULT_PATTERNS = - ImmutableList.of("^groups.*", "ldap_usernames", "projects", "sshkeys"); + ImmutableList.of("^groups.*", "ldap_usernames", "projects", "sshkeys", "tokens"); private final Pattern pattern;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java index b456998..d4fab98 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java
@@ -22,6 +22,7 @@ public static final String GROUPS_BYINCLUDE = "groups_byinclude"; public static final String GROUPS_MEMBERS = "groups_members"; public static final String PROJECTS = "projects"; + public static final String TOKENS = "tokens"; private Constants() {} }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheKeyJsonParser.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheKeyJsonParser.java index ba28650..b8f5e9c 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheKeyJsonParser.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheKeyJsonParser.java
@@ -44,6 +44,7 @@ // Need to add a case for 'adv_bases' switch (cacheName) { case Constants.ACCOUNTS: + case Constants.TOKENS: return id.get() == null ? null : Account.id(id.get().getAsInt()); case Constants.GROUPS: return id.get() == null ? null : AccountGroup.id(id.get().getAsInt());
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java index 63f65d6..6079804 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
@@ -14,10 +14,10 @@ package com.ericsson.gerrit.plugins.highavailability.peers.jgroups; -import autovalue.shaded.com.google.common.collect.ImmutableMap; import com.ericsson.gerrit.plugins.highavailability.Configuration; import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.flogger.FluentLogger; import com.google.gerrit.extensions.events.LifecycleListener;
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md index 6fcd2e2..f62c035 100644 --- a/src/main/resources/Documentation/about.md +++ b/src/main/resources/Documentation/about.md
@@ -27,15 +27,18 @@ sharing or synchronizing them. #### Caches + Every time a cache eviction occurs in one of the instances, the eviction will be forwarded the other nodes so their caches do not contain stale entries. #### Secondary indexes + Every time the secondary index is modified in one of the instances, e.g., a change is added, updated or removed from the index, the others instances index are updated accordingly. This way, both indexes are kept synchronized. #### Stream events + Every time a stream event occurs in one of the instances (see [more events info](https://gerrit-review.googlesource.com/Documentation/cmd-stream-events.html#events)), the event is forwarded to the other instances which re-plays it. This way, the output @@ -43,6 +46,7 @@ connected to. #### Web session + The built-in Gerrit H2 based web session cache is replaced with a file based implementation that is shared amongst the instances. @@ -55,8 +59,8 @@ For the instances: -* Configure gerrit.basePath in gerrit.config to the shared repositories location -* Configure gerrit.serverId in gerrit.config based on [config](config.md)'s introduction +* Configure `gerrit.basePath` in `gerrit.config` to the shared repositories location +* Configure `gerrit.serverId` in `gerrit.config` based on [config](config.md)'s introduction * Install and configure this @PLUGIN@ plugin [further](config.md) or based on below. Here is an example of the minimal @PLUGIN@.config: @@ -110,25 +114,34 @@ * Git repositories must be located on a shared file system * A directory on a shared file system must be available for @PLUGIN@ to use -* An implementation of global-refdb (e.g. Zookeeper) must be accessible from all the active -instances +* An implementation of `global-refdb` (e.g. Zookeeper) must be accessible from all the active + instances to maintain consistent ref updates across all Gerrit primary sites + +The following `global-refdb` implementations are available: + +* [zookeeper-refdb plugin](https://gerrit.googlesource.com/plugins/zookeeper-refdb/+/refs/heads/master) + using Apache Zookeeper +* [aws-dynamodb-refdb plugin](https://gerrit.googlesource.com/plugins/aws-dynamodb-refdb/+/refs/heads/master) + using AWS DynamoDB +* [spanner-refdb plugin](https://gerrit.googlesource.com/plugins/spanner-refdb/+/refs/heads/master) + using Google Cloud Spanner For the instances: -* Configure gerrit.basePath in gerrit.config to the shared repositories location -* Configure gerrit.serverId in gerrit.config based on [config](config.md)'s introduction +* Configure `gerrit.basePath` in `gerrit.config` to the shared repositories location +* Configure `gerrit.serverId` in `gerrit.config` based on [config](config.md)'s introduction * Install and configure this @PLUGIN@ plugin [further](config.md) or based on example configuration -* Install @PLUGIN@ plugin as a database module in $GERRIT_SITE/lib(please note that -@PLUGIN plugin must be installed as a plugin and as a database module) and add -`installDbModule = com.ericsson.gerrit.plugins.highavailability.ValidationModule` -to the gerrit section in gerrit.config -* Install [global-refdb library](https://mvnrepository.com/artifact/com.gerritforge/global-refdb) as a library module in $GERRIT_SITE/lib and add -`installModule = com.gerritforge.gerrit.globalrefdb.validation.LibModule` to the gerrit -section in gerrit.config +* Install @PLUGIN@ plugin as a database module in `$GERRIT_SITE/lib` (please note that +@PLUGIN plugin must be installed as a plugin and as a database module) and add <br/> +`installDbModule = com.ericsson.gerrit.plugins.highavailability.ValidationModule` <br/> +to the gerrit section in `gerrit.config` +* Install [global-refdb library](https://mvnrepository.com/artifact/com.gerritforge/global-refdb) as a library module in $GERRIT_SITE/lib and add <br/> +`installModule = com.gerritforge.gerrit.globalrefdb.validation.LibModule` <br/> +to the `gerrit` section in `gerrit.config` * Install and configure [zookeeper-refdb plugin](https://gerrit-ci.gerritforge.com/view/Plugins-master/job/plugin-zookeeper-refdb-bazel-master) based on [config.md](https://gerrit.googlesource.com/plugins/zookeeper-refdb/+/refs/heads/master/src/main/resources/Documentation/config.md) -* Configure ref-database.enabled = true in @PLUGIN@.config to enable validation with -global-refdb. +* Configure `ref-database.enabled = true` in @PLUGIN@.config to enable validation with +`global-refdb`. Here is an example of the minimal @PLUGIN@.config: @@ -166,12 +179,13 @@ enabled = true ``` -Minimal zookeeper-refdb.config for both active instances: +Minimal `zookeeper-refdb.config` for both active instances: ``` [ref-database "zookeeper"] connectString = zookeeperhost:2181 ``` + ### Last index update timestamp storage The plugin keeps track of the timestamp when it lastly updated an index. @@ -180,6 +194,7 @@ sync with the primary, for example, after a node being offline for a long time. The HA plugin keeps the last update timestamp for each index in the following files: + * `<gerrit_home>/data/high-availability/account` * `<gerrit_home>/data/high-availability/change`
diff --git a/src/test/README.md b/src/test/README.md index 80fe2e4..b0aa3c4 100644 --- a/src/test/README.md +++ b/src/test/README.md
@@ -1,8 +1,8 @@ # Gerrit high-availability docker setup example The Docker Compose project in the docker directory contains a simple test -environment of two Gerrit primaries in HA configuration, with their git repos -hosted on NFS filesystem. +environment of two Gerrit primary servers in HA configuration, with their +git repos hosted on NFS filesystem. ## How to build
diff --git a/src/test/docker/gerrit/Dockerfile b/src/test/docker/gerrit/Dockerfile index ebb4b84..d18e060 100644 --- a/src/test/docker/gerrit/Dockerfile +++ b/src/test/docker/gerrit/Dockerfile
@@ -11,7 +11,7 @@ nfs-utils \ && yum -y clean all -ENV GERRIT_BRANCH stable-3.12 +ENV GERRIT_BRANCH stable-3.13 # Add gerrit user RUN adduser -p -m --uid 1000 gerrit --home-dir /home/gerrit @@ -42,7 +42,7 @@ /var/gerrit/lib/global-refdb.jar ADD --chown=gerrit:gerrit \ - "https://gerrit-ci.gerritforge.com/job/plugin-zookeeper-refdb-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/zookeeper-refdb/zookeeper-refdb.jar" \ + "https://gerrit-ci.gerritforge.com/job/plugin-zookeeper-refdb-gh-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/zookeeper-refdb/zookeeper-refdb.jar" \ /var/gerrit/plugins/zookeeper-refdb.jar ADD --chown=gerrit:gerrit \
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java index b51e1a0..0fb7dad 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -217,9 +217,6 @@ globalPluginConfig.setInt(HTTP_SECTION, null, CONNECTION_TIMEOUT_KEY, TIMEOUT); assertThat(getConfiguration().http().connectionTimeout().toMillis()).isEqualTo(TIMEOUT); - - globalPluginConfig.setString(HTTP_SECTION, null, CONNECTION_TIMEOUT_KEY, INVALID_INT); - assertThat(getConfiguration().http().connectionTimeout()).isEqualTo(DEFAULT_TIMEOUT); } @Test @@ -228,9 +225,6 @@ globalPluginConfig.setInt(HTTP_SECTION, null, SOCKET_TIMEOUT_KEY, TIMEOUT); assertThat(getConfiguration().http().socketTimeout().toMillis()).isEqualTo(TIMEOUT); - - globalPluginConfig.setString(HTTP_SECTION, null, SOCKET_TIMEOUT_KEY, INVALID_INT); - assertThat(getConfiguration().http().socketTimeout()).isEqualTo(DEFAULT_TIMEOUT); } @Test @@ -256,9 +250,6 @@ globalPluginConfig.setInt(HTTP_SECTION, null, RETRY_INTERVAL_KEY, RETRY_INTERVAL); assertThat(getConfiguration().http().retryInterval().toMillis()).isEqualTo(RETRY_INTERVAL); - - globalPluginConfig.setString(HTTP_SECTION, null, RETRY_INTERVAL_KEY, INVALID_INT); - assertThat(getConfiguration().http().retryInterval()).isEqualTo(DEFAULT_RETRY_INTERVAL); } @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcherTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcherTest.java index caf50b9..088b42e 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcherTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcherTest.java
@@ -47,6 +47,7 @@ "ldap_usernames", "projects", "sshkeys", + "tokens", "my_cache_a", "my_cache_b", "other")) {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServletTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServletTest.java index e4ffd59..58c0aef 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServletTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServletTest.java
@@ -87,6 +87,12 @@ } @Test + public void evictTokensCache() throws Exception { + configureMocksFor(Constants.TOKENS); + verifyResponseIsOK(); + } + + @Test public void evictDefault() throws Exception { configureMocksFor(Constants.PROJECTS); verifyResponseIsOK(); @@ -134,6 +140,8 @@ } else if (Constants.GROUPS_BYINCLUDE.equals(cacheName) || Constants.GROUPS_MEMBERS.equals(cacheName)) { when(readerMock.readLine()).thenReturn("{\"uuid\":\"abcd1234\"}"); + } else if (Constants.TOKENS.equals(cacheName)) { + when(readerMock.readLine()).thenReturn("{\"id\":\"1234\"}"); } else { when(readerMock.readLine()).thenReturn("{}"); }