Skip to content

Commit 9338680

Browse files
Update RemoteClusterService to default skip unavailable to true for CPS
In stateless CPS skip_unavailable will not be used and should always be true. Also DisconnectedStrategy.RECONNECT_UNLESS_SKIP_UNAVAILABLE is rejected in CPS as a parameter value for getRemoteClusterClient(). Resolves: ES-12267
1 parent 75e1518 commit 9338680

File tree

3 files changed

+122
-3
lines changed

3 files changed

+122
-3
lines changed

server/src/main/java/org/elasticsearch/transport/RemoteClusterService.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.elasticsearch.cluster.project.DefaultProjectResolver;
2828
import org.elasticsearch.cluster.project.ProjectResolver;
2929
import org.elasticsearch.common.Strings;
30+
import org.elasticsearch.common.collect.Iterators;
3031
import org.elasticsearch.common.settings.ClusterSettings;
3132
import org.elasticsearch.common.settings.SecureSetting;
3233
import org.elasticsearch.common.settings.SecureString;
@@ -48,6 +49,7 @@
4849
import java.util.Iterator;
4950
import java.util.List;
5051
import java.util.Map;
52+
import java.util.Objects;
5153
import java.util.Set;
5254
import java.util.concurrent.CountDownLatch;
5355
import java.util.concurrent.Executor;
@@ -98,7 +100,13 @@ public final class RemoteClusterService extends RemoteClusterAware
98100
public static final Setting.AffixSetting<Boolean> REMOTE_CLUSTER_SKIP_UNAVAILABLE = Setting.affixKeySetting(
99101
"cluster.remote.",
100102
"skip_unavailable",
101-
(ns, key) -> boolSetting(key, true, new RemoteConnectionEnabled<>(ns, key), Setting.Property.Dynamic, Setting.Property.NodeScope)
103+
(ns, key) -> boolSetting(
104+
key,
105+
true,
106+
new FixedValueIfStatelessEnabledValidator<>(ns, key, true),
107+
Setting.Property.Dynamic,
108+
Setting.Property.NodeScope
109+
)
102110
);
103111

