org.opensearch.cluster.node.DiscoveryNodes Maven / Gradle / Ivy
Show all versions of opensearch Show documentation
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.
*/
/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/
package org.opensearch.cluster.node;
import org.opensearch.LegacyESVersion;
import org.opensearch.Version;
import org.opensearch.cluster.AbstractDiffable;
import org.opensearch.cluster.Diff;
import org.opensearch.common.Booleans;
import org.opensearch.common.Nullable;
import org.opensearch.common.annotation.PublicApi;
import org.opensearch.common.regex.Regex;
import org.opensearch.common.util.set.Sets;
import org.opensearch.core.common.Strings;
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.core.common.transport.TransportAddress;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* This class holds all {@link DiscoveryNode} in the cluster and provides convenience methods to
* access, modify merge / diff discovery nodes.
*
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
public class DiscoveryNodes extends AbstractDiffable implements Iterable {
public static final DiscoveryNodes EMPTY_NODES = builder().build();
private final Map nodes;
private final Map dataNodes;
private final Map clusterManagerNodes;
private final Map ingestNodes;
private final String clusterManagerNodeId;
private final String localNodeId;
private final Version minNonClientNodeVersion;
private final Version maxNonClientNodeVersion;
private final Version maxNodeVersion;
private final Version minNodeVersion;
private DiscoveryNodes(
final Map nodes,
final Map dataNodes,
final Map clusterManagerNodes,
final Map ingestNodes,
String clusterManagerNodeId,
String localNodeId,
Version minNonClientNodeVersion,
Version maxNonClientNodeVersion,
Version maxNodeVersion,
Version minNodeVersion
) {
this.nodes = Collections.unmodifiableMap(nodes);
this.dataNodes = Collections.unmodifiableMap(dataNodes);
this.clusterManagerNodes = Collections.unmodifiableMap(clusterManagerNodes);
this.ingestNodes = Collections.unmodifiableMap(ingestNodes);
this.clusterManagerNodeId = clusterManagerNodeId;
this.localNodeId = localNodeId;
this.minNonClientNodeVersion = minNonClientNodeVersion;
this.maxNonClientNodeVersion = maxNonClientNodeVersion;
this.minNodeVersion = minNodeVersion;
this.maxNodeVersion = maxNodeVersion;
}
@Override
public Iterator iterator() {
return nodes.values().iterator();
}
/**
* Returns {@code true} if the local node is the elected cluster-manager node.
*/
public boolean isLocalNodeElectedClusterManager() {
if (localNodeId == null) {
// we don't know yet the local node id, return false
return false;
}
return localNodeId.equals(clusterManagerNodeId);
}
/**
* Returns {@code true} if the local node is the elected cluster-manager node.
*
* @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #isLocalNodeElectedClusterManager()}
*/
@Deprecated
public boolean isLocalNodeElectedMaster() {
return isLocalNodeElectedClusterManager();
}
/**
* Get the number of known nodes
*
* @return number of nodes
*/
public int getSize() {
return nodes.size();
}
/**
* Get a {@link Map} of the discovered nodes arranged by their ids
*
* @return {@link Map} of the discovered nodes arranged by their ids
*/
public Map getNodes() {
return this.nodes;
}
/**
* Get a {@link Map} of the discovered data nodes arranged by their ids
*
* @return {@link Map} of the discovered data nodes arranged by their ids
*/
public Map getDataNodes() {
return this.dataNodes;
}
/**
* Get a {@link Map} of the discovered cluster-manager nodes arranged by their ids
*
* @return {@link Map} of the discovered cluster-manager nodes arranged by their ids
*/
public Map getClusterManagerNodes() {
return this.clusterManagerNodes;
}
/**
* Get a {@link Map} of the discovered cluster-manager nodes arranged by their ids
*
* @return {@link Map} of the discovered cluster-manager nodes arranged by their ids
* @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #getClusterManagerNodes()}
*/
@Deprecated
public Map getMasterNodes() {
return getClusterManagerNodes();
}
/**
* @return All the ingest nodes arranged by their ids
*/
public Map getIngestNodes() {
return ingestNodes;
}
/**
* Get a {@link Map} of the discovered cluster-manager and data nodes arranged by their ids
*
* @return {@link Map} of the discovered cluster-manager and data nodes arranged by their ids
*/
public Map getClusterManagerAndDataNodes() {
final Map nodes = new HashMap<>(dataNodes);
nodes.putAll(clusterManagerNodes);
return Collections.unmodifiableMap(nodes);
}
/**
* Get a {@link Map} of the discovered cluster-manager and data nodes arranged by their ids
*
* @return {@link Map} of the discovered cluster-manager and data nodes arranged by their ids
* @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #getClusterManagerAndDataNodes()}
*/
@Deprecated
public Map getMasterAndDataNodes() {
return getClusterManagerAndDataNodes();
}
/**
* Get a {@link Map} of the coordinating only nodes (nodes which are neither cluster-manager, nor data, nor ingest nodes) arranged by their ids
*
* @return {@link Map} of the coordinating only nodes arranged by their ids
*/
public Map getCoordinatingOnlyNodes() {
final HashMap nodes = new HashMap<>(this.nodes);
nodes.keySet().removeAll(clusterManagerNodes.keySet());
nodes.keySet().removeAll(dataNodes.keySet());
nodes.keySet().removeAll(ingestNodes.keySet());
return Collections.unmodifiableMap(nodes);
}
/**
* Returns a stream of all nodes, with cluster-manager nodes at the front
*/
public Stream clusterManagersFirstStream() {
return Stream.concat(
StreamSupport.stream(Spliterators.spliterator(clusterManagerNodes.entrySet(), 0), false).map(cur -> cur.getValue()),
StreamSupport.stream(this.spliterator(), false).filter(n -> n.isClusterManagerNode() == false)
);
}
/**
* Returns a stream of all nodes, with cluster-manager nodes at the front
*
* @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #clusterManagersFirstStream()}
*/
@Deprecated
public Stream mastersFirstStream() {
return clusterManagersFirstStream();
}
/**
* Get a node by its id
*
* @param nodeId id of the wanted node
* @return wanted node if it exists. Otherwise null
*/
public DiscoveryNode get(String nodeId) {
return nodes.get(nodeId);
}
/**
* Determine if a given node id exists
*
* @param nodeId id of the node which existence should be verified
* @return true
if the node exists. Otherwise false
*/
public boolean nodeExists(String nodeId) {
return nodes.containsKey(nodeId);
}
/**
* Determine if a given node exists
*
* @param node of the node which existence should be verified
* @return true
if the node exists. Otherwise false
*/
public boolean nodeExists(DiscoveryNode node) {
DiscoveryNode existing = nodes.get(node.getId());
return existing != null && existing.equals(node);
}
/**
* Determine if the given node exists and has the right roles. Supported roles vary by version, and our local cluster state might
* have come via an older cluster-manager, so the roles may differ even if the node is otherwise identical.
*/
public boolean nodeExistsWithSameRoles(DiscoveryNode discoveryNode) {
final DiscoveryNode existing = nodes.get(discoveryNode.getId());
return existing != null && existing.equals(discoveryNode) && existing.getRoles().equals(discoveryNode.getRoles());
}
/**
* Determine if the given node exists and has the right version. During upgrade from Elasticsearch version as OpenSearch node run in
* BWC mode and can have the version as 7.10.2 in cluster state from older cluster-manager to OpenSearch cluster-manager.
*/
public boolean nodeExistsWithBWCVersion(DiscoveryNode discoveryNode) {
final DiscoveryNode existing = nodes.get(discoveryNode.getId());
return existing != null
&& existing.equals(discoveryNode)
&& existing.getVersion().equals(LegacyESVersion.V_7_10_2)
&& discoveryNode.getVersion().onOrAfter(Version.V_1_0_0);
}
/**
* Get the id of the cluster-manager node
*
* @return id of the cluster-manager
*/
public String getClusterManagerNodeId() {
return this.clusterManagerNodeId;
}
/**
* Get the id of the cluster-manager node
*
* @return id of the cluster-manager
* @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #getClusterManagerNodeId()}
*/
@Deprecated
public String getMasterNodeId() {
return getClusterManagerNodeId();
}
/**
* Get the id of the local node
*
* @return id of the local node
*/
public String getLocalNodeId() {
return this.localNodeId;
}
/**
* Get the local node
*
* @return local node
*/
public DiscoveryNode getLocalNode() {
return nodes.get(localNodeId);
}
/**
* Returns the cluster-manager node, or {@code null} if there is no cluster-manager node
*/
@Nullable
public DiscoveryNode getClusterManagerNode() {
if (clusterManagerNodeId != null) {
return nodes.get(clusterManagerNodeId);
}
return null;
}
/**
* Returns the cluster-manager node, or {@code null} if there is no cluster-manager node
*
* @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #getClusterManagerNode()}
*/
@Deprecated
@Nullable
public DiscoveryNode getMasterNode() {
return getClusterManagerNode();
}
/**
* Get a node by its address
*
* @param address {@link TransportAddress} of the wanted node
* @return node identified by the given address or null
if no such node exists
*/
public DiscoveryNode findByAddress(TransportAddress address) {
for (final DiscoveryNode node : nodes.values()) {
if (node.getAddress().equals(address)) {
return node;
}
}
return null;
}
/**
* Returns the version of the node with the oldest version in the cluster that is not a client node
*
* If there are no non-client nodes, Version.CURRENT will be returned.
*
* @return the oldest version in the cluster
*/
public Version getSmallestNonClientNodeVersion() {
return minNonClientNodeVersion;
}
/**
* Returns the version of the node with the youngest version in the cluster that is not a client node.
*
* If there are no non-client nodes, Version.CURRENT will be returned.
*
* @return the youngest version in the cluster
*/
public Version getLargestNonClientNodeVersion() {
return maxNonClientNodeVersion;
}
/**
* Returns the version of the node with the oldest version in the cluster.
*
* @return the oldest version in the cluster
*/
public Version getMinNodeVersion() {
return minNodeVersion;
}
/**
* Returns the version of the node with the youngest version in the cluster
*
* @return the youngest version in the cluster
*/
public Version getMaxNodeVersion() {
return maxNodeVersion;
}
/**
* Resolve a node with a given id
*
* @param node id of the node to discover
* @return discovered node matching the given id
* @throws IllegalArgumentException if more than one node matches the request or no nodes have been resolved
*/
public DiscoveryNode resolveNode(String node) {
String[] resolvedNodeIds = resolveNodes(node);
if (resolvedNodeIds.length > 1) {
throw new IllegalArgumentException(
"resolved [" + node + "] into [" + resolvedNodeIds.length + "] nodes, where expected to be resolved to a single node"
);
}
if (resolvedNodeIds.length == 0) {
throw new IllegalArgumentException("failed to resolve [" + node + "], no matching nodes");
}
return nodes.get(resolvedNodeIds[0]);
}
/**
* Resolves a set of nodes according to the given sequence of node specifications. Implements the logic in various APIs that allow the
* user to run the action on a subset of the nodes in the cluster. See [Node specification] in the reference manual for full details.
*
* Works by tracking the current set of nodes and applying each node specification in sequence. The set starts out empty and each node
* specification may either add or remove nodes. For instance:
*
* - _local, _cluster_manager (_master) and _all respectively add to the subset the local node, the currently-elected cluster_manager, and all the nodes
* - node IDs, names, hostnames and IP addresses all add to the subset any nodes which match
* - a wildcard-based pattern of the form "attr*:value*" adds to the subset all nodes with a matching attribute with a matching value
* - role:true adds to the subset all nodes with a matching role
* - role:false removes from the subset all nodes with a matching role.
*
* An empty sequence of node specifications returns all nodes, since the corresponding actions run on all nodes by default.
*/
public String[] resolveNodes(String... nodes) {
if (nodes == null || nodes.length == 0) {
return StreamSupport.stream(this.spliterator(), false).map(DiscoveryNode::getId).toArray(String[]::new);
} else {
final HashSet resolvedNodesIds = new HashSet<>(nodes.length);
for (String nodeId : nodes) {
if (nodeId == null) {
// don't silence the underlying issue, it is a bug, so lets fail if assertions are enabled
assert nodeId != null : "nodeId should not be null";
continue;
} else if (nodeId.equals("_local")) {
String localNodeId = getLocalNodeId();
if (localNodeId != null) {
resolvedNodesIds.add(localNodeId);
}
} else if (nodeId.equals("_master") || nodeId.equals("_cluster_manager")) {
String clusterManagerNodeId = getClusterManagerNodeId();
if (clusterManagerNodeId != null) {
resolvedNodesIds.add(clusterManagerNodeId);
}
} else if (nodeExists(nodeId)) {
resolvedNodesIds.add(nodeId);
} else {
for (DiscoveryNode node : this) {
if ("_all".equals(nodeId)
|| Regex.simpleMatch(nodeId, node.getName())
|| Regex.simpleMatch(nodeId, node.getHostAddress())
|| Regex.simpleMatch(nodeId, node.getHostName())) {
resolvedNodesIds.add(node.getId());
}
}
int index = nodeId.indexOf(':');
if (index != -1) {
String matchAttrName = nodeId.substring(0, index);
String matchAttrValue = nodeId.substring(index + 1);
if (DiscoveryNodeRole.DATA_ROLE.roleName().equals(matchAttrName)) {
if (Booleans.parseBoolean(matchAttrValue, true)) {
resolvedNodesIds.addAll(dataNodes.keySet());
} else {
resolvedNodesIds.removeAll(dataNodes.keySet());
}
} else if (roleNameIsClusterManager(matchAttrName)) {
if (Booleans.parseBoolean(matchAttrValue, true)) {
resolvedNodesIds.addAll(clusterManagerNodes.keySet());
} else {
resolvedNodesIds.removeAll(clusterManagerNodes.keySet());
}
} else if (DiscoveryNodeRole.INGEST_ROLE.roleName().equals(matchAttrName)) {
if (Booleans.parseBoolean(matchAttrValue, true)) {
resolvedNodesIds.addAll(ingestNodes.keySet());
} else {
resolvedNodesIds.removeAll(ingestNodes.keySet());
}
} else if (DiscoveryNode.COORDINATING_ONLY.equals(matchAttrName)) {
if (Booleans.parseBoolean(matchAttrValue, true)) {
resolvedNodesIds.addAll(getCoordinatingOnlyNodes().keySet());
} else {
resolvedNodesIds.removeAll(getCoordinatingOnlyNodes().keySet());
}
} else {
for (DiscoveryNode node : this) {
for (DiscoveryNodeRole role : Sets.difference(node.getRoles(), DiscoveryNodeRole.BUILT_IN_ROLES)) {
if (role.roleName().equals(matchAttrName)) {
if (Booleans.parseBoolean(matchAttrValue, true)) {
resolvedNodesIds.add(node.getId());
} else {
resolvedNodesIds.remove(node.getId());
}
}
}
}
for (DiscoveryNode node : this) {
for (Map.Entry entry : node.getAttributes().entrySet()) {
String attrName = entry.getKey();
String attrValue = entry.getValue();
if (Regex.simpleMatch(matchAttrName, attrName) && Regex.simpleMatch(matchAttrValue, attrValue)) {
resolvedNodesIds.add(node.getId());
}
}
}
}
}
}
}
return resolvedNodesIds.toArray(new String[0]);
}
}
public DiscoveryNodes newNode(DiscoveryNode node) {
return new Builder(this).add(node).build();
}
/**
* Returns the changes comparing this nodes to the provided nodes.
*/
public Delta delta(DiscoveryNodes other) {
final List removed = new ArrayList<>();
final List added = new ArrayList<>();
for (DiscoveryNode node : other) {
if (this.nodeExists(node) == false) {
removed.add(node);
}
}
for (DiscoveryNode node : this) {
if (other.nodeExists(node) == false) {
added.add(node);
}
}
return new Delta(
other.getClusterManagerNode(),
getClusterManagerNode(),
localNodeId,
Collections.unmodifiableList(removed),
Collections.unmodifiableList(added)
);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("nodes: \n");
for (DiscoveryNode node : this) {
sb.append(" ").append(node);
if (node == getLocalNode()) {
sb.append(", local");
}
if (node == getClusterManagerNode()) {
sb.append(", cluster-manager");
}
sb.append("\n");
}
return sb.toString();
}
/**
* Delta between nodes.
*
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
public static class Delta {
private final String localNodeId;
@Nullable
private final DiscoveryNode previousClusterManagerNode;
@Nullable
private final DiscoveryNode newClusterManagerNode;
private final List removed;
private final List added;
private Delta(
@Nullable DiscoveryNode previousClusterManagerNode,
@Nullable DiscoveryNode newClusterManagerNode,
String localNodeId,
List removed,
List added
) {
this.previousClusterManagerNode = previousClusterManagerNode;
this.newClusterManagerNode = newClusterManagerNode;
this.localNodeId = localNodeId;
this.removed = removed;
this.added = added;
}
public boolean hasChanges() {
return clusterManagerNodeChanged() || !removed.isEmpty() || !added.isEmpty();
}
public boolean clusterManagerNodeChanged() {
return Objects.equals(newClusterManagerNode, previousClusterManagerNode) == false;
}
/** @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #clusterManagerNodeChanged()} */
@Deprecated
public boolean masterNodeChanged() {
return clusterManagerNodeChanged();
}
@Nullable
public DiscoveryNode previousClusterManagerNode() {
return previousClusterManagerNode;
}
/** @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #previousClusterManagerNode()} */
@Deprecated
@Nullable
public DiscoveryNode previousMasterNode() {
return previousClusterManagerNode();
}
@Nullable
public DiscoveryNode newClusterManagerNode() {
return newClusterManagerNode;
}
/** @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #newClusterManagerNode()} */
@Deprecated
@Nullable
public DiscoveryNode newMasterNode() {
return newClusterManagerNode();
}
public boolean removed() {
return !removed.isEmpty();
}
public List removedNodes() {
return removed;
}
public boolean added() {
return !added.isEmpty();
}
public List addedNodes() {
return added;
}
public String shortSummary() {
final StringBuilder summary = new StringBuilder();
if (clusterManagerNodeChanged()) {
summary.append("cluster-manager node changed {previous [");
if (previousClusterManagerNode() != null) {
summary.append(previousClusterManagerNode());
}
summary.append("], current [");
if (newClusterManagerNode() != null) {
summary.append(newClusterManagerNode());
}
summary.append("]}");
}
if (removed()) {
if (summary.length() > 0) {
summary.append(", ");
}
summary.append("removed {").append(Strings.collectionToCommaDelimitedString(removedNodes())).append('}');
}
if (added()) {
final String addedNodesExceptLocalNode = addedNodes().stream()
.filter(node -> node.getId().equals(localNodeId) == false)
.map(DiscoveryNode::toString)
.collect(Collectors.joining(","));
if (addedNodesExceptLocalNode.length() > 0) {
// ignore ourselves when reporting on nodes being added
if (summary.length() > 0) {
summary.append(", ");
}
summary.append("added {").append(addedNodesExceptLocalNode).append('}');
}
}
return summary.toString();
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
if (clusterManagerNodeId == null) {
out.writeBoolean(false);
} else {
out.writeBoolean(true);
out.writeString(clusterManagerNodeId);
}
out.writeVInt(nodes.size());
for (DiscoveryNode node : this) {
node.writeTo(out);
}
}
public static DiscoveryNodes readFrom(StreamInput in, DiscoveryNode localNode) throws IOException {
Builder builder = new Builder();
if (in.readBoolean()) {
builder.clusterManagerNodeId(in.readString());
}
if (localNode != null) {
builder.localNodeId(localNode.getId());
}
int size = in.readVInt();
for (int i = 0; i < size; i++) {
DiscoveryNode node = new DiscoveryNode(in);
if (localNode != null && node.getId().equals(localNode.getId())) {
// reuse the same instance of our address and local node id for faster equality
node = localNode;
}
// some one already built this and validated it's OK, skip the n2 scans
assert builder.validateAdd(node) == null : "building disco nodes from network doesn't pass preflight: "
+ builder.validateAdd(node);
builder.putUnsafe(node);
}
return builder.build();
}
public static Diff readDiffFrom(StreamInput in, DiscoveryNode localNode) throws IOException {
return AbstractDiffable.readDiffFrom(in1 -> readFrom(in1, localNode), in);
}
public static Builder builder() {
return new Builder();
}
public static Builder builder(DiscoveryNodes nodes) {
return new Builder(nodes);
}
/**
* Builder of a map of discovery nodes.
*
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
public static class Builder {
private final Map nodes;
private String clusterManagerNodeId;
private String localNodeId;
public Builder() {
nodes = new HashMap<>();
}
public Builder(DiscoveryNodes nodes) {
this.clusterManagerNodeId = nodes.getClusterManagerNodeId();
this.localNodeId = nodes.getLocalNodeId();
this.nodes = new HashMap<>(nodes.getNodes());
}
/**
* adds a disco node to the builder. Will throw an {@link IllegalArgumentException} if
* the supplied node doesn't pass the pre-flight checks performed by {@link #validateAdd(DiscoveryNode)}
*/
public Builder add(DiscoveryNode node) {
final String preflight = validateAdd(node);
if (preflight != null) {
throw new IllegalArgumentException(preflight);
}
putUnsafe(node);
return this;
}
/**
* Get a node by its id
*
* @param nodeId id of the wanted node
* @return wanted node if it exists. Otherwise null
*/
@Nullable
public DiscoveryNode get(String nodeId) {
return nodes.get(nodeId);
}
private void putUnsafe(DiscoveryNode node) {
nodes.put(node.getId(), node);
}
public Builder remove(String nodeId) {
nodes.remove(nodeId);
return this;
}
public Builder remove(DiscoveryNode node) {
if (node.equals(nodes.get(node.getId()))) {
nodes.remove(node.getId());
}
return this;
}
public Builder clusterManagerNodeId(String clusterManagerNodeId) {
this.clusterManagerNodeId = clusterManagerNodeId;
return this;
}
/** @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #clusterManagerNodeId} */
@Deprecated
public Builder masterNodeId(String clusterManagerNodeId) {
return clusterManagerNodeId(clusterManagerNodeId);
}
public Builder localNodeId(String localNodeId) {
this.localNodeId = localNodeId;
return this;
}
/**
* Checks that a node can be safely added to this node collection.
*
* @return null if all is OK or an error message explaining why a node can not be added.
*
* Note: if this method returns a non-null value, calling {@link #add(DiscoveryNode)} will fail with an
* exception
*/
private String validateAdd(DiscoveryNode node) {
for (final DiscoveryNode existingNode : nodes.values()) {
if (node.getAddress().equals(existingNode.getAddress()) && node.getId().equals(existingNode.getId()) == false) {
return "can't add node " + node + ", found existing node " + existingNode + " with same address";
}
if (node.getId().equals(existingNode.getId()) && node.equals(existingNode) == false) {
return "can't add node "
+ node
+ ", found existing node "
+ existingNode
+ " with the same id but is a different node instance";
}
}
return null;
}
public DiscoveryNodes build() {
final Map dataNodesBuilder = new HashMap<>();
final Map clusterManagerNodesBuilder = new HashMap<>();
final Map ingestNodesBuilder = new HashMap<>();
Version minNodeVersion = null;
Version maxNodeVersion = null;
Version minNonClientNodeVersion = null;
Version maxNonClientNodeVersion = null;
for (final Map.Entry nodeEntry : nodes.entrySet()) {
if (nodeEntry.getValue().isDataNode()) {
dataNodesBuilder.put(nodeEntry.getKey(), nodeEntry.getValue());
}
if (nodeEntry.getValue().isClusterManagerNode()) {
clusterManagerNodesBuilder.put(nodeEntry.getKey(), nodeEntry.getValue());
}
final Version version = nodeEntry.getValue().getVersion();
if (nodeEntry.getValue().isDataNode() || nodeEntry.getValue().isClusterManagerNode()) {
if (minNonClientNodeVersion == null) {
minNonClientNodeVersion = version;
maxNonClientNodeVersion = version;
} else {
minNonClientNodeVersion = Version.min(minNonClientNodeVersion, version);
maxNonClientNodeVersion = Version.max(maxNonClientNodeVersion, version);
}
}
if (nodeEntry.getValue().isIngestNode()) {
ingestNodesBuilder.put(nodeEntry.getKey(), nodeEntry.getValue());
}
minNodeVersion = minNodeVersion == null ? version : Version.min(minNodeVersion, version);
maxNodeVersion = maxNodeVersion == null ? version : Version.max(maxNodeVersion, version);
}
return new DiscoveryNodes(
nodes,
dataNodesBuilder,
clusterManagerNodesBuilder,
ingestNodesBuilder,
clusterManagerNodeId,
localNodeId,
minNonClientNodeVersion == null ? Version.CURRENT : minNonClientNodeVersion,
maxNonClientNodeVersion == null ? Version.CURRENT : maxNonClientNodeVersion,
maxNodeVersion == null ? Version.CURRENT : maxNodeVersion,
minNodeVersion == null ? Version.CURRENT : minNodeVersion
);
}
public boolean isLocalNodeElectedClusterManager() {
return clusterManagerNodeId != null && clusterManagerNodeId.equals(localNodeId);
}
/** @deprecated As of 2.2, because supporting inclusive language, replaced by {@link #isLocalNodeElectedClusterManager()} */
@Deprecated
public boolean isLocalNodeElectedMaster() {
return isLocalNodeElectedClusterManager();
}
}
/**
* Check if the given name of the node role is 'cluster_manager' or 'master'.
* The method is added for {@link #resolveNodes} to keep the code clear, when support the both above roles.
* @deprecated As of 2.0, because promoting inclusive language. MASTER_ROLE is deprecated.
* @param matchAttrName a given String for a name of the node role.
* @return true if the given roleName is 'cluster_manger' or 'master'
*/
@Deprecated
private boolean roleNameIsClusterManager(String matchAttrName) {
return DiscoveryNodeRole.MASTER_ROLE.roleName().equals(matchAttrName)
|| DiscoveryNodeRole.CLUSTER_MANAGER_ROLE.roleName().equals(matchAttrName);
}
}