Merge branch 'stable-3.3' into stable-3.4 * stable-3.3: Revert "Set forward context for events having a different instanceId" Use Gerrit v3.2.14 on Ubuntu as CentOS is discontinued Serve reindexing simulating a GET request for /meta ref caching Auto-reload the indexTs file for auto-reindexing Download plugins from archive-ci.gerritforge.com Pin haproxy to 1.8.30-buster and fix associated issues Pin haproxy to 1.8.30-buster and fix associated issues Fix issue with change indexing during the NoteDb online migration Remove references to ReviewDb in README.md Change-Id: I0c89172943e017111dffe726358b82584d794d5e
diff --git a/BUILD b/BUILD index 5975b31..2ee0faa 100644 --- a/BUILD +++ b/BUILD
@@ -21,7 +21,7 @@ resources = glob(["src/main/resources/**/*"]), deps = [ "@jgroups//jar", - "@global-refdb//jar", + "@global-refdb//jar:neverlink", ], )
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl index 9af89f0..74c8f13 100644 --- a/external_plugin_deps.bzl +++ b/external_plugin_deps.bzl
@@ -15,6 +15,6 @@ maven_jar( name = "global-refdb", - artifact = "com.gerritforge:global-refdb:3.3.2.1:jdk8", - sha1 = "7a293d577665dfc6f4d36371af21c4a3f7177b23", + artifact = "com.gerritforge:global-refdb:3.4.8", + sha1 = "a05e1684c0b02867c203e3f55efe62ced2c0fe61", )
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/ConfigurableAllowedEventListeners.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ConfigurableAllowedEventListeners.java new file mode 100644 index 0000000..ea5f69c --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ConfigurableAllowedEventListeners.java
@@ -0,0 +1,50 @@ +// Copyright (C) 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.ericsson.gerrit.plugins.highavailability; + +import com.ericsson.gerrit.plugins.highavailability.forwarder.AllowedForwardedEventListener; +import com.google.gerrit.server.events.EventListener; +import com.google.inject.Inject; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** Configure the allowed listeners in high-availability.config */ +public class ConfigurableAllowedEventListeners implements AllowedForwardedEventListener { + private final Set<String> allowedListenerClasses; + private final ConcurrentHashMap<EventListener, Boolean> cachedAllowedListeners; + + @Inject + ConfigurableAllowedEventListeners(Configuration config) { + allowedListenerClasses = config.event().allowedListeners(); + cachedAllowedListeners = new ConcurrentHashMap<>(); + } + + @Override + public boolean isAllowed(EventListener listener) { + return cachedAllowedListeners.computeIfAbsent(listener, this::computeIsAllowed); + } + + protected Boolean computeIsAllowed(EventListener listener) { + String listenerClassName = listener.getClass().getName(); + boolean allowed = false; + while (!allowed && !listenerClassName.isEmpty()) { + allowed = allowedListenerClasses.contains(listenerClassName); + int lastDotPos = Math.max(listenerClassName.lastIndexOf('.'), 0); + listenerClassName = listenerClassName.substring(0, lastDotPos); + } + + return allowed; + } +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java index f28b7c9..cdca21b 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -23,6 +23,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; import com.google.common.flogger.FluentLogger; import com.google.gerrit.common.Nullable; import com.google.gerrit.server.config.ConfigUtil; @@ -467,9 +468,18 @@ public static class Event extends Forwarding { static final String EVENT_SECTION = "event"; + static final String ALLOWED_LISTENERS = "allowedListeners"; + + private final Set<String> allowedListeners; private Event(Config cfg) { super(cfg, EVENT_SECTION); + + allowedListeners = Sets.newHashSet(cfg.getStringList(EVENT_SECTION, null, ALLOWED_LISTENERS)); + } + + public Set<String> allowedListeners() { + return allowedListeners; } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexModule.java index d4871a7..d5e168d 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexModule.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexModule.java
@@ -18,6 +18,7 @@ import com.google.gerrit.extensions.events.ChangeIndexedListener; import com.google.gerrit.extensions.events.GroupIndexedListener; import com.google.gerrit.extensions.events.LifecycleListener; +import com.google.gerrit.extensions.events.ProjectIndexedListener; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.inject.AbstractModule; @@ -29,5 +30,6 @@ DynamicSet.bind(binder(), ChangeIndexedListener.class).to(IndexTs.class); DynamicSet.bind(binder(), AccountIndexedListener.class).to(IndexTs.class); DynamicSet.bind(binder(), GroupIndexedListener.class).to(IndexTs.class); + DynamicSet.bind(binder(), ProjectIndexedListener.class).to(IndexTs.class); } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java index c21ccae..4ded55e 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
@@ -22,9 +22,9 @@ import com.google.gerrit.entities.AccountGroupByIdAudit; import com.google.gerrit.entities.AccountGroupMemberAudit; import com.google.gerrit.entities.GroupReference; +import com.google.gerrit.entities.InternalGroup; import com.google.gerrit.server.config.AllUsersName; import com.google.gerrit.server.git.GitRepositoryManager; -import com.google.gerrit.server.group.InternalGroup; import com.google.gerrit.server.group.db.Groups; import com.google.gerrit.server.util.OneOffRequestContext; import com.google.inject.Inject;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/AllowedForwardedEventListener.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/AllowedForwardedEventListener.java new file mode 100644 index 0000000..d79625a --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/AllowedForwardedEventListener.java
@@ -0,0 +1,29 @@ +// Copyright (C) 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.ericsson.gerrit.plugins.highavailability.forwarder; + +import com.google.gerrit.server.events.EventListener; + +/** Allow to trigger an event listener unconditionally. */ +public interface AllowedForwardedEventListener { + + /** + * Control whether an event listener should be allowed unconditionally. + * + * @param listener the event listener + * @return true if the listener should be allowed, false otherwise + */ + boolean isAllowed(EventListener listener); +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java index 700d5e1..29d4e56 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java
@@ -14,6 +14,7 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; +import com.google.gerrit.common.Nullable; import com.google.gerrit.server.config.GerritInstanceId; import com.google.gerrit.server.events.Event; import com.google.gerrit.server.events.EventBroker; @@ -24,10 +25,11 @@ import com.google.gerrit.server.plugincontext.PluginSetContext; import com.google.gerrit.server.project.ProjectCache; import com.google.inject.Inject; -import javax.annotation.Nullable; class ForwardedAwareEventBroker extends EventBroker { + private final AllowedForwardedEventListener allowedListeners; + @Inject ForwardedAwareEventBroker( PluginSetContext<UserScopedEventListener> listeners, @@ -35,7 +37,8 @@ PermissionBackend permissionBackend, ProjectCache projectCache, Factory notesFactory, - @Nullable @GerritInstanceId String gerritInstanceId) { + @Nullable @GerritInstanceId String gerritInstanceId, + @Nullable AllowedForwardedEventListener allowedListeners) { super( listeners, unrestrictedListeners, @@ -43,12 +46,21 @@ projectCache, notesFactory, gerritInstanceId); + + this.allowedListeners = allowedListeners; } @Override protected void fireEventForUnrestrictedListeners(Event event) { - if (!Context.isForwardedEvent()) { - super.fireEventForUnrestrictedListeners(event); + // or it was consumed by the high-availability rest endpoint and + // thus the context of its consumption has already been set to "forwarded". + unrestrictedListeners.runEach(l -> fireEventForListener(l, event)); + } + + private void fireEventForListener(EventListener l, Event event) { + if (!Context.isForwardedEvent() + || (allowedListeners != null && allowedListeners.isAllowed(l))) { + l.onEvent(event); } } }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java index 99a820e..7cb107c 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java
@@ -14,14 +14,19 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder; +import com.ericsson.gerrit.plugins.highavailability.ConfigurableAllowedEventListeners; import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.server.events.EventDispatcher; import com.google.inject.AbstractModule; +import com.google.inject.Scopes; public class ForwarderModule extends AbstractModule { @Override protected void configure() { + bind(AllowedForwardedEventListener.class) + .to(ConfigurableAllowedEventListeners.class) + .in(Scopes.SINGLETON); DynamicItem.bind(binder(), EventDispatcher.class).to(ForwardedAwareEventBroker.class); } }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index ff987aa..d94a91e 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md
@@ -175,6 +175,12 @@ Defaults to an empty list, meaning only evictions of the core caches are forwarded. +```event.allowedListeners``` +: Class name or package name of the event listener that is always allowed to receive + all events generated locally or from a remote end. + Can be specified multiple times for allowing multiple listeners classes or packages. + Defaults to an empty list. + ```event.synchronize``` : Whether to synchronize stream events. Defaults to true.
diff --git a/src/test/docker/gerrit/Dockerfile b/src/test/docker/gerrit/Dockerfile index 1d0ffa0..b4f9c6e 100644 --- a/src/test/docker/gerrit/Dockerfile +++ b/src/test/docker/gerrit/Dockerfile
@@ -1,6 +1,6 @@ -FROM gerritcodereview/gerrit:3.3.7-ubuntu20 +FROM gerritcodereview/gerrit:3.4.5-ubuntu20 -ENV GERRIT_BRANCH=stable-3.3 +ENV GERRIT_BRANCH=stable-3.4 ENV GERRIT_CI_URL=https://archive-ci.gerritforge.com/job
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 19cc48d..fb1b8d0 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -20,6 +20,7 @@ import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_NUM_STRIPED_LOCKS; import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_THREAD_POOL_SIZE; import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_TIMEOUT_MS; +import static com.ericsson.gerrit.plugins.highavailability.Configuration.Event.ALLOWED_LISTENERS; import static com.ericsson.gerrit.plugins.highavailability.Configuration.Event.EVENT_SECTION; import static com.ericsson.gerrit.plugins.highavailability.Configuration.Forwarding.DEFAULT_SYNCHRONIZE; import static com.ericsson.gerrit.plugins.highavailability.Configuration.Forwarding.SYNCHRONIZE_KEY; @@ -68,10 +69,14 @@ import com.google.common.collect.ImmutableList; import com.google.gerrit.server.config.PluginConfigFactory; import com.google.gerrit.server.config.SitePaths; +import com.google.gerrit.server.events.Event; +import com.google.gerrit.server.events.EventListener; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jgit.lib.Config; import org.junit.Before; import org.junit.Test; @@ -331,6 +336,88 @@ } @Test + public void testGetEventAllowedListener() throws Exception { + assertThat(getConfiguration().event().allowedListeners()).isEmpty(); + + List<String> allowedListeners = Arrays.asList("listener1", "listener2"); + globalPluginConfig.setStringList(EVENT_SECTION, null, ALLOWED_LISTENERS, allowedListeners); + assertThat(getConfiguration().event().allowedListeners()) + .containsExactlyElementsIn(allowedListeners); + } + + @Test + public void testConfiguredListenerShouldBeAllowed() throws Exception { + EventListener listener = + new EventListener() { + + @Override + public void onEvent(Event event) {} + }; + assertThat(new ConfigurableAllowedEventListeners(getConfiguration()).isAllowed(listener)) + .isFalse(); + + globalPluginConfig.setString( + EVENT_SECTION, null, ALLOWED_LISTENERS, listener.getClass().getName()); + + assertThat(new ConfigurableAllowedEventListeners(getConfiguration()).isAllowed(listener)) + .isTrue(); + + globalPluginConfig.setString( + EVENT_SECTION, null, ALLOWED_LISTENERS, listener.getClass().getPackageName()); + + assertThat(new ConfigurableAllowedEventListeners(getConfiguration()).isAllowed(listener)) + .isTrue(); + } + + @Test + public void testConfiguredListenerAllowedShouldBeCached() throws Exception { + AtomicInteger allowedListenerResolutionCount = new AtomicInteger(); + EventListener listener = + new EventListener() { + + @Override + public void onEvent(Event event) {} + }; + assertThat(new ConfigurableAllowedEventListeners(getConfiguration()).isAllowed(listener)) + .isFalse(); + + globalPluginConfig.setString( + EVENT_SECTION, null, ALLOWED_LISTENERS, listener.getClass().getName()); + + ConfigurableAllowedEventListeners allowedEventListener = + new ConfigurableAllowedEventListeners(getConfiguration()) { + @Override + protected Boolean computeIsAllowed(EventListener listener) { + allowedListenerResolutionCount.incrementAndGet(); + return super.computeIsAllowed(listener); + } + }; + + for (int i = 0; i < 2; i++) { + assertThat(allowedEventListener.isAllowed(listener)).isTrue(); + assertThat(allowedListenerResolutionCount.get()).isEqualTo(1); + } + } + + @Test + public void testConfiguredPackageOfListenerShouldBeAllowed() throws Exception { + EventListener listener = + new EventListener() { + + @Override + public void onEvent(Event event) {} + }; + assertThat(new ConfigurableAllowedEventListeners(getConfiguration()).isAllowed(listener)) + .isFalse(); + + globalPluginConfig.setString( + EVENT_SECTION, null, ALLOWED_LISTENERS, listener.getClass().getPackageName()); + + assertThat(new ConfigurableAllowedEventListeners(getConfiguration()).isAllowed(listener)) + .isTrue(); + } + + @Test public void testGetDefaultSharedDirectory() throws Exception { assertEquals( getConfiguration().main().sharedDirectory(), sitePaths.resolve(DEFAULT_SHARED_DIRECTORY));
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnableTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnableTest.java index 7ab4a1c..afd6df4 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnableTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnableTest.java
@@ -30,9 +30,9 @@ import com.google.gerrit.entities.AccountGroupByIdAudit; import com.google.gerrit.entities.AccountGroupMemberAudit; import com.google.gerrit.entities.GroupReference; +import com.google.gerrit.entities.InternalGroup; import com.google.gerrit.server.config.AllUsersName; import com.google.gerrit.server.git.GitRepositoryManager; -import com.google.gerrit.server.group.InternalGroup; import com.google.gerrit.server.group.db.Groups; import com.google.gerrit.server.util.OneOffRequestContext; import java.sql.Timestamp;
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java index ec5b1de..4c639ba 100644 --- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java
@@ -29,6 +29,7 @@ public class ForwardedAwareEventBrokerTest { private EventListener listenerMock; + private AllowedForwardedEventListener allowListenerMock; private ForwardedAwareEventBroker broker; private Event event = new TestEvent(); @@ -36,10 +37,12 @@ public void setUp() { PluginMetrics mockMetrics = mock(PluginMetrics.class); listenerMock = mock(EventListener.class); + allowListenerMock = mock(AllowedForwardedEventListener.class); DynamicSet<EventListener> set = DynamicSet.emptySet(); set.add("high-availability", listenerMock); PluginSetContext<EventListener> listeners = new PluginSetContext<>(set, mockMetrics); - broker = new ForwardedAwareEventBroker(null, listeners, null, null, null, null); + broker = + new ForwardedAwareEventBroker(null, listeners, null, null, null, null, allowListenerMock); } @Test