2727import org .elasticsearch .cluster .project .DefaultProjectResolver ;
2828import org .elasticsearch .cluster .project .ProjectResolver ;
2929import org .elasticsearch .common .Strings ;
30+ import org .elasticsearch .common .collect .Iterators ;
3031import org .elasticsearch .common .settings .ClusterSettings ;
3132import org .elasticsearch .common .settings .SecureSetting ;
3233import org .elasticsearch .common .settings .SecureString ;
4849import java .util .Iterator ;
4950import java .util .List ;
5051import java .util .Map ;
52+ import java .util .Objects ;
5153import java .util .Set ;
5254import java .util .concurrent .CountDownLatch ;
5355import 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}
0 commit comments