104112
public static final Setting.AffixSetting<TimeValue> REMOTE_CLUSTER_PING_SCHEDULE = Setting.affixKeySetting(
@@ -149,6 +157,7 @@ public final class RemoteClusterService extends RemoteClusterAware
149157

150158
private final boolean enabled;
151159
private final boolean remoteClusterServerEnabled;
160+
private final boolean isStateless;
152161

153162
public boolean isEnabled() {
154163
return enabled;
@@ -167,6 +176,7 @@ public boolean isRemoteClusterServerEnabled() {
167176
RemoteClusterService(Settings settings, TransportService transportService) {
168177
super(settings);
169178
this.enabled = DiscoveryNode.isRemoteClusterClient(settings);
179+
this.isStateless = DiscoveryNode.isStateless(settings);
170180
this.remoteClusterServerEnabled = REMOTE_CLUSTER_SERVER_ENABLED.get(settings);
171181
this.transportService = transportService;
172182
this.projectResolver = DefaultProjectResolver.INSTANCE;
@@ -294,7 +304,7 @@ void ensureConnected(String clusterAlias, ActionListener<Void> listener) {
294304
* Returns whether the cluster identified by the provided alias is configured to be skipped when unavailable
295305
*/
296306
public boolean isSkipUnavailable(String clusterAlias) {
297-
return getRemoteClusterConnection(clusterAlias).isSkipUnavailable();
307+
return isStateless || getRemoteClusterConnection(clusterAlias).isSkipUnavailable();
298308
}
299309

300310
public Transport.Connection getConnection(String cluster) {
@@ -351,10 +361,13 @@ public RemoteClusterConnection getRemoteClusterConnection(String cluster) {
351361
@Override
352362
public void listenForUpdates(ClusterSettings clusterSettings) {
353363
super.listenForUpdates(clusterSettings);
354-
clusterSettings.addAffixUpdateConsumer(REMOTE_CLUSTER_SKIP_UNAVAILABLE, this::updateSkipUnavailable, (alias, value) -> {});
364+
if (isStateless == false) {
365+
clusterSettings.addAffixUpdateConsumer(REMOTE_CLUSTER_SKIP_UNAVAILABLE, this::updateSkipUnavailable, (alias, value) -> {});
366+
}
355367
}
356368

357369
private synchronized void updateSkipUnavailable(String clusterAlias, Boolean skipUnavailable) {
370+
assert isStateless == false : "Cannot configure setting [" + REMOTE_CLUSTER_SKIP_UNAVAILABLE + "] in stateless environments.";
358371
RemoteClusterConnection remote = getConnectionsMapForCurrentProject().get(clusterAlias);
359372
if (remote != null) {
360373
remote.setSkipUnavailable(skipUnavailable);
@@ -667,6 +680,13 @@ public RemoteClusterClient getRemoteClusterClient(
667680
"this node does not have the " + DiscoveryNodeRole.REMOTE_CLUSTER_CLIENT_ROLE.roleName() + " role"
668681
);
669682
}
683+
if (isStateless && disconnectedStrategy == DisconnectedStrategy.RECONNECT_UNLESS_SKIP_UNAVAILABLE) {
684+
throw new IllegalArgumentException(
685+
"DisconnectedStrategy ["
686+
+ DisconnectedStrategy.RECONNECT_UNLESS_SKIP_UNAVAILABLE
687+
+ "] is not supported in stateless environments"
688+
);
689+
}
670690
if (transportService.getRemoteClusterService().getRegisteredRemoteClusterNames().contains(clusterAlias) == false) {
671691
throw new NoSuchRemoteClusterException(clusterAlias);
672692
}
@@ -736,6 +756,10 @@ private RemoteConnectionEnabled(String clusterAlias, String key) {
736756
this.key = key;
737757
}
738758

759+
protected String getKey() {
760+
return key;
761+
}
762+
739763
@Override
740764
public void validate(T value) {}
741765

@@ -760,4 +784,29 @@ private Stream<Setting<?>> settingsStream() {
760784
.map(as -> as.getConcreteSettingForNamespace(clusterAlias));
761785
}
762786
};
787+
788+
private static class FixedValueIfStatelessEnabledValidator<T> extends RemoteConnectionEnabled<T> {
789+
private final Setting<Boolean> statelessSetting = Setting.boolSetting(DiscoveryNode.STATELESS_ENABLED_SETTING_NAME, false);
790+
private final T requiredValue;
791+
792+
private FixedValueIfStatelessEnabledValidator(String clusterAlias, String key, T requiredValue) {
793+
super(clusterAlias, key);
794+
this.requiredValue = Objects.requireNonNull(requiredValue);
795+
}
796+
797+
@Override
798+
public void validate(T value, Map<Setting<?>, Object> settings, boolean isPresent) {
799+
if (isPresent && ((Boolean) settings.get(statelessSetting)) && requiredValue.equals(value) == false) {
800+
throw new IllegalArgumentException(
801+
"setting [" + getKey() + "] must be set to [" + requiredValue + "] when stateless is enabled"
802+
);
803+
}
804+
super.validate(value, settings, isPresent);
805+
}
806+
807+
@Override
808+
public Iterator<Setting<?>> settings() {
809+
return Iterators.concat(super.settings(), List.of(statelessSetting).iterator());
810+
}
811+
}
763812
}

server/src/test/java/org/elasticsearch/transport/RemoteClusterClientTests.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,30 @@ public void testRemoteClusterServiceNotEnabled() {
240240
}
241241
}
242242

243+
public void testGetRemoteClusterClientRejectsSkipUnavailableInStateless() {
244+
final var settings = Settings.builder().put("stateless.enabled", true).putList("node.roles", "remote_cluster_client").build();
245+
try (
246+
MockTransportService service = MockTransportService.createNewService(
247+
settings,
248+
VersionInformation.CURRENT,
249+
TransportVersion.current(),
250+
threadPool,
251+
null
252+
)
253+
) {
254+
final var remoteClusterService = service.getRemoteClusterService();
255+
expectThrows(
256+
IllegalArgumentException.class,
257+
RemoteClusterService.DisconnectedStrategy.RECONNECT_UNLESS_SKIP_UNAVAILABLE + " is unsupported when stateless is enabled",
258+
() -> remoteClusterService.getRemoteClusterClient(
259+
"test",
260+
EsExecutors.DIRECT_EXECUTOR_SERVICE,
261+
RemoteClusterService.DisconnectedStrategy.RECONNECT_UNLESS_SKIP_UNAVAILABLE
262+
)
263+
);
264+
}
265+
}
266+
243267
public void testQuicklySkipUnavailableClusters() throws Exception {
244268
Settings remoteSettings = Settings.builder().put(ClusterName.CLUSTER_NAME_SETTING.getKey(), "foo_bar_cluster").build();
245269
try (

server/src/test/java/org/elasticsearch/transport/RemoteClusterSettingsTests.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,50 @@ public void testProxyDefault() {
9595
final String alias = randomAlphaOfLength(8);
9696
assertThat(REMOTE_CLUSTERS_PROXY.getConcreteSettingForNamespace(alias).get(Settings.EMPTY), equalTo(""));
9797
}
98+
99+
public void testSkipUnavailableAlwaysTrueIfStatelessEnabled() {
100+
final String alias = randomAlphaOfLength(8);
101+
final var skipUnavailableSetting = REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace(alias);
102+
final var modeSetting = RemoteConnectionStrategy.REMOTE_CONNECTION_MODE.getConcreteSettingForNamespace(alias);
103+
final var proxyAddressSetting = ProxyConnectionStrategy.PROXY_ADDRESS.getConcreteSettingForNamespace(alias);
104+
105+
final var statelessEnabledSettings = Settings.builder().put(DiscoveryNode.STATELESS_ENABLED_SETTING_NAME, true).build();
106+
assertTrue(skipUnavailableSetting.get(statelessEnabledSettings));
107+
final var proxyEnabledSettings = Settings.builder()
108+
.put(modeSetting.getKey(), RemoteConnectionStrategy.ConnectionStrategy.PROXY.toString())
109+
.put(proxyAddressSetting.getKey(), "localhost:9400")
110+
.build();
111+
112+
// Ensure the validator still throws if a connection mode is not set.
113+
expectThrows(
114+
IllegalArgumentException.class,
115+
"should not be able to set skip_unavailable if connection mode is not set",
116+
() -> skipUnavailableSetting.get(
117+
Settings.builder().put(statelessEnabledSettings).put(skipUnavailableSetting.getKey(), true).build()
118+
)
119+
);
120+
121+
// Check the validator requires skip_unavailable to always be true if stateless is enabled.
122+
assertThat(
123+
skipUnavailableSetting.get(
124+
Settings.builder()
125+
.put(statelessEnabledSettings)
126+
.put(proxyEnabledSettings)
127+
.put(skipUnavailableSetting.getKey(), true)
128+
.build()
129+
),
130+
equalTo(true)
131+
);
132+
expectThrows(
133+
IllegalArgumentException.class,
134+
"should not be able to set skip_unavailable to false if stateless is enabled",
135+
() -> skipUnavailableSetting.get(
136+
Settings.builder()
137+
.put(statelessEnabledSettings)
138+
.put(proxyEnabledSettings)
139+
.put(skipUnavailableSetting.getKey(), false)
140+
.build()
141+
)
142+
);
143+
}
98144
}

0 commit comments

Comments
 (0)