Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ task verifyVersions {
* the enabled state of every bwc task. It should be set back to true
* after the backport of the backcompat code is complete.
*/
final boolean bwc_tests_enabled = true
final String bwc_tests_disabled_issue = "" /* place a PR link here when committing bwc changes */
final boolean bwc_tests_enabled = false
final String bwc_tests_disabled_issue = "https://github.com/elastic/elasticsearch/pull/38568"
if (bwc_tests_enabled == false) {
if (bwc_tests_disabled_issue.isEmpty()) {
throw new GradleException("bwc_tests_disabled_issue must be set when bwc_tests_enabled == false")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ public void testClusterHealth() throws IOException {
// tag::health-response-nodes
int numberOfNodes = response.getNumberOfNodes(); // <1>
int numberOfDataNodes = response.getNumberOfDataNodes(); // <2>
boolean hasVotingExclusions = response.hasVotingExclusions(); // <3>
// end::health-response-nodes

{
Expand Down
28 changes: 15 additions & 13 deletions docs/java-api/admin/cluster/health.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,28 @@ some technical information about the cluster status per index:
[source,java]
--------------------------------------------------
ClusterHealthResponse healths = client.admin().cluster().prepareHealth().get(); <1>
String clusterName = healths.getClusterName(); <2>
int numberOfDataNodes = healths.getNumberOfDataNodes(); <3>
int numberOfNodes = healths.getNumberOfNodes(); <4>
String clusterName = healths.getClusterName(); <2>
int numberOfDataNodes = healths.getNumberOfDataNodes(); <3>
int numberOfNodes = healths.getNumberOfNodes(); <4>
boolean hasVotingExclusions = healths.hasVotingExclusions(); <5>

for (ClusterIndexHealth health : healths.getIndices().values()) { <5>
String index = health.getIndex(); <6>
int numberOfShards = health.getNumberOfShards(); <7>
int numberOfReplicas = health.getNumberOfReplicas(); <8>
ClusterHealthStatus status = health.getStatus(); <9>
for (ClusterIndexHealth health : healths.getIndices().values()) { <6>
String index = health.getIndex(); <7>
int numberOfShards = health.getNumberOfShards(); <8>
int numberOfReplicas = health.getNumberOfReplicas(); <9>
ClusterHealthStatus status = health.getStatus(); <10>
}
--------------------------------------------------
<1> Get information for all indices
<2> Access the cluster name
<3> Get the total number of data nodes
<4> Get the total number of nodes
<5> Iterate over all indices
<6> Index name
<7> Number of shards
<8> Number of replicas
<9> Index status
<5> Check if there are <<voting-config-exclusions, voting exclusions>> in the cluster state
<6> Iterate over all indices
<7> Index name
<8> Number of shards
<9> Number of replicas
<10> Index status

[[java-admin-cluster-health-wait-status]]
===== Wait for status
Expand Down
1 change: 1 addition & 0 deletions docs/java-rest/high-level/cluster/health.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ include-tagged::{doc-tests-file}[{api}-response-nodes]
--------------------------------------------------
<1> Number of nodes in the cluster
<2> Number of data nodes in the cluster
<3> Whether cluster has <<voting-config-exclusions, voting exclusions>>

["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions docs/reference/cluster/health.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Returns this:
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"has_voting_exclusions" : false,
"active_primary_shards" : 1,
"active_shards" : 1,
"relocating_shards" : 0,
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/cluster/voting-exclusions.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ default value is `10`. Since voting configuration exclusions are persistent and
limited in number, you must clear the voting config exclusions list once the
exclusions are no longer required.

NOTE: Clusters should have no voting configuration exclusions in normal operation.

There is also a
<<modules-discovery-settings,`cluster.auto_shrink_voting_configuration` setting>>,
which is set to true by default. If it is set to false, you must use this API to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public class ClusterHealthResponse extends ActionResponse implements StatusToXCo
private static final String TIMED_OUT = "timed_out";
private static final String NUMBER_OF_NODES = "number_of_nodes";
private static final String NUMBER_OF_DATA_NODES = "number_of_data_nodes";
private static final String HAS_VOTING_EXCLUSIONS = "has_voting_exclusions";
private static final String NUMBER_OF_PENDING_TASKS = "number_of_pending_tasks";
private static final String NUMBER_OF_IN_FLIGHT_FETCH = "number_of_in_flight_fetch";
private static final String DELAYED_UNASSIGNED_SHARDS = "delayed_unassigned_shards";
Expand All @@ -74,6 +75,7 @@ public class ClusterHealthResponse extends ActionResponse implements StatusToXCo
// ClusterStateHealth fields
int numberOfNodes = (int) parsedObjects[i++];
int numberOfDataNodes = (int) parsedObjects[i++];
boolean hasVotingExclusions = (boolean) parsedObjects[i++];
int activeShards = (int) parsedObjects[i++];
int relocatingShards = (int) parsedObjects[i++];
int activePrimaryShards = (int) parsedObjects[i++];
Expand All @@ -93,8 +95,8 @@ public class ClusterHealthResponse extends ActionResponse implements StatusToXCo
}
}
ClusterStateHealth stateHealth = new ClusterStateHealth(activePrimaryShards, activeShards, relocatingShards,
initializingShards, unassignedShards, numberOfNodes, numberOfDataNodes, activeShardsPercent, status,
indices);
initializingShards, unassignedShards, numberOfNodes, numberOfDataNodes, hasVotingExclusions,
activeShardsPercent, status, indices);

// ClusterHealthResponse fields
String clusterName = (String) parsedObjects[i++];
Expand All @@ -114,6 +116,7 @@ public class ClusterHealthResponse extends ActionResponse implements StatusToXCo
// ClusterStateHealth fields
PARSER.declareInt(constructorArg(), new ParseField(NUMBER_OF_NODES));
PARSER.declareInt(constructorArg(), new ParseField(NUMBER_OF_DATA_NODES));
PARSER.declareBoolean(constructorArg(), new ParseField(HAS_VOTING_EXCLUSIONS));
PARSER.declareInt(constructorArg(), new ParseField(ACTIVE_SHARDS));
PARSER.declareInt(constructorArg(), new ParseField(RELOCATING_SHARDS));
PARSER.declareInt(constructorArg(), new ParseField(ACTIVE_PRIMARY_SHARDS));
Expand Down Expand Up @@ -213,6 +216,10 @@ public int getNumberOfDataNodes() {
return clusterStateHealth.getNumberOfDataNodes();
}

public boolean hasVotingExclusions() {
return clusterStateHealth.hasVotingExclusions();
}

public int getNumberOfPendingTasks() {
return this.numberOfPendingTasks;
}
Expand Down Expand Up @@ -326,6 +333,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
builder.field(TIMED_OUT, isTimedOut());
builder.field(NUMBER_OF_NODES, getNumberOfNodes());
builder.field(NUMBER_OF_DATA_NODES, getNumberOfDataNodes());
builder.field(HAS_VOTING_EXCLUSIONS, hasVotingExclusions());
builder.field(ACTIVE_PRIMARY_SHARDS, getActivePrimaryShards());
builder.field(ACTIVE_SHARDS, getActiveShards());
builder.field(RELOCATING_SHARDS, getRelocatingShards());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.elasticsearch.cluster.health;

import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.routing.IndexRoutingTable;
Expand All @@ -40,6 +41,7 @@ public final class ClusterStateHealth implements Iterable<ClusterIndexHealth>, W

private final int numberOfNodes;
private final int numberOfDataNodes;
private final boolean hasVotingExclusions;
private final int activeShards;
private final int relocatingShards;
private final int activePrimaryShards;
Expand Down Expand Up @@ -67,6 +69,7 @@ public ClusterStateHealth(final ClusterState clusterState) {
public ClusterStateHealth(final ClusterState clusterState, final String[] concreteIndices) {
numberOfNodes = clusterState.nodes().getSize();
numberOfDataNodes = clusterState.nodes().getDataNodes().size();
hasVotingExclusions = clusterState.coordinationMetaData().getVotingConfigExclusions().isEmpty() == false;
indices = new HashMap<>();
for (String index : concreteIndices) {
IndexRoutingTable indexRoutingTable = clusterState.routingTable().index(index);
Expand Down Expand Up @@ -134,6 +137,11 @@ public ClusterStateHealth(final StreamInput in) throws IOException {
unassignedShards = in.readVInt();
numberOfNodes = in.readVInt();
numberOfDataNodes = in.readVInt();
if (in.getVersion().onOrAfter(Version.V_7_1_0)) {
hasVotingExclusions = in.readBoolean();
} else {
hasVotingExclusions = false;
}
status = ClusterHealthStatus.fromValue(in.readByte());
int size = in.readVInt();
indices = new HashMap<>(size);
Expand All @@ -148,7 +156,7 @@ public ClusterStateHealth(final StreamInput in) throws IOException {
* For ClusterHealthResponse's XContent Parser
*/
public ClusterStateHealth(int activePrimaryShards, int activeShards, int relocatingShards, int initializingShards, int unassignedShards,
int numberOfNodes, int numberOfDataNodes, double activeShardsPercent, ClusterHealthStatus status,
int numberOfNodes, int numberOfDataNodes, boolean hasVotingExclusions, double activeShardsPercent, ClusterHealthStatus status,
Map<String, ClusterIndexHealth> indices) {
this.activePrimaryShards = activePrimaryShards;
this.activeShards = activeShards;
Expand All @@ -157,6 +165,7 @@ public ClusterStateHealth(int activePrimaryShards, int activeShards, int relocat
this.unassignedShards = unassignedShards;
this.numberOfNodes = numberOfNodes;
this.numberOfDataNodes = numberOfDataNodes;
this.hasVotingExclusions = hasVotingExclusions;
this.activeShardsPercent = activeShardsPercent;
this.status = status;
this.indices = indices;
Expand Down Expand Up @@ -190,6 +199,10 @@ public int getNumberOfDataNodes() {
return this.numberOfDataNodes;
}

public boolean hasVotingExclusions() {
return this.hasVotingExclusions;
}

public ClusterHealthStatus getStatus() {
return status;
}
Expand All @@ -216,6 +229,9 @@ public void writeTo(final StreamOutput out) throws IOException {
out.writeVInt(unassignedShards);
out.writeVInt(numberOfNodes);
out.writeVInt(numberOfDataNodes);
if (out.getVersion().onOrAfter(Version.V_7_1_0)) {
out.writeBoolean(hasVotingExclusions);
}
out.writeByte(status.value());
out.writeVInt(indices.size());
for (ClusterIndexHealth indexHealth : this) {
Expand All @@ -229,6 +245,7 @@ public String toString() {
return "ClusterStateHealth{" +
"numberOfNodes=" + numberOfNodes +
", numberOfDataNodes=" + numberOfDataNodes +
", hasVotingExclusions=" + hasVotingExclusions +
", activeShards=" + activeShards +
", relocatingShards=" + relocatingShards +
", activePrimaryShards=" + activePrimaryShards +
Expand All @@ -247,6 +264,7 @@ public boolean equals(Object o) {
ClusterStateHealth that = (ClusterStateHealth) o;
return numberOfNodes == that.numberOfNodes &&
numberOfDataNodes == that.numberOfDataNodes &&
hasVotingExclusions == that.hasVotingExclusions &&
activeShards == that.activeShards &&
relocatingShards == that.relocatingShards &&
activePrimaryShards == that.activePrimaryShards &&
Expand All @@ -259,7 +277,7 @@ public boolean equals(Object o) {

@Override
public int hashCode() {
return Objects.hash(numberOfNodes, numberOfDataNodes, activeShards, relocatingShards, activePrimaryShards, initializingShards,
unassignedShards, activeShardsPercent, status, indices);
return Objects.hash(numberOfNodes, numberOfDataNodes, hasVotingExclusions, activeShards, relocatingShards, activePrimaryShards,
initializingShards, unassignedShards, activeShardsPercent, status, indices);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ private void assertClusterHealth(ClusterHealthResponse clusterHealth) {
assertThat(clusterHealth.getUnassignedShards(), Matchers.equalTo(clusterStateHealth.getUnassignedShards()));
assertThat(clusterHealth.getNumberOfNodes(), Matchers.equalTo(clusterStateHealth.getNumberOfNodes()));
assertThat(clusterHealth.getNumberOfDataNodes(), Matchers.equalTo(clusterStateHealth.getNumberOfDataNodes()));
assertThat(clusterHealth.hasVotingExclusions(), Matchers.equalTo(clusterStateHealth.hasVotingExclusions()));
}

ClusterHealthResponse maybeSerialize(ClusterHealthResponse clusterHealth) throws IOException {
Expand Down Expand Up @@ -124,7 +125,7 @@ protected ClusterHealthResponse createTestInstance() {
}
}
ClusterStateHealth stateHealth = new ClusterStateHealth(randomInt(100), randomInt(100), randomInt(100),
randomInt(100), randomInt(100), randomInt(100), randomInt(100),
randomInt(100), randomInt(100), randomInt(100), randomInt(100), randomBoolean(),
randomDoubleBetween(0d, 100d, true), randomFrom(ClusterHealthStatus.values()), indices);

return new ClusterHealthResponse(randomAlphaOfLengthBetween(1, 10), randomInt(100), randomInt(100), randomInt(100),
Expand Down Expand Up @@ -175,7 +176,6 @@ protected ClusterHealthResponse mutateInstance(ClusterHealthResponse instance) {
instance.getDelayedUnassignedShards() + between(1, 10), instance.getTaskMaxWaitingTime(),
instance.isTimedOut(), instance.getClusterStateHealth());
case "taskMaxWaitingTime":

return new ClusterHealthResponse(instance.getClusterName(),
instance.getNumberOfPendingTasks(), instance.getNumberOfInFlightFetch(),
instance.getDelayedUnassignedShards(), new TimeValue(instance.getTaskMaxWaitingTime().millis() + between(1, 10)),
Expand All @@ -189,8 +189,8 @@ protected ClusterHealthResponse mutateInstance(ClusterHealthResponse instance) {
ClusterStateHealth state = instance.getClusterStateHealth();
ClusterStateHealth newState = new ClusterStateHealth(state.getActivePrimaryShards() + between(1, 10),
state.getActiveShards(), state.getRelocatingShards(), state.getInitializingShards(), state.getUnassignedShards(),
state.getNumberOfNodes(), state.getNumberOfDataNodes(), state.getActiveShardsPercent(), state.getStatus(),
state.getIndices());
state.getNumberOfNodes(), state.getNumberOfDataNodes(), state.hasVotingExclusions(),
state.getActiveShardsPercent(), state.getStatus(), state.getIndices());
return new ClusterHealthResponse(instance.getClusterName(),
instance.getNumberOfPendingTasks(), instance.getNumberOfInFlightFetch(),
instance.getDelayedUnassignedShards(), instance.getTaskMaxWaitingTime(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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;

import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsRequest;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsRequest;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.InternalTestCluster;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;

@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoMinMasterNodes = false)
public class ClusterHealthVotingExclusionsIT extends ESIntegTestCase {

public void testVotingExclusions() throws ExecutionException, InterruptedException, IOException {
logger.info("--> Start 3 nodes cluster and assert no voting exclusions");
internalCluster().setBootstrapMasterNodeIndex(2);
List<String> nodes = internalCluster().startNodes(3);
ensureGreen();
assertFalse(client().admin().cluster().prepareHealth().get().hasVotingExclusions());

logger.info("--> Add voting exclusion and assert hasVotingExclusions");
String[] excludedNodes = {nodes.get(0)};
client().execute(AddVotingConfigExclusionsAction.INSTANCE, new AddVotingConfigExclusionsRequest(excludedNodes)).get();
assertTrue(client().admin().cluster().prepareHealth().get().hasVotingExclusions());

logger.info("--> Stop the node, voting exclusions still should be there");
internalCluster().stopRandomNode(InternalTestCluster.nameFilter(nodes.get(0)));
assertTrue(client().admin().cluster().prepareHealth().get().hasVotingExclusions());

logger.info("--> Clear voting exclusions and assert no voting exclusions");
client().execute(ClearVotingConfigExclusionsAction.INSTANCE, new ClearVotingConfigExclusionsRequest()).get();
assertFalse(client().admin().cluster().prepareHealth().get().hasVotingExclusions());
}
}
Loading