|
|
@@ -27,11 +27,9 @@ import org.elasticsearch.action.admin.cluster.shards.ClusterSearchShardsGroup;
|
|
|
import org.elasticsearch.action.admin.cluster.shards.ClusterSearchShardsResponse;
|
|
|
import org.elasticsearch.action.support.GroupedActionListener;
|
|
|
import org.elasticsearch.action.support.PlainActionFuture;
|
|
|
-import org.elasticsearch.cluster.metadata.ClusterNameExpressionResolver;
|
|
|
import org.elasticsearch.cluster.node.DiscoveryNode;
|
|
|
import org.elasticsearch.common.Booleans;
|
|
|
import org.elasticsearch.common.Strings;
|
|
|
-import org.elasticsearch.common.component.AbstractComponent;
|
|
|
import org.elasticsearch.common.settings.Setting;
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.common.transport.TransportAddress;
|
|
|
@@ -46,10 +44,7 @@ import org.elasticsearch.transport.TransportService;
|
|
|
|
|
|
import java.io.Closeable;
|
|
|
import java.io.IOException;
|
|
|
-import java.net.InetAddress;
|
|
|
import java.net.InetSocketAddress;
|
|
|
-import java.net.UnknownHostException;
|
|
|
-import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.Collection;
|
|
|
import java.util.Collections;
|
|
|
@@ -64,21 +59,12 @@ import java.util.concurrent.atomic.AtomicReference;
|
|
|
import java.util.function.Function;
|
|
|
import java.util.function.Predicate;
|
|
|
import java.util.stream.Collectors;
|
|
|
-import java.util.stream.Stream;
|
|
|
|
|
|
/**
|
|
|
* Basic service for accessing remote clusters via gateway nodes
|
|
|
*/
|
|
|
-public final class RemoteClusterService extends AbstractComponent implements Closeable {
|
|
|
+public final class RemoteClusterService extends RemoteClusterAware implements Closeable {
|
|
|
|
|
|
- static final String LOCAL_CLUSTER_GROUP_KEY = "";
|
|
|
-
|
|
|
- /**
|
|
|
- * A list of initial seed nodes to discover eligible nodes from the remote cluster
|
|
|
- */
|
|
|
- public static final Setting.AffixSetting<List<InetSocketAddress>> REMOTE_CLUSTERS_SEEDS = Setting.affixKeySetting("search.remote.",
|
|
|
- "seeds", (key) -> Setting.listSetting(key, Collections.emptyList(), RemoteClusterService::parseSeedAddress,
|
|
|
- Setting.Property.NodeScope, Setting.Property.Dynamic));
|
|
|
/**
|
|
|
* The maximum number of connections that will be established to a remote cluster. For instance if there is only a single
|
|
|
* seed node, other nodes will be discovered up to the given number of nodes in this setting. The default is 3.
|
|
|
@@ -109,17 +95,13 @@ public final class RemoteClusterService extends AbstractComponent implements Clo
|
|
|
public static final Setting<Boolean> ENABLE_REMOTE_CLUSTERS = Setting.boolSetting("search.remote.connect", true,
|
|
|
Setting.Property.NodeScope);
|
|
|
|
|
|
- private static final char REMOTE_CLUSTER_INDEX_SEPARATOR = ':';
|
|
|
-
|
|
|
private final TransportService transportService;
|
|
|
private final int numRemoteConnections;
|
|
|
- private final ClusterNameExpressionResolver clusterNameResolver;
|
|
|
private volatile Map<String, RemoteClusterConnection> remoteClusters = Collections.emptyMap();
|
|
|
|
|
|
RemoteClusterService(Settings settings, TransportService transportService) {
|
|
|
super(settings);
|
|
|
this.transportService = transportService;
|
|
|
- this.clusterNameResolver = new ClusterNameExpressionResolver(settings);
|
|
|
numRemoteConnections = REMOTE_CONNECTIONS_PER_CLUSTER.get(settings);
|
|
|
}
|
|
|
|
|
|
@@ -195,46 +177,6 @@ public final class RemoteClusterService extends AbstractComponent implements Clo
|
|
|
return remoteClusters.get(remoteCluster).isNodeConnected(node);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Groups indices per cluster by splitting remote cluster-alias, index-name pairs on {@link #REMOTE_CLUSTER_INDEX_SEPARATOR}. All
|
|
|
- * indices per cluster are collected as a list in the returned map keyed by the cluster alias. Local indices are grouped under
|
|
|
- * {@link #LOCAL_CLUSTER_GROUP_KEY}. The returned map is mutable.
|
|
|
- *
|
|
|
- * @param requestIndices the indices in the search request to filter
|
|
|
- * @param indexExists a predicate that can test if a certain index or alias exists
|
|
|
- *
|
|
|
- * @return a map of grouped remote and local indices
|
|
|
- */
|
|
|
- Map<String, List<String>> groupClusterIndices(String[] requestIndices, Predicate<String> indexExists) {
|
|
|
- Map<String, List<String>> perClusterIndices = new HashMap<>();
|
|
|
- Set<String> remoteClusterNames = this.remoteClusters.keySet();
|
|
|
- for (String index : requestIndices) {
|
|
|
- int i = index.indexOf(REMOTE_CLUSTER_INDEX_SEPARATOR);
|
|
|
- if (i >= 0) {
|
|
|
- String remoteClusterName = index.substring(0, i);
|
|
|
- List<String> clusters = clusterNameResolver.resolveClusterNames(remoteClusterNames, remoteClusterName);
|
|
|
- if (clusters.isEmpty() == false) {
|
|
|
- if (indexExists.test(index)) {
|
|
|
- // we use : as a separator for remote clusters. might conflict if there is an index that is actually named
|
|
|
- // remote_cluster_alias:index_name - for this case we fail the request. the user can easily change the cluster alias
|
|
|
- // if that happens
|
|
|
- throw new IllegalArgumentException("Can not filter indices; index " + index +
|
|
|
- " exists but there is also a remote cluster named: " + remoteClusterName);
|
|
|
- }
|
|
|
- String indexName = index.substring(i + 1);
|
|
|
- for (String clusterName : clusters) {
|
|
|
- perClusterIndices.computeIfAbsent(clusterName, k -> new ArrayList<>()).add(indexName);
|
|
|
- }
|
|
|
- } else {
|
|
|
- perClusterIndices.computeIfAbsent(LOCAL_CLUSTER_GROUP_KEY, k -> new ArrayList<>()).add(index);
|
|
|
- }
|
|
|
- } else {
|
|
|
- perClusterIndices.computeIfAbsent(LOCAL_CLUSTER_GROUP_KEY, k -> new ArrayList<>()).add(index);
|
|
|
- }
|
|
|
- }
|
|
|
- return perClusterIndices;
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* Returns <code>true</code> iff the given cluster is configured as a remote cluster. Otherwise <code>false</code>
|
|
|
*/
|
|
|
@@ -342,7 +284,12 @@ public final class RemoteClusterService extends AbstractComponent implements Clo
|
|
|
return connection.getConnection(node);
|
|
|
}
|
|
|
|
|
|
- void updateRemoteCluster(String clusterAlias, List<InetSocketAddress> addresses) {
|
|
|
+ @Override
|
|
|
+ protected Set<String> getRemoteClusterNames() {
|
|
|
+ return this.remoteClusters.keySet();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected void updateRemoteCluster(String clusterAlias, List<InetSocketAddress> addresses) {
|
|
|
updateRemoteCluster(clusterAlias, addresses, ActionListener.wrap((x) -> {}, (x) -> {}));
|
|
|
}
|
|
|
|
|
|
@@ -359,47 +306,6 @@ public final class RemoteClusterService extends AbstractComponent implements Clo
|
|
|
updateRemoteClusters(Collections.singletonMap(clusterAlias, nodes), connectionListener);
|
|
|
}
|
|
|
|
|
|
- static Map<String, List<DiscoveryNode>> buildRemoteClustersSeeds(Settings settings) {
|
|
|
- Stream<Setting<List<InetSocketAddress>>> allConcreteSettings = REMOTE_CLUSTERS_SEEDS.getAllConcreteSettings(settings);
|
|
|
- return allConcreteSettings.collect(
|
|
|
- Collectors.toMap(REMOTE_CLUSTERS_SEEDS::getNamespace, concreteSetting -> {
|
|
|
- String clusterName = REMOTE_CLUSTERS_SEEDS.getNamespace(concreteSetting);
|
|
|
- List<DiscoveryNode> nodes = new ArrayList<>();
|
|
|
- for (InetSocketAddress address : concreteSetting.get(settings)) {
|
|
|
- TransportAddress transportAddress = new TransportAddress(address);
|
|
|
- DiscoveryNode node = new DiscoveryNode(clusterName + "#" + transportAddress.toString(),
|
|
|
- transportAddress,
|
|
|
- Version.CURRENT.minimumCompatibilityVersion());
|
|
|
- nodes.add(node);
|
|
|
- }
|
|
|
- return nodes;
|
|
|
- }));
|
|
|
- }
|
|
|
-
|
|
|
- private static InetSocketAddress parseSeedAddress(String remoteHost) {
|
|
|
- int portSeparator = remoteHost.lastIndexOf(':'); // in case we have a IPv6 address ie. [::1]:9300
|
|
|
- if (portSeparator == -1 || portSeparator == remoteHost.length()) {
|
|
|
- throw new IllegalArgumentException("remote hosts need to be configured as [host:port], found [" + remoteHost + "] instead");
|
|
|
- }
|
|
|
- String host = remoteHost.substring(0, portSeparator);
|
|
|
- InetAddress hostAddress;
|
|
|
- try {
|
|
|
- hostAddress = InetAddress.getByName(host);
|
|
|
- } catch (UnknownHostException e) {
|
|
|
- throw new IllegalArgumentException("unknown host [" + host + "]", e);
|
|
|
- }
|
|
|
- try {
|
|
|
- int port = Integer.valueOf(remoteHost.substring(portSeparator + 1));
|
|
|
- if (port <= 0) {
|
|
|
- throw new IllegalArgumentException("port number must be > 0 but was: [" + port + "]");
|
|
|
- }
|
|
|
- return new InetSocketAddress(hostAddress, port);
|
|
|
- } catch (NumberFormatException e) {
|
|
|
- throw new IllegalArgumentException("port must be a number", e);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Connects to all remote clusters in a blocking fashion. This should be called on node startup to establish an initial connection
|
|
|
* to all configured seed nodes.
|
|
|
@@ -407,7 +313,7 @@ public final class RemoteClusterService extends AbstractComponent implements Clo
|
|
|
void initializeRemoteClusters() {
|
|
|
final TimeValue timeValue = REMOTE_INITIAL_CONNECTION_TIMEOUT_SETTING.get(settings);
|
|
|
final PlainActionFuture<Void> future = new PlainActionFuture<>();
|
|
|
- Map<String, List<DiscoveryNode>> seeds = buildRemoteClustersSeeds(settings);
|
|
|
+ Map<String, List<DiscoveryNode>> seeds = RemoteClusterAware.buildRemoteClustersSeeds(settings);
|
|
|
updateRemoteClusters(seeds, future);
|
|
|
try {
|
|
|
future.get(timeValue.millis(), TimeUnit.MILLISECONDS);
|