Zen2: Rename tombstones to exclusions (#36226)
Renames the withdrawal / tombstones APIs to voting configuration exclusions.
This commit is contained in:
parent
5d6602120f
commit
03d0ea91ef
|
@ -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")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 +
|
||||
'}';
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 +
|
||||
'}';
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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()));
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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())
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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" +
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue