Zen2: Rename tombstones to exclusions (#36226)

Renames the withdrawal / tombstones APIs to voting configuration exclusions.
This commit is contained in:
Yannick Welsch 2018-12-05 23:12:28 +01:00 committed by GitHub
parent 5d6602120f
commit 03d0ea91ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 412 additions and 398 deletions

View File

@ -91,7 +91,8 @@ public class Zen2RestApiIT extends ESNetty4IntegTestCase {
public void doAfterNodes(int n, Client client) throws IOException {
ensureGreen("test");
Response response =
restClient.performRequest(new Request("POST", "/_cluster/withdrawn_votes/" + internalCluster().getNodeNames()[n]));
restClient.performRequest(new Request("POST", "/_cluster/voting_config_exclusions/" +
internalCluster().getNodeNames()[n]));
assertThat(response.getStatusLine().getStatusCode(), is(200));
}
@ -111,7 +112,7 @@ public class Zen2RestApiIT extends ESNetty4IntegTestCase {
)
)
);
Response deleteResponse = restClient.performRequest(new Request("DELETE", "/_cluster/withdrawn_votes"));
Response deleteResponse = restClient.performRequest(new Request("DELETE", "/_cluster/voting_config_exclusions"));
assertThat(deleteResponse.getStatusLine().getStatusCode(), is(200));
ClusterHealthResponse clusterHealthResponse = client(viaNode).admin().cluster().prepareHealth()
@ -135,10 +136,11 @@ public class Zen2RestApiIT extends ESNetty4IntegTestCase {
public void testClearVotingTombstonesNotWaitingForRemoval() throws Exception {
List<String> nodes = internalCluster().startNodes(3);
RestClient restClient = getRestClient();
Response response = restClient.performRequest(new Request("POST", "/_cluster/withdrawn_votes/" + nodes.get(2)));
Response response = restClient.performRequest(new Request("POST", "/_cluster/voting_config_exclusions/" + nodes.get(2)));
assertThat(response.getStatusLine().getStatusCode(), is(200));
assertThat(response.getEntity().getContentLength(), is(0L));
Response deleteResponse = restClient.performRequest(new Request("DELETE", "/_cluster/withdrawn_votes/?wait_for_removal=false"));
Response deleteResponse = restClient.performRequest(
new Request("DELETE", "/_cluster/voting_config_exclusions/?wait_for_removal=false"));
assertThat(deleteResponse.getStatusLine().getStatusCode(), is(200));
assertThat(deleteResponse.getEntity().getContentLength(), is(0L));
}
@ -147,11 +149,11 @@ public class Zen2RestApiIT extends ESNetty4IntegTestCase {
List<String> nodes = internalCluster().startNodes(3);
RestClient restClient = getRestClient();
String nodeToWithdraw = nodes.get(randomIntBetween(0, 2));
Response response = restClient.performRequest(new Request("POST", "/_cluster/withdrawn_votes/" + nodeToWithdraw));
Response response = restClient.performRequest(new Request("POST", "/_cluster/voting_config_exclusions/" + nodeToWithdraw));
assertThat(response.getStatusLine().getStatusCode(), is(200));
assertThat(response.getEntity().getContentLength(), is(0L));
internalCluster().stopRandomNode(InternalTestCluster.nameFilter(nodeToWithdraw));
Response deleteResponse = restClient.performRequest(new Request("DELETE", "/_cluster/withdrawn_votes"));
Response deleteResponse = restClient.performRequest(new Request("DELETE", "/_cluster/voting_config_exclusions"));
assertThat(deleteResponse.getStatusLine().getStatusCode(), is(200));
assertThat(deleteResponse.getEntity().getContentLength(), is(0L));
}
@ -160,13 +162,13 @@ public class Zen2RestApiIT extends ESNetty4IntegTestCase {
internalCluster().startNodes(3);
RestClient restClient = getRestClient();
try {
restClient.performRequest(new Request("POST", "/_cluster/withdrawn_votes/invalid"));
restClient.performRequest(new Request("POST", "/_cluster/voting_config_exclusions/invalid"));
fail("Invalid node name should throw.");
} catch (ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(400));
assertThat(
e.getCause().getMessage(),
Matchers.containsString("add voting tombstones request for [invalid] matched no master-eligible nodes")
Matchers.containsString("add voting config exclusions request for [invalid] matched no master-eligible nodes")
);
}
}

View File

@ -27,10 +27,10 @@ import org.elasticsearch.action.admin.cluster.bootstrap.BootstrapClusterAction;
import org.elasticsearch.action.admin.cluster.bootstrap.GetDiscoveredNodesAction;
import org.elasticsearch.action.admin.cluster.bootstrap.TransportBootstrapClusterAction;
import org.elasticsearch.action.admin.cluster.bootstrap.TransportGetDiscoveredNodesAction;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingTombstonesAction;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingTombstonesAction;
import org.elasticsearch.action.admin.cluster.configuration.TransportAddVotingTombstonesAction;
import org.elasticsearch.action.admin.cluster.configuration.TransportClearVotingTombstonesAction;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.cluster.configuration.TransportAddVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.cluster.configuration.TransportClearVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction;
import org.elasticsearch.action.admin.cluster.health.TransportClusterHealthAction;
import org.elasticsearch.action.admin.cluster.node.hotthreads.NodesHotThreadsAction;
@ -225,7 +225,7 @@ import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.rest.action.RestFieldCapabilitiesAction;
import org.elasticsearch.rest.action.RestMainAction;
import org.elasticsearch.rest.action.admin.cluster.RestCancelTasksAction;
import org.elasticsearch.rest.action.admin.cluster.RestClearVotingTombstonesAction;
import org.elasticsearch.rest.action.admin.cluster.RestClearVotingConfigExclusionsAction;
import org.elasticsearch.rest.action.admin.cluster.RestClusterAllocationExplainAction;
import org.elasticsearch.rest.action.admin.cluster.RestClusterGetSettingsAction;
import org.elasticsearch.rest.action.admin.cluster.RestClusterHealthAction;
@ -255,7 +255,7 @@ import org.elasticsearch.rest.action.admin.cluster.RestRemoteClusterInfoAction;
import org.elasticsearch.rest.action.admin.cluster.RestRestoreSnapshotAction;
import org.elasticsearch.rest.action.admin.cluster.RestSnapshotsStatusAction;
import org.elasticsearch.rest.action.admin.cluster.RestVerifyRepositoryAction;
import org.elasticsearch.rest.action.admin.cluster.RestAddVotingTombstonesAction;
import org.elasticsearch.rest.action.admin.cluster.RestAddVotingConfigExclusionAction;
import org.elasticsearch.rest.action.admin.indices.RestAnalyzeAction;
import org.elasticsearch.rest.action.admin.indices.RestClearIndicesCacheAction;
import org.elasticsearch.rest.action.admin.indices.RestCloseIndexAction;
@ -435,8 +435,8 @@ public class ActionModule extends AbstractModule {
actions.register(GetDiscoveredNodesAction.INSTANCE, TransportGetDiscoveredNodesAction.class);
actions.register(BootstrapClusterAction.INSTANCE, TransportBootstrapClusterAction.class);
actions.register(AddVotingTombstonesAction.INSTANCE, TransportAddVotingTombstonesAction.class);
actions.register(ClearVotingTombstonesAction.INSTANCE, TransportClearVotingTombstonesAction.class);
actions.register(AddVotingConfigExclusionsAction.INSTANCE, TransportAddVotingConfigExclusionsAction.class);
actions.register(ClearVotingConfigExclusionsAction.INSTANCE, TransportClearVotingConfigExclusionsAction.class);
actions.register(ClusterAllocationExplainAction.INSTANCE, TransportClusterAllocationExplainAction.class);
actions.register(ClusterStatsAction.INSTANCE, TransportClusterStatsAction.class);
actions.register(ClusterStateAction.INSTANCE, TransportClusterStateAction.class);
@ -545,8 +545,8 @@ public class ActionModule extends AbstractModule {
catActions.add((AbstractCatAction) a);
}
};
registerHandler.accept(new RestAddVotingTombstonesAction(settings, restController));
registerHandler.accept(new RestClearVotingTombstonesAction(settings, restController));
registerHandler.accept(new RestAddVotingConfigExclusionAction(settings, restController));
registerHandler.accept(new RestClearVotingConfigExclusionsAction(settings, restController));
registerHandler.accept(new RestMainAction(settings, restController));
registerHandler.accept(new RestNodesInfoAction(settings, restController, settingsFilter));
registerHandler.accept(new RestRemoteClusterInfoAction(settings, restController));

View File

@ -21,21 +21,21 @@ package org.elasticsearch.action.admin.cluster.configuration;
import org.elasticsearch.action.Action;
import org.elasticsearch.common.io.stream.Writeable.Reader;
public class AddVotingTombstonesAction extends Action<AddVotingTombstonesResponse> {
public static final AddVotingTombstonesAction INSTANCE = new AddVotingTombstonesAction();
public static final String NAME = "cluster:admin/voting/add_tombstones";
public class AddVotingConfigExclusionsAction extends Action<AddVotingConfigExclusionsResponse> {
public static final AddVotingConfigExclusionsAction INSTANCE = new AddVotingConfigExclusionsAction();
public static final String NAME = "cluster:admin/voting_config/add_exclusions";
private AddVotingTombstonesAction() {
private AddVotingConfigExclusionsAction() {
super(NAME);
}
@Override
public AddVotingTombstonesResponse newResponse() {
public AddVotingConfigExclusionsResponse newResponse() {
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
}
@Override
public Reader<AddVotingTombstonesResponse> getResponseReader() {
return AddVotingTombstonesResponse::new;
public Reader<AddVotingConfigExclusionsResponse> getResponseReader() {
return AddVotingConfigExclusionsResponse::new;
}
}

View File

@ -21,7 +21,7 @@ package org.elasticsearch.action.admin.cluster.configuration;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.MasterNodeRequest;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.io.stream.StreamInput;
@ -34,29 +34,29 @@ import java.util.Set;
import java.util.stream.Collectors;
/**
* A request to add voting tombstones for certain master-eligible nodes, and wait for these nodes to be removed from the voting
* A request to add voting config exclusions for certain master-eligible nodes, and wait for these nodes to be removed from the voting
* configuration.
*/
public class AddVotingTombstonesRequest extends MasterNodeRequest<AddVotingTombstonesRequest> {
public class AddVotingConfigExclusionsRequest extends MasterNodeRequest<AddVotingConfigExclusionsRequest> {
private final String[] nodeDescriptions;
private final TimeValue timeout;
/**
* Construct a request to add voting tombstones for master-eligible nodes matching the given descriptions, and wait for a default 30
* seconds for these nodes to be removed from the voting configuration.
* Construct a request to add voting config exclusions for master-eligible nodes matching the given descriptions, and wait for a
* default 30 seconds for these exclusions to take effect, removing the nodes from the voting configuration.
* @param nodeDescriptions Descriptions of the nodes to add - see {@link DiscoveryNodes#resolveNodes(String...)}
*/
public AddVotingTombstonesRequest(String[] nodeDescriptions) {
public AddVotingConfigExclusionsRequest(String[] nodeDescriptions) {
this(nodeDescriptions, TimeValue.timeValueSeconds(30));
}
/**
* Construct a request to add voting tombstones for master-eligible nodes matching the given descriptions, and wait for these nodes to
* be removed from the voting configuration.
* @param nodeDescriptions Descriptions of the nodes whose tombstones to add - see {@link DiscoveryNodes#resolveNodes(String...)}.
* @param timeout How long to wait for the nodes to be removed from the voting configuration.
* Construct a request to add voting config exclusions for master-eligible nodes matching the given descriptions, and wait for these
* nodes to be removed from the voting configuration.
* @param nodeDescriptions Descriptions of the nodes whose exclusions to add - see {@link DiscoveryNodes#resolveNodes(String...)}.
* @param timeout How long to wait for the added exclusions to take effect and be removed from the voting configuration.
*/
public AddVotingTombstonesRequest(String[] nodeDescriptions, TimeValue timeout) {
public AddVotingConfigExclusionsRequest(String[] nodeDescriptions, TimeValue timeout) {
if (timeout.compareTo(TimeValue.ZERO) < 0) {
throw new IllegalArgumentException("timeout [" + timeout + "] must be non-negative");
}
@ -64,50 +64,50 @@ public class AddVotingTombstonesRequest extends MasterNodeRequest<AddVotingTombs
this.timeout = timeout;
}
public AddVotingTombstonesRequest(StreamInput in) throws IOException {
public AddVotingConfigExclusionsRequest(StreamInput in) throws IOException {
super(in);
nodeDescriptions = in.readStringArray();
timeout = in.readTimeValue();
}
Set<VotingTombstone> resolveVotingTombstones(ClusterState currentState) {
Set<VotingConfigExclusion> resolveVotingConfigExclusions(ClusterState currentState) {
final DiscoveryNodes allNodes = currentState.nodes();
final Set<VotingTombstone> resolvedNodes = Arrays.stream(allNodes.resolveNodes(nodeDescriptions))
.map(allNodes::get).filter(DiscoveryNode::isMasterNode).map(VotingTombstone::new).collect(Collectors.toSet());
final Set<VotingConfigExclusion> resolvedNodes = Arrays.stream(allNodes.resolveNodes(nodeDescriptions))
.map(allNodes::get).filter(DiscoveryNode::isMasterNode).map(VotingConfigExclusion::new).collect(Collectors.toSet());
if (resolvedNodes.isEmpty()) {
throw new IllegalArgumentException("add voting tombstones request for " + Arrays.asList(nodeDescriptions)
throw new IllegalArgumentException("add voting config exclusions request for " + Arrays.asList(nodeDescriptions)
+ " matched no master-eligible nodes");
}
resolvedNodes.removeIf(n -> currentState.getVotingTombstones().contains(n));
resolvedNodes.removeIf(n -> currentState.getVotingConfigExclusions().contains(n));
return resolvedNodes;
}
Set<VotingTombstone> resolveVotingTombstonesAndCheckMaximum(ClusterState currentState, int maxTombstoneCount,
Set<VotingConfigExclusion> resolveVotingConfigExclusionsAndCheckMaximum(ClusterState currentState, int maxExclusionsCount,
String maximumSettingKey) {
final Set<VotingTombstone> resolvedNodes = resolveVotingTombstones(currentState);
final Set<VotingConfigExclusion> resolvedExclusions = resolveVotingConfigExclusions(currentState);
final int oldTombstoneCount = currentState.getVotingTombstones().size();
final int newTombstoneCount = resolvedNodes.size();
if (oldTombstoneCount + newTombstoneCount > maxTombstoneCount) {
throw new IllegalArgumentException("add voting tombstones request for " + Arrays.asList(nodeDescriptions)
+ " would add [" + newTombstoneCount + "] voting tombstones to the existing [" + oldTombstoneCount
+ "] which would exceed the maximum of [" + maxTombstoneCount + "] set by ["
final int oldExclusionsCount = currentState.getVotingConfigExclusions().size();
final int newExclusionsCount = resolvedExclusions.size();
if (oldExclusionsCount + newExclusionsCount > maxExclusionsCount) {
throw new IllegalArgumentException("add voting config exclusions request for " + Arrays.asList(nodeDescriptions)
+ " would add [" + newExclusionsCount + "] exclusions to the existing [" + oldExclusionsCount
+ "] which would exceed the maximum of [" + maxExclusionsCount + "] set by ["
+ maximumSettingKey + "]");
}
return resolvedNodes;
return resolvedExclusions;
}
/**
* @return descriptions of the nodes for whom to add tombstones.
* @return descriptions of the nodes for whom to add voting config exclusions.
*/
public String[] getNodeDescriptions() {
return nodeDescriptions;
}
/**
* @return how long to wait after adding the tombstones for the nodes to be removed from the voting configuration.
* @return how long to wait after adding the exclusions for the nodes to be removed from the voting configuration.
*/
public TimeValue getTimeout() {
return timeout;
@ -132,7 +132,7 @@ public class AddVotingTombstonesRequest extends MasterNodeRequest<AddVotingTombs
@Override
public String toString() {
return "AddVotingTombstonesRequest{" +
return "AddVotingConfigExclusionsRequest{" +
"nodeDescriptions=" + Arrays.asList(nodeDescriptions) +
", timeout=" + timeout +
'}';

View File

@ -27,15 +27,15 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
/**
* A response to {@link AddVotingTombstonesRequest} indicating that voting tombstones have been added for the requested nodes and these
* nodes have been removed from the voting configuration.
* A response to {@link AddVotingConfigExclusionsRequest} indicating that voting config exclusions have been added for the requested nodes
* and these nodes have been removed from the voting configuration.
*/
public class AddVotingTombstonesResponse extends ActionResponse implements ToXContentObject {
public class AddVotingConfigExclusionsResponse extends ActionResponse implements ToXContentObject {
public AddVotingTombstonesResponse() {
public AddVotingConfigExclusionsResponse() {
}
public AddVotingTombstonesResponse(StreamInput in) throws IOException {
public AddVotingConfigExclusionsResponse(StreamInput in) throws IOException {
super(in);
}

View File

@ -21,21 +21,21 @@ package org.elasticsearch.action.admin.cluster.configuration;
import org.elasticsearch.action.Action;
import org.elasticsearch.common.io.stream.Writeable.Reader;
public class ClearVotingTombstonesAction extends Action<ClearVotingTombstonesResponse> {
public static final ClearVotingTombstonesAction INSTANCE = new ClearVotingTombstonesAction();
public static final String NAME = "cluster:admin/voting/clear_tombstones";
public class ClearVotingConfigExclusionsAction extends Action<ClearVotingConfigExclusionsResponse> {
public static final ClearVotingConfigExclusionsAction INSTANCE = new ClearVotingConfigExclusionsAction();
public static final String NAME = "cluster:admin/voting_config/clear_exclusions";
private ClearVotingTombstonesAction() {
private ClearVotingConfigExclusionsAction() {
super(NAME);
}
@Override
public ClearVotingTombstonesResponse newResponse() {
public ClearVotingConfigExclusionsResponse newResponse() {
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
}
@Override
public Reader<ClearVotingTombstonesResponse> getResponseReader() {
return ClearVotingTombstonesResponse::new;
public Reader<ClearVotingConfigExclusionsResponse> getResponseReader() {
return ClearVotingConfigExclusionsResponse::new;
}
}

View File

@ -27,41 +27,43 @@ import org.elasticsearch.common.unit.TimeValue;
import java.io.IOException;
/**
* A request to clear the voting tombstones from the cluster state, optionally waiting for these nodes to be removed from the cluster first.
* A request to clear the voting config exclusions from the cluster state, optionally waiting for these nodes to be removed from the
* cluster first.
*/
public class ClearVotingTombstonesRequest extends MasterNodeRequest<ClearVotingTombstonesRequest> {
public class ClearVotingConfigExclusionsRequest extends MasterNodeRequest<ClearVotingConfigExclusionsRequest> {
private boolean waitForRemoval = true;
private TimeValue timeout = TimeValue.timeValueSeconds(30);
/**
* Construct a request to remove all the voting tombstones from the cluster state.
* Construct a request to remove all the voting config exclusions from the cluster state.
*/
public ClearVotingTombstonesRequest() {
public ClearVotingConfigExclusionsRequest() {
}
public ClearVotingTombstonesRequest(StreamInput in) throws IOException {
public ClearVotingConfigExclusionsRequest(StreamInput in) throws IOException {
super(in);
waitForRemoval = in.readBoolean();
timeout = in.readTimeValue();
}
/**
* @return whether to wait for the tombstoned nodes to be removed from the cluster before removing their tombstones. True by default.
* @return whether to wait for the currently excluded nodes to be removed from the cluster before removing their exclusions.
* True by default.
*/
public boolean getWaitForRemoval() {
return waitForRemoval;
}
/**
* @param waitForRemoval whether to wait for the tombstoned nodes to be removed from the cluster before removing their tombstones. True
* by default.
* @param waitForRemoval whether to wait for the currently excluded nodes to be removed from the cluster before removing their
* exclusions. True by default.
*/
public void setWaitForRemoval(boolean waitForRemoval) {
this.waitForRemoval = waitForRemoval;
}
/**
* @param timeout how long to wait for the tombstoned nodes to be removed if {@link ClearVotingTombstonesRequest#waitForRemoval} is
* @param timeout how long to wait for the excluded nodes to be removed if {@link ClearVotingConfigExclusionsRequest#waitForRemoval} is
* true. Defaults to 30 seconds.
*/
public void setTimeout(TimeValue timeout) {
@ -69,7 +71,7 @@ public class ClearVotingTombstonesRequest extends MasterNodeRequest<ClearVotingT
}
/**
* @return how long to wait for the tombstoned nodes to be removed if {@link ClearVotingTombstonesRequest#waitForRemoval} is
* @return how long to wait for the excluded nodes to be removed if {@link ClearVotingConfigExclusionsRequest#waitForRemoval} is
* true. Defaults to 30 seconds.
*/
public TimeValue getTimeout() {
@ -95,7 +97,7 @@ public class ClearVotingTombstonesRequest extends MasterNodeRequest<ClearVotingT
@Override
public String toString() {
return "ClearVotingTombstonesRequest{" +
return "ClearVotingConfigExclusionsRequest{" +
", waitForRemoval=" + waitForRemoval +
", timeout=" + timeout +
'}';

View File

@ -27,13 +27,14 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
/**
* A response to {@link ClearVotingTombstonesRequest} indicating that voting tombstones have been cleared from the cluster state.
* A response to {@link ClearVotingConfigExclusionsRequest} indicating that voting config exclusions have been cleared from the
* cluster state.
*/
public class ClearVotingTombstonesResponse extends ActionResponse implements ToXContentObject {
public ClearVotingTombstonesResponse() {
public class ClearVotingConfigExclusionsResponse extends ActionResponse implements ToXContentObject {
public ClearVotingConfigExclusionsResponse() {
}
public ClearVotingTombstonesResponse(StreamInput in) throws IOException {
public ClearVotingConfigExclusionsResponse(StreamInput in) throws IOException {
super(in);
}

View File

@ -30,7 +30,7 @@ import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.coordination.CoordinationMetaData;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.service.ClusterService;
@ -49,16 +49,17 @@ import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class TransportAddVotingTombstonesAction extends TransportMasterNodeAction<AddVotingTombstonesRequest, AddVotingTombstonesResponse> {
public class TransportAddVotingConfigExclusionsAction extends TransportMasterNodeAction<AddVotingConfigExclusionsRequest,
AddVotingConfigExclusionsResponse> {
public static final Setting<Integer> MAXIMUM_VOTING_TOMBSTONES_SETTING
= Setting.intSetting("cluster.max_voting_tombstones", 10, 1, Property.Dynamic, Property.NodeScope);
public static final Setting<Integer> MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING
= Setting.intSetting("cluster.max_voting_config_exclusions", 10, 1, Property.Dynamic, Property.NodeScope);
@Inject
public TransportAddVotingTombstonesAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool,
public TransportAddVotingConfigExclusionsAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool,
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
super(AddVotingTombstonesAction.NAME, transportService, clusterService, threadPool, actionFilters, AddVotingTombstonesRequest::new,
indexNameExpressionResolver);
super(AddVotingConfigExclusionsAction.NAME, transportService, clusterService, threadPool, actionFilters,
AddVotingConfigExclusionsRequest::new, indexNameExpressionResolver);
}
@Override
@ -67,35 +68,36 @@ public class TransportAddVotingTombstonesAction extends TransportMasterNodeActio
}
@Override
protected AddVotingTombstonesResponse newResponse() {
protected AddVotingConfigExclusionsResponse newResponse() {
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
}
@Override
protected AddVotingTombstonesResponse read(StreamInput in) throws IOException {
return new AddVotingTombstonesResponse(in);
protected AddVotingConfigExclusionsResponse read(StreamInput in) throws IOException {
return new AddVotingConfigExclusionsResponse(in);
}
@Override
protected void masterOperation(AddVotingTombstonesRequest request, ClusterState state,
ActionListener<AddVotingTombstonesResponse> listener) throws Exception {
protected void masterOperation(AddVotingConfigExclusionsRequest request, ClusterState state,
ActionListener<AddVotingConfigExclusionsResponse> listener) throws Exception {
resolveVotingTombstonesAndCheckMaximum(request, state); // throws IllegalArgumentException if no nodes matched or maximum exceeded
resolveVotingConfigExclusionsAndCheckMaximum(request, state); // throws IAE if no nodes matched or maximum exceeded
clusterService.submitStateUpdateTask("add-voting-tombstones", new ClusterStateUpdateTask(Priority.URGENT) {
clusterService.submitStateUpdateTask("add-voting-config-exclusions", new ClusterStateUpdateTask(Priority.URGENT) {
private Set<VotingTombstone> resolvedNodes;
private Set<VotingConfigExclusion> resolvedExclusions;
@Override
public ClusterState execute(ClusterState currentState) {
assert resolvedNodes == null : resolvedNodes;
resolvedNodes = resolveVotingTombstonesAndCheckMaximum(request, currentState);
assert resolvedExclusions == null : resolvedExclusions;
resolvedExclusions = resolveVotingConfigExclusionsAndCheckMaximum(request, currentState);
final CoordinationMetaData.Builder builder = CoordinationMetaData.builder(currentState.coordinationMetaData());
resolvedNodes.forEach(builder::addVotingTombstone);
resolvedExclusions.forEach(builder::addVotingConfigExclusion);
final MetaData newMetaData = MetaData.builder(currentState.metaData()).coordinationMetaData(builder.build()).build();
final ClusterState newState = ClusterState.builder(currentState).metaData(newMetaData).build();
assert newState.getVotingTombstones().size() <= MAXIMUM_VOTING_TOMBSTONES_SETTING.get(currentState.metaData().settings());
assert newState.getVotingConfigExclusions().size() <= MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.get(
currentState.metaData().settings());
return newState;
}
@ -110,29 +112,30 @@ public class TransportAddVotingTombstonesAction extends TransportMasterNodeActio
final ClusterStateObserver observer
= new ClusterStateObserver(clusterService, request.getTimeout(), logger, threadPool.getThreadContext());
final Set<String> resolvedNodeIds = resolvedNodes.stream().map(VotingTombstone::getNodeId).collect(Collectors.toSet());
final Set<String> excludedNodeIds = resolvedExclusions.stream().map(VotingConfigExclusion::getNodeId)
.collect(Collectors.toSet());
final Predicate<ClusterState> allNodesRemoved = clusterState -> {
final Set<String> votingNodeIds = clusterState.getLastCommittedConfiguration().getNodeIds();
return resolvedNodeIds.stream().noneMatch(votingNodeIds::contains);
final Set<String> votingConfigNodeIds = clusterState.getLastCommittedConfiguration().getNodeIds();
return excludedNodeIds.stream().noneMatch(votingConfigNodeIds::contains);
};
final Listener clusterStateListener = new Listener() {
@Override
public void onNewClusterState(ClusterState state) {
listener.onResponse(new AddVotingTombstonesResponse());
listener.onResponse(new AddVotingConfigExclusionsResponse());
}
@Override
public void onClusterServiceClose() {
listener.onFailure(new ElasticsearchException("cluster service closed while waiting for withdrawal of votes from "
+ resolvedNodes));
listener.onFailure(new ElasticsearchException("cluster service closed while waiting for voting config exclusions " +
resolvedExclusions + " to take effect"));
}
@Override
public void onTimeout(TimeValue timeout) {
listener.onFailure(new ElasticsearchTimeoutException("timed out waiting for withdrawal of votes from "
+ resolvedNodes));
listener.onFailure(new ElasticsearchTimeoutException("timed out waiting for voting config exclusions "
+ resolvedExclusions + " to take effect"));
}
};
@ -145,13 +148,14 @@ public class TransportAddVotingTombstonesAction extends TransportMasterNodeActio
});
}
private static Set<VotingTombstone> resolveVotingTombstonesAndCheckMaximum(AddVotingTombstonesRequest request, ClusterState state) {
return request.resolveVotingTombstonesAndCheckMaximum(state,
MAXIMUM_VOTING_TOMBSTONES_SETTING.get(state.metaData().settings()), MAXIMUM_VOTING_TOMBSTONES_SETTING.getKey());
private static Set<VotingConfigExclusion> resolveVotingConfigExclusionsAndCheckMaximum(AddVotingConfigExclusionsRequest request,
ClusterState state) {
return request.resolveVotingConfigExclusionsAndCheckMaximum(state,
MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.get(state.metaData().settings()), MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.getKey());
}
@Override
protected ClusterBlockException checkBlock(AddVotingTombstonesRequest request, ClusterState state) {
protected ClusterBlockException checkBlock(AddVotingConfigExclusionsRequest request, ClusterState state) {
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
}
}

View File

@ -30,7 +30,7 @@ import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.coordination.CoordinationMetaData;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.service.ClusterService;
@ -45,14 +45,15 @@ import org.elasticsearch.transport.TransportService;
import java.io.IOException;
import java.util.function.Predicate;
public class TransportClearVotingTombstonesAction
extends TransportMasterNodeAction<ClearVotingTombstonesRequest, ClearVotingTombstonesResponse> {
public class TransportClearVotingConfigExclusionsAction
extends TransportMasterNodeAction<ClearVotingConfigExclusionsRequest, ClearVotingConfigExclusionsResponse> {
@Inject
public TransportClearVotingTombstonesAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool,
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
super(ClearVotingTombstonesAction.NAME, transportService, clusterService, threadPool, actionFilters,
ClearVotingTombstonesRequest::new, indexNameExpressionResolver);
public TransportClearVotingConfigExclusionsAction(TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(ClearVotingConfigExclusionsAction.NAME, transportService, clusterService, threadPool, actionFilters,
ClearVotingConfigExclusionsRequest::new, indexNameExpressionResolver);
}
@Override
@ -61,23 +62,23 @@ public class TransportClearVotingTombstonesAction
}
@Override
protected ClearVotingTombstonesResponse newResponse() {
protected ClearVotingConfigExclusionsResponse newResponse() {
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
}
@Override
protected ClearVotingTombstonesResponse read(StreamInput in) throws IOException {
return new ClearVotingTombstonesResponse(in);
protected ClearVotingConfigExclusionsResponse read(StreamInput in) throws IOException {
return new ClearVotingConfigExclusionsResponse(in);
}
@Override
protected void masterOperation(ClearVotingTombstonesRequest request, ClusterState initialState,
ActionListener<ClearVotingTombstonesResponse> listener) throws Exception {
protected void masterOperation(ClearVotingConfigExclusionsRequest request, ClusterState initialState,
ActionListener<ClearVotingConfigExclusionsResponse> listener) throws Exception {
final long startTimeMillis = threadPool.relativeTimeInMillis();
final Predicate<ClusterState> allTombstonedNodesRemoved = newState -> {
for (VotingTombstone tombstone : initialState.getVotingTombstones()) {
final Predicate<ClusterState> allExclusionsRemoved = newState -> {
for (VotingConfigExclusion tombstone : initialState.getVotingConfigExclusions()) {
// NB checking for the existence of any node with this persistent ID, because persistent IDs are how votes are counted.
if (newState.nodes().nodeExists(tombstone.getNodeId())) {
return false;
@ -86,41 +87,41 @@ public class TransportClearVotingTombstonesAction
return true;
};
if (request.getWaitForRemoval() && allTombstonedNodesRemoved.test(initialState) == false) {
if (request.getWaitForRemoval() && allExclusionsRemoved.test(initialState) == false) {
final ClusterStateObserver clusterStateObserver = new ClusterStateObserver(initialState, clusterService, request.getTimeout(),
logger, threadPool.getThreadContext());
clusterStateObserver.waitForNextChange(new Listener() {
@Override
public void onNewClusterState(ClusterState state) {
submitClearTombstonesTask(request, startTimeMillis, listener);
submitClearVotingConfigExclusionsTask(request, startTimeMillis, listener);
}
@Override
public void onClusterServiceClose() {
listener.onFailure(new ElasticsearchException("cluster service closed while waiting for removal of nodes "
+ initialState.getVotingTombstones()));
+ initialState.getVotingConfigExclusions()));
}
@Override
public void onTimeout(TimeValue timeout) {
listener.onFailure(new ElasticsearchTimeoutException(
"timed out waiting for removal of nodes; if nodes should not be removed, set waitForRemoval to false. "
+ initialState.getVotingTombstones()));
+ initialState.getVotingConfigExclusions()));
}
}, allTombstonedNodesRemoved);
}, allExclusionsRemoved);
} else {
submitClearTombstonesTask(request, startTimeMillis, listener);
submitClearVotingConfigExclusionsTask(request, startTimeMillis, listener);
}
}
private void submitClearTombstonesTask(ClearVotingTombstonesRequest request, long startTimeMillis,
ActionListener<ClearVotingTombstonesResponse> listener) {
clusterService.submitStateUpdateTask("clear-voting-tombstones", new ClusterStateUpdateTask(Priority.URGENT) {
private void submitClearVotingConfigExclusionsTask(ClearVotingConfigExclusionsRequest request, long startTimeMillis,
ActionListener<ClearVotingConfigExclusionsResponse> listener) {
clusterService.submitStateUpdateTask("clear-voting-config-exclusions", new ClusterStateUpdateTask(Priority.URGENT) {
@Override
public ClusterState execute(ClusterState currentState) {
final CoordinationMetaData newCoordinationMetaData =
CoordinationMetaData.builder(currentState.coordinationMetaData()).clearVotingTombstones().build();
CoordinationMetaData.builder(currentState.coordinationMetaData()).clearVotingConfigExclusions().build();
final MetaData newMetaData = MetaData.builder(currentState.metaData()).
coordinationMetaData(newCoordinationMetaData).build();
return ClusterState.builder(currentState).metaData(newMetaData).build();
@ -138,13 +139,13 @@ public class TransportClearVotingTombstonesAction
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
listener.onResponse(new ClearVotingTombstonesResponse());
listener.onResponse(new ClearVotingConfigExclusionsResponse());
}
});
}
@Override
protected ClusterBlockException checkBlock(ClearVotingTombstonesRequest request, ClusterState state) {
protected ClusterBlockException checkBlock(ClearVotingConfigExclusionsRequest request, ClusterState state) {
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
}
}

View File

@ -28,7 +28,7 @@ import org.elasticsearch.cluster.block.ClusterBlock;
import org.elasticsearch.cluster.block.ClusterBlocks;
import org.elasticsearch.cluster.coordination.CoordinationMetaData;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfiguration;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
@ -278,8 +278,8 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
return coordinationMetaData().getLastCommittedConfiguration();
}
public Set<VotingTombstone> getVotingTombstones() {
return coordinationMetaData().getVotingTombstones();
public Set<VotingConfigExclusion> getVotingConfigExclusions() {
return coordinationMetaData().getVotingConfigExclusions();
}
// Used for testing and logging to determine how this cluster state was send over the wire
@ -314,7 +314,7 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
sb.append(TAB).append(TAB)
.append("last_accepted_config: ").append(coordinationMetaData().getLastAcceptedConfiguration()).append("\n");
sb.append(TAB).append(TAB)
.append("voting tombstones: ").append(coordinationMetaData().getVotingTombstones()).append("\n");
.append("voting tombstones: ").append(coordinationMetaData().getVotingConfigExclusions()).append("\n");
for (IndexMetaData indexMetaData : metaData) {
sb.append(TAB).append(indexMetaData.getIndex());
sb.append(": v[").append(indexMetaData.getVersion())

View File

@ -49,12 +49,12 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
private final VotingConfiguration lastAcceptedConfiguration;
private final Set<VotingTombstone> votingTombstones;
private final Set<VotingConfigExclusion> votingConfigExclusions;
private static final ParseField TERM_PARSE_FIELD = new ParseField("term");
private static final ParseField LAST_COMMITTED_CONFIGURATION_FIELD = new ParseField("last_committed_config");
private static final ParseField LAST_ACCEPTED_CONFIGURATION_FIELD = new ParseField("last_accepted_config");
private static final ParseField VOTING_TOMBSTONES_FIELD = new ParseField("voting_tombstones");
private static final ParseField VOTING_CONFIG_EXCLUSIONS_FIELD = new ParseField("voting_config_exclusions");
private static long term(Object[] termAndConfigs) {
return (long)termAndConfigs[0];
@ -73,35 +73,35 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
}
@SuppressWarnings("unchecked")
private static Set<VotingTombstone> votingTombstones(Object[] fields) {
Set<VotingTombstone> votingTombstones = new HashSet<>((List<VotingTombstone>) fields[3]);
private static Set<VotingConfigExclusion> votingConfigExclusions(Object[] fields) {
Set<VotingConfigExclusion> votingTombstones = new HashSet<>((List<VotingConfigExclusion>) fields[3]);
return votingTombstones;
}
private static final ConstructingObjectParser<CoordinationMetaData, Void> PARSER = new ConstructingObjectParser<>(
"coordination_metadata",
fields -> new CoordinationMetaData(term(fields), lastCommittedConfig(fields),
lastAcceptedConfig(fields), votingTombstones(fields)));
lastAcceptedConfig(fields), votingConfigExclusions(fields)));
static {
PARSER.declareLong(ConstructingObjectParser.constructorArg(), TERM_PARSE_FIELD);
PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), LAST_COMMITTED_CONFIGURATION_FIELD);
PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), LAST_ACCEPTED_CONFIGURATION_FIELD);
PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), VotingTombstone.PARSER, VOTING_TOMBSTONES_FIELD);
PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), VotingConfigExclusion.PARSER, VOTING_CONFIG_EXCLUSIONS_FIELD);
}
public CoordinationMetaData(long term, VotingConfiguration lastCommittedConfiguration, VotingConfiguration lastAcceptedConfiguration,
Set<VotingTombstone> votingTombstones) {
Set<VotingConfigExclusion> votingConfigExclusions) {
this.term = term;
this.lastCommittedConfiguration = lastCommittedConfiguration;
this.lastAcceptedConfiguration = lastAcceptedConfiguration;
this.votingTombstones = Collections.unmodifiableSet(new HashSet<>(votingTombstones));
this.votingConfigExclusions = Collections.unmodifiableSet(new HashSet<>(votingConfigExclusions));
}
public CoordinationMetaData(StreamInput in) throws IOException {
term = in.readLong();
lastCommittedConfiguration = new VotingConfiguration(in);
lastAcceptedConfiguration = new VotingConfiguration(in);
votingTombstones = Collections.unmodifiableSet(in.readSet(VotingTombstone::new));
votingConfigExclusions = Collections.unmodifiableSet(in.readSet(VotingConfigExclusion::new));
}
public static Builder builder() {
@ -117,7 +117,7 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
out.writeLong(term);
lastCommittedConfiguration.writeTo(out);
lastAcceptedConfiguration.writeTo(out);
out.writeCollection(votingTombstones, (o, v) -> v.writeTo(o));
out.writeCollection(votingConfigExclusions, (o, v) -> v.writeTo(o));
}
@Override
@ -126,7 +126,7 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
.field(TERM_PARSE_FIELD.getPreferredName(), term)
.field(LAST_COMMITTED_CONFIGURATION_FIELD.getPreferredName(), lastCommittedConfiguration)
.field(LAST_ACCEPTED_CONFIGURATION_FIELD.getPreferredName(), lastAcceptedConfiguration)
.field(VOTING_TOMBSTONES_FIELD.getPreferredName(), votingTombstones);
.field(VOTING_CONFIG_EXCLUSIONS_FIELD.getPreferredName(), votingConfigExclusions);
}
public static CoordinationMetaData fromXContent(XContentParser parser) throws IOException {
@ -145,8 +145,8 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
return lastCommittedConfiguration;
}
public Set<VotingTombstone> getVotingTombstones() {
return votingTombstones;
public Set<VotingConfigExclusion> getVotingConfigExclusions() {
return votingConfigExclusions;
}
@Override
@ -159,7 +159,7 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
if (term != that.term) return false;
if (!lastCommittedConfiguration.equals(that.lastCommittedConfiguration)) return false;
if (!lastAcceptedConfiguration.equals(that.lastAcceptedConfiguration)) return false;
return votingTombstones.equals(that.votingTombstones);
return votingConfigExclusions.equals(that.votingConfigExclusions);
}
@Override
@ -167,7 +167,7 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
int result = (int) (term ^ (term >>> 32));
result = 31 * result + lastCommittedConfiguration.hashCode();
result = 31 * result + lastAcceptedConfiguration.hashCode();
result = 31 * result + votingTombstones.hashCode();
result = 31 * result + votingConfigExclusions.hashCode();
return result;
}
@ -177,7 +177,7 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
"term=" + term +
", lastCommittedConfiguration=" + lastCommittedConfiguration +
", lastAcceptedConfiguration=" + lastAcceptedConfiguration +
", votingTombstones=" + votingTombstones +
", votingConfigExclusions=" + votingConfigExclusions +
'}';
}
@ -185,7 +185,7 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
private long term = 0;
private VotingConfiguration lastCommittedConfiguration = VotingConfiguration.EMPTY_CONFIG;
private VotingConfiguration lastAcceptedConfiguration = VotingConfiguration.EMPTY_CONFIG;
private final Set<VotingTombstone> votingTombstones = new HashSet<>();
private final Set<VotingConfigExclusion> votingConfigExclusions = new HashSet<>();
public Builder() {
@ -195,7 +195,7 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
this.term = state.term;
this.lastCommittedConfiguration = state.lastCommittedConfiguration;
this.lastAcceptedConfiguration = state.lastAcceptedConfiguration;
this.votingTombstones.addAll(state.votingTombstones);
this.votingConfigExclusions.addAll(state.votingConfigExclusions);
}
public Builder term(long term) {
@ -213,35 +213,35 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
return this;
}
public Builder addVotingTombstone(VotingTombstone tombstone) {
votingTombstones.add(tombstone);
public Builder addVotingConfigExclusion(VotingConfigExclusion exclusion) {
votingConfigExclusions.add(exclusion);
return this;
}
public Builder clearVotingTombstones() {
votingTombstones.clear();
public Builder clearVotingConfigExclusions() {
votingConfigExclusions.clear();
return this;
}
public CoordinationMetaData build() {
return new CoordinationMetaData(term, lastCommittedConfiguration, lastAcceptedConfiguration, votingTombstones);
return new CoordinationMetaData(term, lastCommittedConfiguration, lastAcceptedConfiguration, votingConfigExclusions);
}
}
public static class VotingTombstone implements Writeable, ToXContentFragment {
public static class VotingConfigExclusion implements Writeable, ToXContentFragment {
private final String nodeId;
private final String nodeName;
public VotingTombstone(DiscoveryNode node) {
public VotingConfigExclusion(DiscoveryNode node) {
this(node.getId(), node.getName());
}
public VotingTombstone(StreamInput in) throws IOException {
public VotingConfigExclusion(StreamInput in) throws IOException {
this.nodeId = in.readString();
this.nodeName = in.readString();
}
public VotingTombstone(String nodeId, String nodeName) {
public VotingConfigExclusion(String nodeId, String nodeName) {
this.nodeId = nodeId;
this.nodeName = nodeName;
}
@ -271,9 +271,9 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
return (String) nodeIdAndName[1];
}
private static final ConstructingObjectParser<VotingTombstone, Void> PARSER = new ConstructingObjectParser<>(
"voting_tombstone",
nodeIdAndName -> new VotingTombstone(nodeId(nodeIdAndName), nodeName(nodeIdAndName))
private static final ConstructingObjectParser<VotingConfigExclusion, Void> PARSER = new ConstructingObjectParser<>(
"voting_config_exclusion",
nodeIdAndName -> new VotingConfigExclusion(nodeId(nodeIdAndName), nodeName(nodeIdAndName))
);
static {
@ -281,7 +281,7 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
PARSER.declareString(ConstructingObjectParser.constructorArg(), NODE_NAME_PARSE_FIELD);
}
public static VotingTombstone fromXContent(XContentParser parser) throws IOException {
public static VotingConfigExclusion fromXContent(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}
@ -297,7 +297,7 @@ public class CoordinationMetaData implements Writeable, ToXContentFragment {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VotingTombstone that = (VotingTombstone) o;
VotingConfigExclusion that = (VotingConfigExclusion) o;
return Objects.equals(nodeId, that.nodeId) &&
Objects.equals(nodeName, that.nodeName);
}

View File

@ -33,7 +33,7 @@ import org.elasticsearch.cluster.ClusterStateTaskConfig;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.block.ClusterBlocks;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfiguration;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.coordination.FollowersChecker.FollowerCheckRequest;
import org.elasticsearch.cluster.coordination.JoinHelper.InitialJoinAccumulator;
import org.elasticsearch.cluster.metadata.MetaData;
@ -671,7 +671,7 @@ public class Coordinator extends AbstractLifecycleComponent implements Discovery
final Set<DiscoveryNode> liveNodes = StreamSupport.stream(clusterState.nodes().spliterator(), false)
.filter(this::hasJoinVoteFrom).collect(Collectors.toSet());
final VotingConfiguration newConfig = reconfigurator.reconfigure(liveNodes,
clusterState.getVotingTombstones().stream().map(VotingTombstone::getNodeId).collect(Collectors.toSet()),
clusterState.getVotingConfigExclusions().stream().map(VotingConfigExclusion::getNodeId).collect(Collectors.toSet()),
clusterState.getLastAcceptedConfiguration());
if (newConfig.equals(clusterState.getLastAcceptedConfiguration()) == false) {
assert coordinationState.get().joinVotesHaveQuorumFor(newConfig);

View File

@ -19,7 +19,7 @@
package org.elasticsearch.common.settings;
import org.apache.logging.log4j.LogManager;
import org.elasticsearch.action.admin.cluster.configuration.TransportAddVotingTombstonesAction;
import org.elasticsearch.action.admin.cluster.configuration.TransportAddVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.indices.close.TransportCloseIndexAction;
import org.elasticsearch.action.search.TransportSearchAction;
import org.elasticsearch.action.support.AutoCreateIndex;
@ -470,7 +470,7 @@ public final class ClusterSettings extends AbstractScopedSettings {
LeaderChecker.LEADER_CHECK_INTERVAL_SETTING,
LeaderChecker.LEADER_CHECK_RETRY_COUNT_SETTING,
Reconfigurator.CLUSTER_AUTO_SHRINK_VOTING_CONFIGURATION,
TransportAddVotingTombstonesAction.MAXIMUM_VOTING_TOMBSTONES_SETTING,
TransportAddVotingConfigExclusionsAction.MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING,
ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING,
ClusterBootstrapService.INITIAL_MASTER_NODE_COUNT_SETTING,
LagDetector.CLUSTER_FOLLOWER_LAG_TIMEOUT_SETTING

View File

@ -19,8 +19,8 @@
package org.elasticsearch.rest.action.admin.cluster;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingTombstonesAction;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingTombstonesRequest;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsRequest;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsAction;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
@ -31,30 +31,30 @@ import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException;
public class RestAddVotingTombstonesAction extends BaseRestHandler {
public class RestAddVotingConfigExclusionAction extends BaseRestHandler {
private static final TimeValue DEFAULT_TIMEOUT = TimeValue.timeValueSeconds(30L);
public RestAddVotingTombstonesAction(Settings settings, RestController controller) {
public RestAddVotingConfigExclusionAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(RestRequest.Method.POST, "/_cluster/withdrawn_votes/{node_name}", this);
controller.registerHandler(RestRequest.Method.POST, "/_cluster/voting_config_exclusions/{node_name}", this);
}
@Override
public String getName() {
return "add_voting_tombstones_action";
return "add_voting_config_exclusions_action";
}
@Override
protected RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
String nodeName = request.param("node_name");
AddVotingTombstonesRequest addVotingTombstonesRequest = new AddVotingTombstonesRequest(
AddVotingConfigExclusionsRequest votingConfigExclusionsRequest = new AddVotingConfigExclusionsRequest(
new String[]{nodeName},
TimeValue.parseTimeValue(request.param("timeout"), DEFAULT_TIMEOUT, getClass().getSimpleName() + ".timeout")
);
return channel -> client.execute(
AddVotingTombstonesAction.INSTANCE,
addVotingTombstonesRequest,
AddVotingConfigExclusionsAction.INSTANCE,
votingConfigExclusionsRequest,
new RestToXContentListener<>(channel)
);
}

View File

@ -19,8 +19,8 @@
package org.elasticsearch.rest.action.admin.cluster;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingTombstonesAction;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingTombstonesRequest;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsRequest;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsAction;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.BaseRestHandler;
@ -30,24 +30,24 @@ import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException;
public class RestClearVotingTombstonesAction extends BaseRestHandler {
public class RestClearVotingConfigExclusionsAction extends BaseRestHandler {
public RestClearVotingTombstonesAction(Settings settings, RestController controller) {
public RestClearVotingConfigExclusionsAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(RestRequest.Method.DELETE, "/_cluster/withdrawn_votes", this);
controller.registerHandler(RestRequest.Method.DELETE, "/_cluster/voting_config_exclusions", this);
}
@Override
public String getName() {
return "clear_voting_tombstones_action";
return "clear_voting_config_exclusions_action";
}
@Override
protected RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
ClearVotingTombstonesRequest req = new ClearVotingTombstonesRequest();
ClearVotingConfigExclusionsRequest req = new ClearVotingConfigExclusionsRequest();
if (request.hasParam("wait_for_removal")) {
req.setWaitForRemoval(request.paramAsBoolean("wait_for_removal", true));
}
return channel -> client.execute(ClearVotingTombstonesAction.INSTANCE, req, new RestToXContentListener<>(channel));
return channel -> client.execute(ClearVotingConfigExclusionsAction.INSTANCE, req, new RestToXContentListener<>(channel));
}
}

View File

@ -22,7 +22,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.coordination.CoordinationMetaData;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNode.Role;
@ -39,7 +39,7 @@ import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
public class AddVotingTombstonesRequestTests extends ESTestCase {
public class AddVotingConfigExclusionsRequestTests extends ESTestCase {
public void testSerialization() throws IOException {
int descriptionCount = between(0, 5);
String[] descriptions = new String[descriptionCount];
@ -47,8 +47,9 @@ public class AddVotingTombstonesRequestTests extends ESTestCase {
descriptions[i] = randomAlphaOfLength(10);
}
TimeValue timeout = TimeValue.timeValueMillis(between(0, 30000));
final AddVotingTombstonesRequest originalRequest = new AddVotingTombstonesRequest(descriptions, timeout);
final AddVotingTombstonesRequest deserialized = copyWriteable(originalRequest, writableRegistry(), AddVotingTombstonesRequest::new);
final AddVotingConfigExclusionsRequest originalRequest = new AddVotingConfigExclusionsRequest(descriptions, timeout);
final AddVotingConfigExclusionsRequest deserialized = copyWriteable(originalRequest, writableRegistry(),
AddVotingConfigExclusionsRequest::new);
assertThat(deserialized.getNodeDescriptions(), equalTo(originalRequest.getNodeDescriptions()));
assertThat(deserialized.getTimeout(), equalTo(originalRequest.getTimeout()));
}
@ -56,66 +57,66 @@ public class AddVotingTombstonesRequestTests extends ESTestCase {
public void testResolve() {
final DiscoveryNode localNode
= new DiscoveryNode("local", "local", buildNewFakeTransportAddress(), emptyMap(), singleton(Role.MASTER), Version.CURRENT);
final VotingTombstone localNodeTombstone = new VotingTombstone(localNode);
final VotingConfigExclusion localNodeExclusion = new VotingConfigExclusion(localNode);
final DiscoveryNode otherNode1
= new DiscoveryNode("other1", "other1", buildNewFakeTransportAddress(), emptyMap(), singleton(Role.MASTER), Version.CURRENT);
final VotingTombstone otherNode1Tombstone = new VotingTombstone(otherNode1);
final VotingConfigExclusion otherNode1Exclusion = new VotingConfigExclusion(otherNode1);
final DiscoveryNode otherNode2
= new DiscoveryNode("other2", "other2", buildNewFakeTransportAddress(), emptyMap(), singleton(Role.MASTER), Version.CURRENT);
final VotingTombstone otherNode2Tombstone = new VotingTombstone(otherNode2);
final VotingConfigExclusion otherNode2Exclusion = new VotingConfigExclusion(otherNode2);
final DiscoveryNode otherDataNode
= new DiscoveryNode("data", "data", buildNewFakeTransportAddress(), emptyMap(), emptySet(), Version.CURRENT);
final ClusterState clusterState = ClusterState.builder(new ClusterName("cluster")).nodes(new Builder()
.add(localNode).add(otherNode1).add(otherNode2).add(otherDataNode).localNodeId(localNode.getId())).build();
assertThat(makeRequest().resolveVotingTombstones(clusterState),
containsInAnyOrder(localNodeTombstone, otherNode1Tombstone, otherNode2Tombstone));
assertThat(makeRequest("_all").resolveVotingTombstones(clusterState),
containsInAnyOrder(localNodeTombstone, otherNode1Tombstone, otherNode2Tombstone));
assertThat(makeRequest("_local").resolveVotingTombstones(clusterState),
contains(localNodeTombstone));
assertThat(makeRequest("other*").resolveVotingTombstones(clusterState),
containsInAnyOrder(otherNode1Tombstone, otherNode2Tombstone));
assertThat(makeRequest().resolveVotingConfigExclusions(clusterState),
containsInAnyOrder(localNodeExclusion, otherNode1Exclusion, otherNode2Exclusion));
assertThat(makeRequest("_all").resolveVotingConfigExclusions(clusterState),
containsInAnyOrder(localNodeExclusion, otherNode1Exclusion, otherNode2Exclusion));
assertThat(makeRequest("_local").resolveVotingConfigExclusions(clusterState),
contains(localNodeExclusion));
assertThat(makeRequest("other*").resolveVotingConfigExclusions(clusterState),
containsInAnyOrder(otherNode1Exclusion, otherNode2Exclusion));
assertThat(expectThrows(IllegalArgumentException.class,
() -> makeRequest("not-a-node").resolveVotingTombstones(clusterState)).getMessage(),
equalTo("add voting tombstones request for [not-a-node] matched no master-eligible nodes"));
() -> makeRequest("not-a-node").resolveVotingConfigExclusions(clusterState)).getMessage(),
equalTo("add voting config exclusions request for [not-a-node] matched no master-eligible nodes"));
}
public void testResolveAndCheckMaximum() {
final DiscoveryNode localNode
= new DiscoveryNode("local", "local", buildNewFakeTransportAddress(), emptyMap(), singleton(Role.MASTER), Version.CURRENT);
final VotingTombstone localNodeTombstone = new VotingTombstone(localNode);
final VotingConfigExclusion localNodeExclusion = new VotingConfigExclusion(localNode);
final DiscoveryNode otherNode1
= new DiscoveryNode("other1", "other1", buildNewFakeTransportAddress(), emptyMap(), singleton(Role.MASTER), Version.CURRENT);
final VotingTombstone otherNode1Tombstone = new VotingTombstone(otherNode1);
final VotingConfigExclusion otherNode1Exclusion = new VotingConfigExclusion(otherNode1);
final DiscoveryNode otherNode2
= new DiscoveryNode("other2", "other2", buildNewFakeTransportAddress(), emptyMap(), singleton(Role.MASTER), Version.CURRENT);
final VotingTombstone otherNode2Tombstone = new VotingTombstone(otherNode2);
final VotingConfigExclusion otherNode2Exclusion = new VotingConfigExclusion(otherNode2);
final ClusterState.Builder builder = ClusterState.builder(new ClusterName("cluster")).nodes(new Builder()
.add(localNode).add(otherNode1).add(otherNode2).localNodeId(localNode.getId()));
builder.metaData(MetaData.builder()
.coordinationMetaData(CoordinationMetaData.builder().addVotingTombstone(otherNode1Tombstone).build()));
.coordinationMetaData(CoordinationMetaData.builder().addVotingConfigExclusion(otherNode1Exclusion).build()));
final ClusterState clusterState = builder.build();
assertThat(makeRequest().resolveVotingTombstonesAndCheckMaximum(clusterState, 3, "setting.name"),
containsInAnyOrder(localNodeTombstone, otherNode2Tombstone));
assertThat(makeRequest("_local").resolveVotingTombstonesAndCheckMaximum(clusterState, 2, "setting.name"),
contains(localNodeTombstone));
assertThat(makeRequest().resolveVotingConfigExclusionsAndCheckMaximum(clusterState, 3, "setting.name"),
containsInAnyOrder(localNodeExclusion, otherNode2Exclusion));
assertThat(makeRequest("_local").resolveVotingConfigExclusionsAndCheckMaximum(clusterState, 2, "setting.name"),
contains(localNodeExclusion));
assertThat(expectThrows(IllegalArgumentException.class,
() -> makeRequest().resolveVotingTombstonesAndCheckMaximum(clusterState, 2, "setting.name")).getMessage(),
equalTo("add voting tombstones request for [] would add [2] voting tombstones to the existing [1] which would exceed the " +
"maximum of [2] set by [setting.name]"));
() -> makeRequest().resolveVotingConfigExclusionsAndCheckMaximum(clusterState, 2, "setting.name")).getMessage(),
equalTo("add voting config exclusions request for [] would add [2] exclusions to the existing [1] which would exceed " +
"the maximum of [2] set by [setting.name]"));
assertThat(expectThrows(IllegalArgumentException.class,
() -> makeRequest("_local").resolveVotingTombstonesAndCheckMaximum(clusterState, 1, "setting.name")).getMessage(),
equalTo("add voting tombstones request for [_local] would add [1] voting tombstones to the existing [1] which would exceed " +
"the maximum of [1] set by [setting.name]"));
() -> makeRequest("_local").resolveVotingConfigExclusionsAndCheckMaximum(clusterState, 1, "setting.name")).getMessage(),
equalTo("add voting config exclusions request for [_local] would add [1] exclusions to the existing [1] which would " +
"exceed the maximum of [1] set by [setting.name]"));
}
private static AddVotingTombstonesRequest makeRequest(String... descriptions) {
return new AddVotingTombstonesRequest(descriptions);
private static AddVotingConfigExclusionsRequest makeRequest(String... descriptions) {
return new AddVotingConfigExclusionsRequest(descriptions);
}
}

View File

@ -22,10 +22,10 @@ import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
public class AddVotingTombstonesResponseTests extends ESTestCase {
public class AddVotingConfigExclusionsResponseTests extends ESTestCase {
public void testSerialization() throws IOException {
final AddVotingTombstonesResponse originalRequest = new AddVotingTombstonesResponse();
copyWriteable(originalRequest, writableRegistry(), AddVotingTombstonesResponse::new);
final AddVotingConfigExclusionsResponse originalRequest = new AddVotingConfigExclusionsResponse();
copyWriteable(originalRequest, writableRegistry(), AddVotingConfigExclusionsResponse::new);
// there are no fields so we're just checking that this doesn't throw anything
}
}

View File

@ -25,17 +25,17 @@ import java.io.IOException;
import static org.hamcrest.Matchers.equalTo;
public class ClearVotingTombstonesRequestTests extends ESTestCase {
public class ClearVotingConfigExclusionsRequestTests extends ESTestCase {
public void testSerialization() throws IOException {
final ClearVotingTombstonesRequest originalRequest = new ClearVotingTombstonesRequest();
final ClearVotingConfigExclusionsRequest originalRequest = new ClearVotingConfigExclusionsRequest();
if (randomBoolean()) {
originalRequest.setWaitForRemoval(randomBoolean());
}
if (randomBoolean()) {
originalRequest.setTimeout(TimeValue.timeValueMillis(randomLongBetween(0, 30000)));
}
final ClearVotingTombstonesRequest deserialized
= copyWriteable(originalRequest, writableRegistry(), ClearVotingTombstonesRequest::new);
final ClearVotingConfigExclusionsRequest deserialized
= copyWriteable(originalRequest, writableRegistry(), ClearVotingConfigExclusionsRequest::new);
assertThat(deserialized.getWaitForRemoval(), equalTo(originalRequest.getWaitForRemoval()));
assertThat(deserialized.getTimeout(), equalTo(originalRequest.getTimeout()));
}

View File

@ -22,10 +22,10 @@ import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
public class ClearVotingTombstonesResponseTests extends ESTestCase {
public class ClearVotingConfigExclusionsResponseTests extends ESTestCase {
public void testSerialization() throws IOException {
final ClearVotingTombstonesResponse originalRequest = new ClearVotingTombstonesResponse();
copyWriteable(originalRequest, writableRegistry(), ClearVotingTombstonesResponse::new);
final ClearVotingConfigExclusionsResponse originalRequest = new ClearVotingConfigExclusionsResponse();
copyWriteable(originalRequest, writableRegistry(), ClearVotingConfigExclusionsResponse::new);
// there are no fields so we're just checking that this doesn't throw anything
}
}

View File

@ -29,7 +29,7 @@ import org.elasticsearch.cluster.ClusterStateObserver.Listener;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.coordination.CoordinationMetaData;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfiguration;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
@ -61,7 +61,7 @@ import java.util.function.Consumer;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
import static org.elasticsearch.action.admin.cluster.configuration.TransportAddVotingTombstonesAction.MAXIMUM_VOTING_TOMBSTONES_SETTING;
import static org.elasticsearch.action.admin.cluster.configuration.TransportAddVotingConfigExclusionsAction.MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING;
import static org.elasticsearch.cluster.ClusterState.builder;
import static org.elasticsearch.test.ClusterServiceUtils.createClusterService;
import static org.elasticsearch.test.ClusterServiceUtils.setState;
@ -72,12 +72,12 @@ import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.sameInstance;
import static org.hamcrest.Matchers.startsWith;
public class TransportAddVotingTombstonesActionTests extends ESTestCase {
public class TransportAddVotingConfigExclusionsActionTests extends ESTestCase {
private static ThreadPool threadPool;
private static ClusterService clusterService;
private static DiscoveryNode localNode, otherNode1, otherNode2, otherDataNode;
private static VotingTombstone localNodeTombstone, otherNode1Tombstone, otherNode2Tombstone;
private static VotingConfigExclusion localNodeExclusion, otherNode1Exclusion, otherNode2Exclusion;
private TransportService transportService;
private ClusterStateObserver clusterStateObserver;
@ -86,11 +86,11 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
public static void createThreadPoolAndClusterService() {
threadPool = new TestThreadPool("test", Settings.EMPTY);
localNode = makeDiscoveryNode("local");
localNodeTombstone = new VotingTombstone(localNode);
localNodeExclusion = new VotingConfigExclusion(localNode);
otherNode1 = makeDiscoveryNode("other1");
otherNode1Tombstone = new VotingTombstone(otherNode1);
otherNode1Exclusion = new VotingConfigExclusion(otherNode1);
otherNode2 = makeDiscoveryNode("other2");
otherNode2Tombstone = new VotingTombstone(otherNode2);
otherNode2Exclusion = new VotingConfigExclusion(otherNode2);
otherDataNode = new DiscoveryNode("data", "data", buildNewFakeTransportAddress(), emptyMap(), emptySet(), Version.CURRENT);
clusterService = createClusterService(threadPool, localNode);
}
@ -111,7 +111,7 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
transportService = transport.createTransportService(Settings.EMPTY, threadPool,
TransportService.NOOP_TRANSPORT_INTERCEPTOR, boundTransportAddress -> localNode, null, emptySet());
new TransportAddVotingTombstonesAction(transportService, clusterService, threadPool, new ActionFilters(emptySet()),
new TransportAddVotingConfigExclusionsAction(transportService, clusterService, threadPool, new ActionFilters(emptySet()),
new IndexNameExpressionResolver()); // registers action
transportService.start();
@ -132,9 +132,9 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
public void testWithdrawsVoteFromANode() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
clusterStateObserver.waitForNextChange(new AdjustConfigurationForTombstones());
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"other1"}),
clusterStateObserver.waitForNextChange(new AdjustConfigurationForExclusions());
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"other1"}),
expectSuccess(r -> {
assertNotNull(r);
countDownLatch.countDown();
@ -142,15 +142,15 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(), contains(otherNode1Tombstone));
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(), contains(otherNode1Exclusion));
}
public void testWithdrawsVotesFromMultipleNodes() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
clusterStateObserver.waitForNextChange(new AdjustConfigurationForTombstones());
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"other1", "other2"}),
clusterStateObserver.waitForNextChange(new AdjustConfigurationForExclusions());
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"other1", "other2"}),
expectSuccess(r -> {
assertNotNull(r);
countDownLatch.countDown();
@ -158,16 +158,16 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(),
containsInAnyOrder(otherNode1Tombstone, otherNode2Tombstone));
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(),
containsInAnyOrder(otherNode1Exclusion, otherNode2Exclusion));
}
public void testWithdrawsVotesFromNodesMatchingWildcard() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
clusterStateObserver.waitForNextChange(new AdjustConfigurationForTombstones());
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"other*"}),
clusterStateObserver.waitForNextChange(new AdjustConfigurationForExclusions());
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"other*"}),
expectSuccess(r -> {
assertNotNull(r);
countDownLatch.countDown();
@ -175,16 +175,16 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(),
containsInAnyOrder(otherNode1Tombstone, otherNode2Tombstone));
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(),
containsInAnyOrder(otherNode1Exclusion, otherNode2Exclusion));
}
public void testWithdrawsVotesFromAllMasterEligibleNodes() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
clusterStateObserver.waitForNextChange(new AdjustConfigurationForTombstones());
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"_all"}),
clusterStateObserver.waitForNextChange(new AdjustConfigurationForExclusions());
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"_all"}),
expectSuccess(r -> {
assertNotNull(r);
countDownLatch.countDown();
@ -192,16 +192,16 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(),
containsInAnyOrder(localNodeTombstone, otherNode1Tombstone, otherNode2Tombstone));
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(),
containsInAnyOrder(localNodeExclusion, otherNode1Exclusion, otherNode2Exclusion));
}
public void testWithdrawsVoteFromLocalNode() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
clusterStateObserver.waitForNextChange(new AdjustConfigurationForTombstones());
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"_local"}),
clusterStateObserver.waitForNextChange(new AdjustConfigurationForExclusions());
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"_local"}),
expectSuccess(r -> {
assertNotNull(r);
countDownLatch.countDown();
@ -209,8 +209,8 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(),
contains(localNodeTombstone));
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(),
contains(localNodeExclusion));
}
public void testReturnsImmediatelyIfVoteAlreadyWithdrawn() throws InterruptedException {
@ -225,8 +225,8 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(1);
// no observer to reconfigure
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"other1"}, TimeValue.ZERO),
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"other1"}, TimeValue.ZERO),
expectSuccess(r -> {
assertNotNull(r);
countDownLatch.countDown();
@ -234,34 +234,16 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(),
contains(otherNode1Tombstone));
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(),
contains(otherNode1Exclusion));
}
public void testReturnsErrorIfNoMatchingNodes() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
final SetOnce<TransportException> exceptionHolder = new SetOnce<>();
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"not-a-node"}),
expectError(e -> {
exceptionHolder.set(e);
countDownLatch.countDown();
})
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
final Throwable rootCause = exceptionHolder.get().getRootCause();
assertThat(rootCause, instanceOf(IllegalArgumentException.class));
assertThat(rootCause.getMessage(), equalTo("add voting tombstones request for [not-a-node] matched no master-eligible nodes"));
}
public void testOnlyMatchesMasterEligibleNodes() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
final SetOnce<TransportException> exceptionHolder = new SetOnce<>();
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"_all", "master:false"}),
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"not-a-node"}),
expectError(e -> {
exceptionHolder.set(e);
countDownLatch.countDown();
@ -272,23 +254,42 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
final Throwable rootCause = exceptionHolder.get().getRootCause();
assertThat(rootCause, instanceOf(IllegalArgumentException.class));
assertThat(rootCause.getMessage(),
equalTo("add voting tombstones request for [_all, master:false] matched no master-eligible nodes"));
equalTo("add voting config exclusions request for [not-a-node] matched no master-eligible nodes"));
}
public void testSucceedsEvenIfAllTombstonesAlreadyAdded() throws InterruptedException {
public void testOnlyMatchesMasterEligibleNodes() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
final SetOnce<TransportException> exceptionHolder = new SetOnce<>();
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"_all", "master:false"}),
expectError(e -> {
exceptionHolder.set(e);
countDownLatch.countDown();
})
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
final Throwable rootCause = exceptionHolder.get().getRootCause();
assertThat(rootCause, instanceOf(IllegalArgumentException.class));
assertThat(rootCause.getMessage(),
equalTo("add voting config exclusions request for [_all, master:false] matched no master-eligible nodes"));
}
public void testSucceedsEvenIfAllExclusionsAlreadyAdded() throws InterruptedException {
final ClusterState state = clusterService.state();
final ClusterState.Builder builder = builder(state);
builder.metaData(MetaData.builder(state.metaData()).
coordinationMetaData(
CoordinationMetaData.builder(state.coordinationMetaData())
.addVotingTombstone(otherNode1Tombstone).
.addVotingConfigExclusion(otherNode1Exclusion).
build()));
setState(clusterService, builder);
final CountDownLatch countDownLatch = new CountDownLatch(1);
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"other1"}),
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"other1"}),
expectSuccess(r -> {
assertNotNull(r);
countDownLatch.countDown();
@ -296,21 +297,21 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(),
contains(otherNode1Tombstone));
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(),
contains(otherNode1Exclusion));
}
public void testReturnsErrorIfMaximumTombstoneCountExceeded() throws InterruptedException {
public void testReturnsErrorIfMaximumExclusionCountExceeded() throws InterruptedException {
final MetaData.Builder metaDataBuilder = MetaData.builder(clusterService.state().metaData()).persistentSettings(
Settings.builder().put(clusterService.state().metaData().persistentSettings())
.put(MAXIMUM_VOTING_TOMBSTONES_SETTING.getKey(), 2).build());
.put(MAXIMUM_VOTING_CONFIG_EXCLUSIONS_SETTING.getKey(), 2).build());
CoordinationMetaData.Builder coordinationMetaDataBuilder =
CoordinationMetaData.builder(clusterService.state().coordinationMetaData())
.addVotingTombstone(localNodeTombstone);
.addVotingConfigExclusion(localNodeExclusion);
final int existingCount, newCount;
if (randomBoolean()) {
coordinationMetaDataBuilder.addVotingTombstone(otherNode1Tombstone);
coordinationMetaDataBuilder.addVotingConfigExclusion(otherNode1Exclusion);
existingCount = 2;
newCount = 1;
} else {
@ -326,8 +327,8 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
final CountDownLatch countDownLatch = new CountDownLatch(1);
final SetOnce<TransportException> exceptionHolder = new SetOnce<>();
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"other*"}),
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"other*"}),
expectError(e -> {
exceptionHolder.set(e);
countDownLatch.countDown();
@ -337,17 +338,17 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
final Throwable rootCause = exceptionHolder.get().getRootCause();
assertThat(rootCause, instanceOf(IllegalArgumentException.class));
assertThat(rootCause.getMessage(), equalTo("add voting tombstones request for [other*] would add [" + newCount +
"] voting tombstones to the existing [" + existingCount +
"] which would exceed the maximum of [2] set by [cluster.max_voting_tombstones]"));
assertThat(rootCause.getMessage(), equalTo("add voting config exclusions request for [other*] would add [" + newCount +
"] exclusions to the existing [" + existingCount +
"] which would exceed the maximum of [2] set by [cluster.max_voting_config_exclusions]"));
}
public void testTimesOut() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
final SetOnce<TransportException> exceptionHolder = new SetOnce<>();
transportService.sendRequest(localNode, AddVotingTombstonesAction.NAME,
new AddVotingTombstonesRequest(new String[]{"other1"}, TimeValue.timeValueMillis(100)),
transportService.sendRequest(localNode, AddVotingConfigExclusionsAction.NAME,
new AddVotingConfigExclusionsRequest(new String[]{"other1"}, TimeValue.timeValueMillis(100)),
expectError(e -> {
exceptionHolder.set(e);
countDownLatch.countDown();
@ -357,26 +358,27 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
final Throwable rootCause = exceptionHolder.get().getRootCause();
assertThat(rootCause,instanceOf(ElasticsearchTimeoutException.class));
assertThat(rootCause.getMessage(), startsWith("timed out waiting for withdrawal of votes from [{other1}"));
assertThat(rootCause.getMessage(), startsWith("timed out waiting for voting config exclusions [{other1}"));
}
private TransportResponseHandler<AddVotingTombstonesResponse> expectSuccess(Consumer<AddVotingTombstonesResponse> onResponse) {
private TransportResponseHandler<AddVotingConfigExclusionsResponse> expectSuccess(
Consumer<AddVotingConfigExclusionsResponse> onResponse) {
return responseHandler(onResponse, e -> {
throw new AssertionError("unexpected", e);
});
}
private TransportResponseHandler<AddVotingTombstonesResponse> expectError(Consumer<TransportException> onException) {
private TransportResponseHandler<AddVotingConfigExclusionsResponse> expectError(Consumer<TransportException> onException) {
return responseHandler(r -> {
assert false : r;
}, onException);
}
private TransportResponseHandler<AddVotingTombstonesResponse> responseHandler(Consumer<AddVotingTombstonesResponse> onResponse,
Consumer<TransportException> onException) {
return new TransportResponseHandler<AddVotingTombstonesResponse>() {
private TransportResponseHandler<AddVotingConfigExclusionsResponse> responseHandler(
Consumer<AddVotingConfigExclusionsResponse> onResponse, Consumer<TransportException> onException) {
return new TransportResponseHandler<AddVotingConfigExclusionsResponse>() {
@Override
public void handleResponse(AddVotingTombstonesResponse response) {
public void handleResponse(AddVotingConfigExclusionsResponse response) {
onResponse.accept(response);
}
@ -391,13 +393,13 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
}
@Override
public AddVotingTombstonesResponse read(StreamInput in) throws IOException {
return new AddVotingTombstonesResponse(in);
public AddVotingConfigExclusionsResponse read(StreamInput in) throws IOException {
return new AddVotingConfigExclusionsResponse(in);
}
};
}
private class AdjustConfigurationForTombstones implements Listener {
private class AdjustConfigurationForExclusions implements Listener {
@Override
public void onNewClusterState(ClusterState state) {
clusterService.getMasterService().submitStateUpdateTask("reconfiguration", new ClusterStateUpdateTask() {
@ -406,7 +408,7 @@ public class TransportAddVotingTombstonesActionTests extends ESTestCase {
assertThat(currentState, sameInstance(state));
final Set<String> votingNodeIds = new HashSet<>();
currentState.nodes().forEach(n -> votingNodeIds.add(n.getId()));
currentState.getVotingTombstones().forEach(t -> votingNodeIds.remove(t.getNodeId()));
currentState.getVotingConfigExclusions().forEach(t -> votingNodeIds.remove(t.getNodeId()));
final VotingConfiguration votingConfiguration = new VotingConfiguration(votingNodeIds);
return builder(currentState)
.metaData(MetaData.builder(currentState.metaData())

View File

@ -25,7 +25,7 @@ import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.coordination.CoordinationMetaData;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
@ -62,12 +62,12 @@ import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.startsWith;
public class TransportClearVotingTombstonesActionTests extends ESTestCase {
public class TransportClearVotingConfigExclusionsActionTests extends ESTestCase {
private static ThreadPool threadPool;
private static ClusterService clusterService;
private static DiscoveryNode localNode, otherNode1, otherNode2;
private static VotingTombstone otherNode1Tombstone, otherNode2Tombstone;
private static VotingConfigExclusion otherNode1Exclusion, otherNode2Exclusion;
private TransportService transportService;
@ -76,9 +76,9 @@ public class TransportClearVotingTombstonesActionTests extends ESTestCase {
threadPool = new TestThreadPool("test", Settings.EMPTY);
localNode = new DiscoveryNode("local", buildNewFakeTransportAddress(), Version.CURRENT);
otherNode1 = new DiscoveryNode("other1", "other1", buildNewFakeTransportAddress(), emptyMap(), emptySet(), Version.CURRENT);
otherNode1Tombstone = new VotingTombstone(otherNode1);
otherNode1Exclusion = new VotingConfigExclusion(otherNode1);
otherNode2 = new DiscoveryNode("other2", "other2", buildNewFakeTransportAddress(), emptyMap(), emptySet(), Version.CURRENT);
otherNode2Tombstone = new VotingTombstone(otherNode2);
otherNode2Exclusion = new VotingConfigExclusion(otherNode2);
clusterService = createClusterService(threadPool, localNode);
}
@ -94,7 +94,7 @@ public class TransportClearVotingTombstonesActionTests extends ESTestCase {
transportService = transport.createTransportService(Settings.EMPTY, threadPool,
TransportService.NOOP_TRANSPORT_INTERCEPTOR, boundTransportAddress -> localNode, null, emptySet());
new TransportClearVotingTombstonesAction(transportService, clusterService, threadPool, new ActionFilters(emptySet()),
new TransportClearVotingConfigExclusionsAction(transportService, clusterService, threadPool, new ActionFilters(emptySet()),
new IndexNameExpressionResolver()); // registers action
transportService.start();
@ -105,20 +105,20 @@ public class TransportClearVotingTombstonesActionTests extends ESTestCase {
.localNodeId(localNode.getId()).masterNodeId(localNode.getId()));
builder.metaData(MetaData.builder()
.coordinationMetaData(CoordinationMetaData.builder()
.addVotingTombstone(otherNode1Tombstone)
.addVotingTombstone(otherNode2Tombstone)
.addVotingConfigExclusion(otherNode1Exclusion)
.addVotingConfigExclusion(otherNode2Exclusion)
.build()));
setState(clusterService, builder);
}
public void testClearsVotingTombstones() throws InterruptedException {
public void testClearsVotingConfigExclusions() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
final SetOnce<ClearVotingTombstonesResponse> responseHolder = new SetOnce<>();
final SetOnce<ClearVotingConfigExclusionsResponse> responseHolder = new SetOnce<>();
final ClearVotingTombstonesRequest clearVotingTombstonesRequest = new ClearVotingTombstonesRequest();
clearVotingTombstonesRequest.setWaitForRemoval(false);
transportService.sendRequest(localNode, ClearVotingTombstonesAction.NAME,
clearVotingTombstonesRequest,
final ClearVotingConfigExclusionsRequest clearVotingConfigExclusionsRequest = new ClearVotingConfigExclusionsRequest();
clearVotingConfigExclusionsRequest.setWaitForRemoval(false);
transportService.sendRequest(localNode, ClearVotingConfigExclusionsAction.NAME,
clearVotingConfigExclusionsRequest,
expectSuccess(r -> {
responseHolder.set(r);
countDownLatch.countDown();
@ -127,17 +127,17 @@ public class TransportClearVotingTombstonesActionTests extends ESTestCase {
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertNotNull(responseHolder.get());
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(), empty());
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(), empty());
}
public void testTimesOutIfWaitingForNodesThatAreNotRemoved() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
final SetOnce<TransportException> responseHolder = new SetOnce<>();
final ClearVotingTombstonesRequest clearVotingTombstonesRequest = new ClearVotingTombstonesRequest();
clearVotingTombstonesRequest.setTimeout(TimeValue.timeValueMillis(100));
transportService.sendRequest(localNode, ClearVotingTombstonesAction.NAME,
clearVotingTombstonesRequest,
final ClearVotingConfigExclusionsRequest clearVotingConfigExclusionsRequest = new ClearVotingConfigExclusionsRequest();
clearVotingConfigExclusionsRequest.setTimeout(TimeValue.timeValueMillis(100));
transportService.sendRequest(localNode, ClearVotingConfigExclusionsAction.NAME,
clearVotingConfigExclusionsRequest,
expectError(e -> {
responseHolder.set(e);
countDownLatch.countDown();
@ -145,8 +145,8 @@ public class TransportClearVotingTombstonesActionTests extends ESTestCase {
);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(),
containsInAnyOrder(otherNode1Tombstone, otherNode2Tombstone));
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(),
containsInAnyOrder(otherNode1Exclusion, otherNode2Exclusion));
final Throwable rootCause = responseHolder.get().getRootCause();
assertThat(rootCause, instanceOf(ElasticsearchTimeoutException.class));
assertThat(rootCause.getMessage(),
@ -155,10 +155,10 @@ public class TransportClearVotingTombstonesActionTests extends ESTestCase {
public void testSucceedsIfNodesAreRemovedWhileWaiting() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
final SetOnce<ClearVotingTombstonesResponse> responseHolder = new SetOnce<>();
final SetOnce<ClearVotingConfigExclusionsResponse> responseHolder = new SetOnce<>();
transportService.sendRequest(localNode, ClearVotingTombstonesAction.NAME,
new ClearVotingTombstonesRequest(),
transportService.sendRequest(localNode, ClearVotingConfigExclusionsAction.NAME,
new ClearVotingConfigExclusionsRequest(),
expectSuccess(r -> {
responseHolder.set(r);
countDownLatch.countDown();
@ -170,26 +170,27 @@ public class TransportClearVotingTombstonesActionTests extends ESTestCase {
setState(clusterService, builder);
assertTrue(countDownLatch.await(30, TimeUnit.SECONDS));
assertThat(clusterService.getClusterApplierService().state().getVotingTombstones(), empty());
assertThat(clusterService.getClusterApplierService().state().getVotingConfigExclusions(), empty());
}
private TransportResponseHandler<ClearVotingTombstonesResponse> expectSuccess(Consumer<ClearVotingTombstonesResponse> onResponse) {
private TransportResponseHandler<ClearVotingConfigExclusionsResponse> expectSuccess(
Consumer<ClearVotingConfigExclusionsResponse> onResponse) {
return responseHandler(onResponse, e -> {
throw new AssertionError("unexpected", e);
});
}
private TransportResponseHandler<ClearVotingTombstonesResponse> expectError(Consumer<TransportException> onException) {
private TransportResponseHandler<ClearVotingConfigExclusionsResponse> expectError(Consumer<TransportException> onException) {
return responseHandler(r -> {
assert false : r;
}, onException);
}
private TransportResponseHandler<ClearVotingTombstonesResponse> responseHandler(Consumer<ClearVotingTombstonesResponse> onResponse,
Consumer<TransportException> onException) {
return new TransportResponseHandler<ClearVotingTombstonesResponse>() {
private TransportResponseHandler<ClearVotingConfigExclusionsResponse> responseHandler(
Consumer<ClearVotingConfigExclusionsResponse> onResponse, Consumer<TransportException> onException) {
return new TransportResponseHandler<ClearVotingConfigExclusionsResponse>() {
@Override
public void handleResponse(ClearVotingTombstonesResponse response) {
public void handleResponse(ClearVotingConfigExclusionsResponse response) {
onResponse.accept(response);
}
@ -204,8 +205,8 @@ public class TransportClearVotingTombstonesActionTests extends ESTestCase {
}
@Override
public ClearVotingTombstonesResponse read(StreamInput in) throws IOException {
return new ClearVotingTombstonesResponse(in);
public ClearVotingConfigExclusionsResponse read(StreamInput in) throws IOException {
return new ClearVotingConfigExclusionsResponse(in);
}
};
}

View File

@ -88,7 +88,7 @@ public class ClusterRerouteResponseTests extends ESTestCase {
" \"term\" : 0,\n" +
" \"last_committed_config\" : [ ],\n" +
" \"last_accepted_config\" : [ ],\n" +
" \"voting_tombstones\" : [ ]\n" +
" \"voting_config_exclusions\" : [ ]\n" +
" },\n" +
" \"templates\" : { },\n" +
" \"indices\" : {\n" +
@ -183,7 +183,7 @@ public class ClusterRerouteResponseTests extends ESTestCase {
" \"term\" : 0,\n" +
" \"last_committed_config\" : [ ],\n" +
" \"last_accepted_config\" : [ ],\n" +
" \"voting_tombstones\" : [ ]\n" +
" \"voting_config_exclusions\" : [ ]\n" +
" },\n" +
" \"templates\" : { },\n" +
" \"indices\" : {\n" +

View File

@ -23,7 +23,7 @@ import com.carrotsearch.hppc.cursors.ObjectCursor;
import org.elasticsearch.cluster.block.ClusterBlock;
import org.elasticsearch.cluster.block.ClusterBlocks;
import org.elasticsearch.cluster.coordination.CoordinationMetaData;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexGraveyard;
import org.elasticsearch.cluster.metadata.IndexGraveyardTests;
@ -208,7 +208,7 @@ public class ClusterStateDiffIT extends ESIntegTestCase {
new CoordinationMetaData.VotingConfiguration(Sets.newHashSet(generateRandomStringArray(10, 10, false))));
}
if (randomBoolean()) {
metaBuilder.addVotingTombstone(new VotingTombstone(randomNode("node-" + randomAlphaOfLength(10))));
metaBuilder.addVotingConfigExclusion(new VotingConfigExclusion(randomNode("node-" + randomAlphaOfLength(10))));
}
return builder;
}

View File

@ -19,7 +19,7 @@
package org.elasticsearch.cluster.coordination;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfiguration;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.util.set.Sets;
@ -94,29 +94,29 @@ public class CoordinationMetaDataTests extends ESTestCase {
}
public void testVotingTombstoneSerializationEqualsHashCode() {
VotingTombstone tombstone = new VotingTombstone(randomAlphaOfLength(10), randomAlphaOfLength(10));
VotingConfigExclusion tombstone = new VotingConfigExclusion(randomAlphaOfLength(10), randomAlphaOfLength(10));
EqualsHashCodeTestUtils.checkEqualsAndHashCode(tombstone,
orig -> ESTestCase.copyWriteable(orig, new NamedWriteableRegistry(Collections.emptyList()), VotingTombstone::new),
orig -> ESTestCase.copyWriteable(orig, new NamedWriteableRegistry(Collections.emptyList()), VotingConfigExclusion::new),
orig -> randomlyChangeVotingTombstone(orig));
}
public void testVotingTombstoneXContent() throws IOException {
VotingTombstone originalTombstone = new VotingTombstone(randomAlphaOfLength(10), randomAlphaOfLength(10));
VotingConfigExclusion originalTombstone = new VotingConfigExclusion(randomAlphaOfLength(10), randomAlphaOfLength(10));
final XContentBuilder builder = JsonXContent.contentBuilder();
originalTombstone.toXContent(builder, ToXContent.EMPTY_PARAMS);
try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) {
final VotingTombstone fromXContentTombstone = VotingTombstone.fromXContent(parser);
final VotingConfigExclusion fromXContentTombstone = VotingConfigExclusion.fromXContent(parser);
assertThat(originalTombstone, equalTo(fromXContentTombstone));
}
}
private VotingTombstone randomlyChangeVotingTombstone(VotingTombstone tombstone) {
private VotingConfigExclusion randomlyChangeVotingTombstone(VotingConfigExclusion tombstone) {
if (randomBoolean()) {
return new VotingTombstone(randomAlphaOfLength(10), tombstone.getNodeName());
return new VotingConfigExclusion(randomAlphaOfLength(10), tombstone.getNodeName());
} else {
return new VotingTombstone(tombstone.getNodeId(), randomAlphaOfLength(10));
return new VotingConfigExclusion(tombstone.getNodeId(), randomAlphaOfLength(10));
}
}
@ -136,11 +136,11 @@ public class CoordinationMetaDataTests extends ESTestCase {
return new VotingConfiguration(newNodeIds);
}
private Set<VotingTombstone> randomVotingTombstones() {
private Set<VotingConfigExclusion> randomVotingTombstones() {
final int size = randomIntBetween(1, 10);
final Set<VotingTombstone> nodes = new HashSet<>(size);
final Set<VotingConfigExclusion> nodes = new HashSet<>(size);
while (nodes.size() < size) {
assertTrue(nodes.add(new VotingTombstone(randomAlphaOfLength(10), randomAlphaOfLength(10))));
assertTrue(nodes.add(new VotingConfigExclusion(randomAlphaOfLength(10), randomAlphaOfLength(10))));
}
return nodes;
}
@ -163,10 +163,10 @@ public class CoordinationMetaDataTests extends ESTestCase {
builder.lastAcceptedConfiguration(randomlyChangeVotingConfiguration(meta.getLastAcceptedConfiguration()));
break;
case 3:
if (meta.getVotingTombstones().isEmpty() == false && randomBoolean()) {
builder.clearVotingTombstones();
if (meta.getVotingConfigExclusions().isEmpty() == false && randomBoolean()) {
builder.clearVotingConfigExclusions();
} else {
randomVotingTombstones().forEach(dn -> builder.addVotingTombstone(dn));
randomVotingTombstones().forEach(dn -> builder.addVotingConfigExclusion(dn));
}
break;
}

View File

@ -23,7 +23,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.cluster.ClusterModule;
import org.elasticsearch.cluster.coordination.CoordinationMetaData;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.bytes.BytesReference;
@ -415,18 +415,18 @@ public class MetaDataTests extends ESTestCase {
return new CoordinationMetaData.VotingConfiguration(Sets.newHashSet(generateRandomStringArray(randomInt(10), 20, false)));
}
private Set<VotingTombstone> randomVotingTombstones() {
private Set<VotingConfigExclusion> randomVotingConfigExclusions() {
final int size = randomIntBetween(0, 10);
final Set<VotingTombstone> nodes = new HashSet<>(size);
final Set<VotingConfigExclusion> nodes = new HashSet<>(size);
while (nodes.size() < size) {
assertTrue(nodes.add(new VotingTombstone(randomAlphaOfLength(10), randomAlphaOfLength(10))));
assertTrue(nodes.add(new VotingConfigExclusion(randomAlphaOfLength(10), randomAlphaOfLength(10))));
}
return nodes;
}
public void testXContentWithCoordinationMetaData() throws IOException {
CoordinationMetaData originalMeta = new CoordinationMetaData(randomNonNegativeLong(), randomVotingConfig(), randomVotingConfig(),
randomVotingTombstones());
randomVotingConfigExclusions());
MetaData metaData = MetaData.builder().coordinationMetaData(originalMeta).build();
@ -443,10 +443,10 @@ public class MetaDataTests extends ESTestCase {
public void testGlobalStateEqualsCoordinationMetaData() {
CoordinationMetaData coordinationMetaData1 = new CoordinationMetaData(randomNonNegativeLong(), randomVotingConfig(),
randomVotingConfig(), randomVotingTombstones());
randomVotingConfig(), randomVotingConfigExclusions());
MetaData metaData1 = MetaData.builder().coordinationMetaData(coordinationMetaData1).build();
CoordinationMetaData coordinationMetaData2 = new CoordinationMetaData(randomNonNegativeLong(), randomVotingConfig(),
randomVotingConfig(), randomVotingTombstones());
randomVotingConfig(), randomVotingConfigExclusions());
MetaData metaData2 = MetaData.builder().coordinationMetaData(coordinationMetaData2).build();
assertTrue(MetaData.isGlobalStateEquals(metaData1, metaData1));

View File

@ -23,7 +23,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.coordination.CoordinationMetaData;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingTombstone;
import org.elasticsearch.cluster.coordination.CoordinationMetaData.VotingConfigExclusion;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.Manifest;
import org.elasticsearch.cluster.metadata.MetaData;
@ -145,7 +145,7 @@ public class GatewayMetaStatePersistedStateTests extends ESTestCase {
new CoordinationMetaData.VotingConfiguration(
Sets.newHashSet(generateRandomStringArray(10, 10, false))));
for (int i = 0; i < randomIntBetween(0, 5); i++) {
builder.addVotingTombstone(new VotingTombstone(randomAlphaOfLength(10), randomAlphaOfLength(10)));
builder.addVotingConfigExclusion(new VotingConfigExclusion(randomAlphaOfLength(10), randomAlphaOfLength(10)));
}
return builder.build();

View File

@ -31,10 +31,10 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.store.AlreadyClosedException;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingTombstonesAction;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingTombstonesRequest;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingTombstonesAction;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingTombstonesRequest;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsRequest;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsRequest;
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
import org.elasticsearch.action.admin.indices.stats.CommonStatsFlags;
import org.elasticsearch.action.admin.indices.stats.CommonStatsFlags.Flag;
@ -1636,7 +1636,7 @@ public final class InternalTestCluster extends TestCluster {
}
private synchronized void stopNodesAndClients(Collection<NodeAndClient> nodeAndClients) throws IOException {
final Set<String> withdrawnNodeIds = new HashSet<>();
final Set<String> excludedNodeIds = new HashSet<>();
if (autoManageMinMasterNodes && nodeAndClients.size() > 0) {
@ -1649,13 +1649,13 @@ public final class InternalTestCluster extends TestCluster {
// However, we do not yet have a way to be sure there's a majority left, because the voting configuration may not yet have
// been updated when the previous nodes shut down, so we must always explicitly withdraw votes.
// TODO add cluster health API to check that voting configuration is optimal so this isn't always needed
nodeAndClients.stream().filter(NodeAndClient::isMasterEligible).map(NodeAndClient::getName).forEach(withdrawnNodeIds::add);
assert withdrawnNodeIds.size() == stoppingMasters;
nodeAndClients.stream().filter(NodeAndClient::isMasterEligible).map(NodeAndClient::getName).forEach(excludedNodeIds::add);
assert excludedNodeIds.size() == stoppingMasters;
logger.info("withdrawing votes from {} prior to shutdown", withdrawnNodeIds);
logger.info("adding voting config exclusions {} prior to shutdown", excludedNodeIds);
try {
client().execute(AddVotingTombstonesAction.INSTANCE,
new AddVotingTombstonesRequest(withdrawnNodeIds.toArray(new String[0]))).get();
client().execute(AddVotingConfigExclusionsAction.INSTANCE,
new AddVotingConfigExclusionsRequest(excludedNodeIds.toArray(new String[0]))).get();
} catch (InterruptedException | ExecutionException e) {
throw new AssertionError("unexpected", e);
}
@ -1673,10 +1673,10 @@ public final class InternalTestCluster extends TestCluster {
nodeAndClient.close();
}
if (withdrawnNodeIds.isEmpty() == false) {
logger.info("removing voting tombstones for {} after shutdown", withdrawnNodeIds);
if (excludedNodeIds.isEmpty() == false) {
logger.info("removing voting config exclusions for {} after shutdown", excludedNodeIds);
try {
client().execute(ClearVotingTombstonesAction.INSTANCE, new ClearVotingTombstonesRequest()).get();
client().execute(ClearVotingConfigExclusionsAction.INSTANCE, new ClearVotingConfigExclusionsRequest()).get();
} catch (InterruptedException | ExecutionException e) {
throw new AssertionError("unexpected", e);
}