/*
* 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.health;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.routing.IndexRoutingTable;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.rest.RestStatus;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public final class ClusterStateHealth implements Iterable<ClusterIndexHealth>, Writeable {
private final int numberOfNodes;
private final int numberOfDataNodes;
private final int activeShards;
private final int relocatingShards;
private final int activePrimaryShards;
private final int initializingShards;
private final int unassignedShards;
private final double activeShardsPercent;
private final ClusterHealthStatus status;
private final Map<String, ClusterIndexHealth> indices = new HashMap<>();
/**
* Creates a new <code>ClusterStateHealth</code> instance considering the current cluster state and all indices in the cluster.
*
* @param clusterState The current cluster state. Must not be null.
*/
public ClusterStateHealth(final ClusterState clusterState) {
this(clusterState, clusterState.metaData().getConcreteAllIndices());
}
/**
* Creates a new <code>ClusterStateHealth</code> instance considering the current cluster state and the provided index names.
*
* @param clusterState The current cluster state. Must not be null.
* @param concreteIndices An array of index names to consider. Must not be null but may be empty.
*/
public ClusterStateHealth(final ClusterState clusterState, final String[] concreteIndices) {
numberOfNodes = clusterState.nodes().getSize();
numberOfDataNodes = clusterState.nodes().getDataNodes().size();
for (String index : concreteIndices) {
IndexRoutingTable indexRoutingTable = clusterState.routingTable().index(index);
IndexMetaData indexMetaData = clusterState.metaData().index(index);
if (indexRoutingTable == null) {
continue;
}
ClusterIndexHealth indexHealth = new ClusterIndexHealth(indexMetaData, indexRoutingTable);
indices.put(indexHealth.getIndex(), indexHealth);
}
ClusterHealthStatus computeStatus = ClusterHealthStatus.GREEN;
int computeActivePrimaryShards = 0;
int computeActiveShards = 0;
int computeRelocatingShards = 0;
int computeInitializingShards = 0;
int computeUnassignedShards = 0;
for (ClusterIndexHealth indexHealth : indices.values()) {
computeActivePrimaryShards += indexHealth.getActivePrimaryShards();
computeActiveShards += indexHealth.getActiveShards();
computeRelocatingShards += indexHealth.getRelocatingShards();
computeInitializingShards += indexHealth.getInitializingShards();
computeUnassignedShards += indexHealth.getUnassignedShards();
if (indexHealth.getStatus() == ClusterHealthStatus.RED) {
computeStatus = ClusterHealthStatus.RED;
} else if (indexHealth.getStatus() == ClusterHealthStatus.YELLOW && computeStatus != ClusterHealthStatus.RED) {
computeStatus = ClusterHealthStatus.YELLOW;
}
}
if (clusterState.blocks().hasGlobalBlock(RestStatus.SERVICE_UNAVAILABLE)) {
computeStatus = ClusterHealthStatus.RED;
}
this.status = computeStatus;
this.activePrimaryShards = computeActivePrimaryShards;
this.activeShards = computeActiveShards;
this.relocatingShards = computeRelocatingShards;
this.initializingShards = computeInitializingShards;
this.unassignedShards = computeUnassignedShards;
// shortcut on green
if (computeStatus.equals(ClusterHealthStatus.GREEN)) {
this.activeShardsPercent = 100;
} else {
List<ShardRouting> shardRoutings = clusterState.getRoutingTable().allShards();
int activeShardCount = 0;
int totalShardCount = 0;
for (ShardRouting shardRouting : shardRoutings) {
if (shardRouting.active()) activeShardCount++;
totalShardCount++;
}
this.activeShardsPercent = (((double) activeShardCount) / totalShardCount) * 100;
}
}
public ClusterStateHealth(final StreamInput in) throws IOException {
activePrimaryShards = in.readVInt();
activeShards = in.readVInt();
relocatingShards = in.readVInt();
initializingShards = in.readVInt();
unassignedShards = in.readVInt();
numberOfNodes = in.readVInt();
numberOfDataNodes = in.readVInt();
status = ClusterHealthStatus.fromValue(in.readByte());
int size = in.readVInt();
for (int i = 0; i < size; i++) {
ClusterIndexHealth indexHealth = new ClusterIndexHealth(in);
indices.put(indexHealth.getIndex(), indexHealth);
}
activeShardsPercent = in.readDouble();
}
public int getActiveShards() {
return activeShards;
}
public int getRelocatingShards() {
return relocatingShards;
}
public int getActivePrimaryShards() {
return activePrimaryShards;
}
public int getInitializingShards() {
return initializingShards;
}
public int getUnassignedShards() {
return unassignedShards;
}
public int getNumberOfNodes() {
return this.numberOfNodes;
}
public int getNumberOfDataNodes() {
return this.numberOfDataNodes;
}
public ClusterHealthStatus getStatus() {
return status;
}
public Map<String, ClusterIndexHealth> getIndices() {
return Collections.unmodifiableMap(indices);
}
public double getActiveShardsPercent() {
return activeShardsPercent;
}
@Override
public Iterator<ClusterIndexHealth> iterator() {
return indices.values().iterator();
}
@Override
public void writeTo(final StreamOutput out) throws IOException {
out.writeVInt(activePrimaryShards);
out.writeVInt(activeShards);
out.writeVInt(relocatingShards);
out.writeVInt(initializingShards);
out.writeVInt(unassignedShards);
out.writeVInt(numberOfNodes);
out.writeVInt(numberOfDataNodes);
out.writeByte(status.value());
out.writeVInt(indices.size());
for (ClusterIndexHealth indexHealth : this) {
indexHealth.writeTo(out);
}
out.writeDouble(activeShardsPercent);
}
}