All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.cluster.node.DiscoveryNode Maven / Gradle / Ivy

There is a newer version: 8.14.1
Show newest version
/*
 * 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.
 */

package org.elasticsearch.cluster.node;

import org.elasticsearch.Version;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.transport.TransportAddressSerializers;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.node.Node;

import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

import static org.elasticsearch.common.transport.TransportAddressSerializers.addressToStream;

/**
 * A discovery node represents a node that is part of the cluster.
 */
public class DiscoveryNode implements Writeable, ToXContent {

    public static boolean nodeRequiresLocalStorage(Settings settings) {
        boolean localStorageEnable = Node.NODE_LOCAL_STORAGE_SETTING.get(settings);
        if (localStorageEnable == false &&
            (Node.NODE_DATA_SETTING.get(settings) ||
                Node.NODE_MASTER_SETTING.get(settings))
            ) {
            // TODO: make this a proper setting validation logic, requiring multi-settings validation
            throw new IllegalArgumentException("storage can not be disabled for master and data nodes");
        }
        return localStorageEnable;
    }

    public static boolean isMasterNode(Settings settings) {
        return Node.NODE_MASTER_SETTING.get(settings);
    }

    public static boolean isDataNode(Settings settings) {
        return Node.NODE_DATA_SETTING.get(settings);
    }

    public static boolean isIngestNode(Settings settings) {
        return Node.NODE_INGEST_SETTING.get(settings);
    }

    private final String nodeName;
    private final String nodeId;
    private final String ephemeralId;
    private final String hostName;
    private final String hostAddress;
    private final TransportAddress address;
    private final Map attributes;
    private final Version version;
    private final Set roles;


    /**
     * Creates a new {@link DiscoveryNode}
     * 

* Note: if the version of the node is unknown {@link Version#minimumCompatibilityVersion()} should be used for the current * version. it corresponds to the minimum version this elasticsearch version can communicate with. If a higher version is used * the node might not be able to communicate with the remove node. After initial handshakes node versions will be discovered * and updated. *

* * @param id the nodes unique (persistent) node id. This constructor will auto generate a random ephemeral id. * @param address the nodes transport address * @param version the version of the node */ public DiscoveryNode(final String id, TransportAddress address, Version version) { this(id, address, Collections.emptyMap(), EnumSet.allOf(Role.class), version); } /** * Creates a new {@link DiscoveryNode} *

* Note: if the version of the node is unknown {@link Version#minimumCompatibilityVersion()} should be used for the current * version. it corresponds to the minimum version this elasticsearch version can communicate with. If a higher version is used * the node might not be able to communicate with the remove node. After initial handshakes node versions will be discovered * and updated. *

* * @param id the nodes unique (persistent) node id. This constructor will auto generate a random ephemeral id. * @param address the nodes transport address * @param attributes node attributes * @param roles node roles * @param version the version of the node */ public DiscoveryNode(String id, TransportAddress address, Map attributes, Set roles, Version version) { this("", id, address, attributes, roles, version); } /** * Creates a new {@link DiscoveryNode} *

* Note: if the version of the node is unknown {@link Version#minimumCompatibilityVersion()} should be used for the current * version. it corresponds to the minimum version this elasticsearch version can communicate with. If a higher version is used * the node might not be able to communicate with the remove node. After initial handshakes node versions will be discovered * and updated. *

* * @param nodeName the nodes name * @param nodeId the nodes unique persistent id. An ephemeral id will be auto generated. * @param address the nodes transport address * @param attributes node attributes * @param roles node roles * @param version the version of the node */ public DiscoveryNode(String nodeName, String nodeId, TransportAddress address, Map attributes, Set roles, Version version) { this(nodeName, nodeId, UUIDs.randomBase64UUID(), address.getHost(), address.getAddress(), address, attributes, roles, version); } /** * Creates a new {@link DiscoveryNode}. *

* Note: if the version of the node is unknown {@link Version#minimumCompatibilityVersion()} should be used for the current * version. it corresponds to the minimum version this elasticsearch version can communicate with. If a higher version is used * the node might not be able to communicate with the remove node. After initial handshakes node versions will be discovered * and updated. *

* * @param nodeName the nodes name * @param nodeId the nodes unique persistent id * @param ephemeralId the nodes unique ephemeral id * @param hostAddress the nodes host address * @param address the nodes transport address * @param attributes node attributes * @param roles node roles * @param version the version of the node */ public DiscoveryNode(String nodeName, String nodeId, String ephemeralId, String hostName, String hostAddress, TransportAddress address, Map attributes, Set roles, Version version) { if (nodeName != null) { this.nodeName = nodeName.intern(); } else { this.nodeName = ""; } this.nodeId = nodeId.intern(); this.ephemeralId = ephemeralId.intern(); this.hostName = hostName.intern(); this.hostAddress = hostAddress.intern(); this.address = address; if (version == null) { this.version = Version.CURRENT; } else { this.version = version; } this.attributes = Collections.unmodifiableMap(attributes); //verify that no node roles are being provided as attributes Predicate> predicate = (attrs) -> { for (Role role : Role.values()) { assert attrs.containsKey(role.getRoleName()) == false; } return true; }; assert predicate.test(attributes); Set rolesSet = EnumSet.noneOf(Role.class); rolesSet.addAll(roles); this.roles = Collections.unmodifiableSet(rolesSet); } /** Creates a DiscoveryNode representing the local node. */ public static DiscoveryNode createLocal(Settings settings, TransportAddress publishAddress, String nodeId) { Map attributes = new HashMap<>(Node.NODE_ATTRIBUTES.get(settings).getAsMap()); Set roles = getRolesFromSettings(settings); return new DiscoveryNode(Node.NODE_NAME_SETTING.get(settings), nodeId, publishAddress, attributes, roles, Version.CURRENT); } /** extract node roles from the given settings */ public static Set getRolesFromSettings(Settings settings) { Set roles = EnumSet.noneOf(Role.class); if (Node.NODE_INGEST_SETTING.get(settings)) { roles.add(Role.INGEST); } if (Node.NODE_MASTER_SETTING.get(settings)) { roles.add(Role.MASTER); } if (Node.NODE_DATA_SETTING.get(settings)) { roles.add(Role.DATA); } return roles; } /** * Creates a new {@link DiscoveryNode} by reading from the stream provided as argument * @param in the stream * @throws IOException if there is an error while reading from the stream */ public DiscoveryNode(StreamInput in) throws IOException { this.nodeName = in.readString().intern(); this.nodeId = in.readString().intern(); this.ephemeralId = in.readString().intern(); this.hostName = in.readString().intern(); this.hostAddress = in.readString().intern(); if (in.getVersion().after(Version.V_5_0_2)) { this.address = TransportAddressSerializers.addressFromStream(in); } else { // we need to do this to preserve the host information during pinging and joining of a master. Since the version of the // DiscoveryNode is set to Version#minimumCompatibilityVersion(), the host information gets lost as we do not serialize the // hostString for the address this.address = TransportAddressSerializers.addressFromStream(in, hostName); } int size = in.readVInt(); this.attributes = new HashMap<>(size); for (int i = 0; i < size; i++) { this.attributes.put(in.readString(), in.readString()); } int rolesSize = in.readVInt(); this.roles = EnumSet.noneOf(Role.class); for (int i = 0; i < rolesSize; i++) { this.roles.add(in.readEnum(Role.class)); } this.version = Version.readVersion(in); } @Override public void writeTo(StreamOutput out) throws IOException { out.writeString(nodeName); out.writeString(nodeId); out.writeString(ephemeralId); out.writeString(hostName); out.writeString(hostAddress); addressToStream(out, address); out.writeVInt(attributes.size()); for (Map.Entry entry : attributes.entrySet()) { out.writeString(entry.getKey()); out.writeString(entry.getValue()); } out.writeVInt(roles.size()); for (Role role : roles) { out.writeEnum(role); } Version.writeVersion(version, out); } /** * The address that the node can be communicated with. */ public TransportAddress getAddress() { return address; } /** * The unique id of the node. */ public String getId() { return nodeId; } /** * The unique ephemeral id of the node. Ephemeral ids are meant to be attached the the life span * of a node process. When ever a node is restarted, it's ephemeral id is required to change (while it's {@link #getId()} * will be read from the data folder and will remain the same across restarts). Since all node attributes and addresses * are maintained during the life span of a node process, we can (and are) using the ephemeralId in * {@link DiscoveryNode#equals(Object)}. */ public String getEphemeralId() { return ephemeralId; } /** * The name of the node. */ public String getName() { return this.nodeName; } /** * The node attributes. */ public Map getAttributes() { return this.attributes; } /** * Should this node hold data (shards) or not. */ public boolean isDataNode() { return roles.contains(Role.DATA); } /** * Can this node become master or not. */ public boolean isMasterNode() { return roles.contains(Role.MASTER); } /** * Returns a boolean that tells whether this an ingest node or not */ public boolean isIngestNode() { return roles.contains(Role.INGEST); } /** * Returns a set of all the roles that the node fulfills. * If the node doesn't have any specific role, the set is returned empty, which means that the node is a coordinating only node. */ public Set getRoles() { return roles; } public Version getVersion() { return this.version; } public String getHostName() { return this.hostName; } public String getHostAddress() { return this.hostAddress; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } DiscoveryNode that = (DiscoveryNode) o; return ephemeralId.equals(that.ephemeralId); } @Override public int hashCode() { // we only need to hash the id because it's highly unlikely that two nodes // in our system will have the same id but be different // This is done so that this class can be used efficiently as a key in a map return ephemeralId.hashCode(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (nodeName.length() > 0) { sb.append('{').append(nodeName).append('}'); } sb.append('{').append(nodeId).append('}'); sb.append('{').append(ephemeralId).append('}'); sb.append('{').append(hostName).append('}'); sb.append('{').append(address).append('}'); if (!attributes.isEmpty()) { sb.append(attributes); } return sb.toString(); } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(getId()); builder.field("name", getName()); builder.field("ephemeral_id", getEphemeralId()); builder.field("transport_address", getAddress().toString()); builder.startObject("attributes"); for (Map.Entry entry : attributes.entrySet()) { builder.field(entry.getKey(), entry.getValue()); } builder.endObject(); builder.endObject(); return builder; } /** * Enum that holds all the possible roles that that a node can fulfill in a cluster. * Each role has its name and a corresponding abbreviation used by cat apis. */ public enum Role { MASTER("master", "m"), DATA("data", "d"), INGEST("ingest", "i"); private final String roleName; private final String abbreviation; Role(String roleName, String abbreviation) { this.roleName = roleName; this.abbreviation = abbreviation; } public String getRoleName() { return roleName; } public String getAbbreviation() { return abbreviation; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy