Skip to content

Commit ee05ef1

Browse files
committed
Merge branch 'zen2'
2 parents 9ae5ee2 + 38ab15c commit ee05ef1

File tree

227 files changed

+25402
-2139
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

227 files changed

+25402
-2139
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.rest.discovery;
21+
22+
import org.apache.http.HttpHost;
23+
import org.elasticsearch.ESNetty4IntegTestCase;
24+
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
25+
import org.elasticsearch.client.Client;
26+
import org.elasticsearch.client.Node;
27+
import org.elasticsearch.client.Request;
28+
import org.elasticsearch.client.Response;
29+
import org.elasticsearch.client.ResponseException;
30+
import org.elasticsearch.client.RestClient;
31+
import org.elasticsearch.cluster.coordination.ClusterBootstrapService;
32+
import org.elasticsearch.cluster.metadata.IndexMetaData;
33+
import org.elasticsearch.cluster.routing.UnassignedInfo;
34+
import org.elasticsearch.common.Priority;
35+
import org.elasticsearch.common.settings.Settings;
36+
import org.elasticsearch.common.settings.Settings.Builder;
37+
import org.elasticsearch.common.unit.TimeValue;
38+
import org.elasticsearch.discovery.zen.ElectMasterService;
39+
import org.elasticsearch.gateway.GatewayService;
40+
import org.elasticsearch.http.HttpServerTransport;
41+
import org.elasticsearch.test.ESIntegTestCase;
42+
import org.elasticsearch.test.InternalTestCluster;
43+
import org.elasticsearch.test.discovery.TestZenDiscovery;
44+
import org.hamcrest.Matchers;
45+
46+
import java.io.IOException;
47+
import java.util.Collections;
48+
import java.util.List;
49+
50+
import static org.hamcrest.core.Is.is;
51+
52+
// These tests are here today so they have access to a proper REST client. They cannot be in :server:integTest since the REST client needs a
53+
// proper transport implementation, and they cannot be REST tests today since they need to restart nodes. When #35599 and friends land we
54+
// should be able to move these tests to run against a proper cluster instead. TODO do this.
55+
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, transportClientRatio = 0, autoMinMasterNodes = false)
56+
public class Zen2RestApiIT extends ESNetty4IntegTestCase {
57+
58+
@Override
59+
protected Settings nodeSettings(int nodeOrdinal) {
60+
final Builder builder = Settings.builder().put(super.nodeSettings(nodeOrdinal))
61+
.put(TestZenDiscovery.USE_ZEN2.getKey(), true)
62+
.put(GatewayService.RECOVER_AFTER_MASTER_NODES_SETTING.getKey(), 1)
63+
.put(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), Integer.MAX_VALUE);
64+
65+
if (nodeOrdinal == 0) {
66+
builder.put(ClusterBootstrapService.INITIAL_MASTER_NODE_COUNT_SETTING.getKey(), 2);
67+
}
68+
69+
return builder.build();
70+
}
71+
72+
@Override
73+
protected boolean addMockHttpTransport() {
74+
return false; // enable http
75+
}
76+
77+
public void testRollingRestartOfTwoNodeCluster() throws Exception {
78+
final List<String> nodes = internalCluster().startNodes(2);
79+
createIndex("test",
80+
Settings.builder()
81+
.put(UnassignedInfo.INDEX_DELAYED_NODE_LEFT_TIMEOUT_SETTING.getKey(), TimeValue.ZERO) // assign shards
82+
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 2) // causes rebalancing
83+
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 1)
84+
.build());
85+
ensureGreen("test");
86+
87+
RestClient restClient = getRestClient();
88+
89+
internalCluster().rollingRestart(new InternalTestCluster.RestartCallback() {
90+
@Override
91+
public void doAfterNodes(int n, Client client) throws IOException {
92+
ensureGreen("test");
93+
Response response =
94+
restClient.performRequest(new Request("POST", "/_cluster/voting_config_exclusions/" +
95+
internalCluster().getNodeNames()[n]));
96+
assertThat(response.getStatusLine().getStatusCode(), is(200));
97+
}
98+
99+
@Override
100+
public Settings onNodeStopped(String nodeName) throws IOException {
101+
String viaNode = randomValueOtherThan(nodeName, () -> randomFrom(nodes));
102+
103+
List<Node> allNodes = restClient.getNodes();
104+
try {
105+
restClient.setNodes(
106+
Collections.singletonList(
107+
new Node(
108+
HttpHost.create(
109+
internalCluster().getInstance(HttpServerTransport.class, viaNode)
110+
.boundAddress().publishAddress().toString()
111+
)
112+
)
113+
)
114+
);
115+
Response deleteResponse = restClient.performRequest(new Request("DELETE", "/_cluster/voting_config_exclusions"));
116+
assertThat(deleteResponse.getStatusLine().getStatusCode(), is(200));
117+
118+
ClusterHealthResponse clusterHealthResponse = client(viaNode).admin().cluster().prepareHealth()
119+
.setWaitForEvents(Priority.LANGUID)
120+
.setWaitForNodes(Integer.toString(1))
121+
.setTimeout(TimeValue.timeValueSeconds(30L))
122+
.setWaitForYellowStatus()
123+
.get();
124+
assertFalse(nodeName, clusterHealthResponse.isTimedOut());
125+
return Settings.EMPTY;
126+
} finally {
127+
restClient.setNodes(allNodes);
128+
}
129+
}
130+
});
131+
ensureStableCluster(2);
132+
ensureGreen("test");
133+
assertThat(internalCluster().size(), is(2));
134+
}
135+
136+
public void testClearVotingTombstonesNotWaitingForRemoval() throws Exception {
137+
List<String> nodes = internalCluster().startNodes(3);
138+
RestClient restClient = getRestClient();
139+
Response response = restClient.performRequest(new Request("POST", "/_cluster/voting_config_exclusions/" + nodes.get(2)));
140+
assertThat(response.getStatusLine().getStatusCode(), is(200));
141+
assertThat(response.getEntity().getContentLength(), is(0L));
142+
Response deleteResponse = restClient.performRequest(
143+
new Request("DELETE", "/_cluster/voting_config_exclusions/?wait_for_removal=false"));
144+
assertThat(deleteResponse.getStatusLine().getStatusCode(), is(200));
145+
assertThat(deleteResponse.getEntity().getContentLength(), is(0L));
146+
}
147+
148+
public void testClearVotingTombstonesWaitingForRemoval() throws Exception {
149+
List<String> nodes = internalCluster().startNodes(3);
150+
RestClient restClient = getRestClient();
151+
String nodeToWithdraw = nodes.get(randomIntBetween(0, 2));
152+
Response response = restClient.performRequest(new Request("POST", "/_cluster/voting_config_exclusions/" + nodeToWithdraw));
153+
assertThat(response.getStatusLine().getStatusCode(), is(200));
154+
assertThat(response.getEntity().getContentLength(), is(0L));
155+
internalCluster().stopRandomNode(InternalTestCluster.nameFilter(nodeToWithdraw));
156+
Response deleteResponse = restClient.performRequest(new Request("DELETE", "/_cluster/voting_config_exclusions"));
157+
assertThat(deleteResponse.getStatusLine().getStatusCode(), is(200));
158+
assertThat(deleteResponse.getEntity().getContentLength(), is(0L));
159+
}
160+
161+
public void testFailsOnUnknownNode() throws Exception {
162+
internalCluster().startNodes(3);
163+
RestClient restClient = getRestClient();
164+
try {
165+
restClient.performRequest(new Request("POST", "/_cluster/voting_config_exclusions/invalid"));
166+
fail("Invalid node name should throw.");
167+
} catch (ResponseException e) {
168+
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(400));
169+
assertThat(
170+
e.getCause().getMessage(),
171+
Matchers.containsString("add voting config exclusions request for [invalid] matched no master-eligible nodes")
172+
);
173+
}
174+
}
175+
}

server/src/main/java/org/elasticsearch/ElasticsearchException.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -987,8 +987,8 @@ private enum ElasticsearchExceptionHandle {
987987
UNKNOWN_VERSION_ADDED),
988988
TYPE_MISSING_EXCEPTION(org.elasticsearch.indices.TypeMissingException.class,
989989
org.elasticsearch.indices.TypeMissingException::new, 137, UNKNOWN_VERSION_ADDED),
990-
FAILED_TO_COMMIT_CLUSTER_STATE_EXCEPTION(org.elasticsearch.discovery.Discovery.FailedToCommitClusterStateException.class,
991-
org.elasticsearch.discovery.Discovery.FailedToCommitClusterStateException::new, 140, UNKNOWN_VERSION_ADDED),
990+
FAILED_TO_COMMIT_CLUSTER_STATE_EXCEPTION(org.elasticsearch.cluster.coordination.FailedToCommitClusterStateException.class,
991+
org.elasticsearch.cluster.coordination.FailedToCommitClusterStateException::new, 140, UNKNOWN_VERSION_ADDED),
992992
QUERY_SHARD_EXCEPTION(org.elasticsearch.index.query.QueryShardException.class,
993993
org.elasticsearch.index.query.QueryShardException::new, 141, UNKNOWN_VERSION_ADDED),
994994
NO_LONGER_PRIMARY_SHARD_EXCEPTION(ShardStateAction.NoLongerPrimaryShardException.class,
@@ -1006,8 +1006,9 @@ private enum ElasticsearchExceptionHandle {
10061006
UNKNOWN_NAMED_OBJECT_EXCEPTION(org.elasticsearch.common.xcontent.UnknownNamedObjectException.class,
10071007
org.elasticsearch.common.xcontent.UnknownNamedObjectException::new, 148, UNKNOWN_VERSION_ADDED),
10081008
TOO_MANY_BUCKETS_EXCEPTION(MultiBucketConsumerService.TooManyBucketsException.class,
1009-
MultiBucketConsumerService.TooManyBucketsException::new, 149,
1010-
Version.V_7_0_0);
1009+
MultiBucketConsumerService.TooManyBucketsException::new, 149, Version.V_7_0_0),
1010+
COORDINATION_STATE_REJECTED_EXCEPTION(org.elasticsearch.cluster.coordination.CoordinationStateRejectedException.class,
1011+
org.elasticsearch.cluster.coordination.CoordinationStateRejectedException::new, 150, Version.V_7_0_0);
10111012

10121013
final Class<? extends ElasticsearchException> exceptionClass;
10131014
final CheckedFunction<StreamInput, ? extends ElasticsearchException, IOException> constructor;

server/src/main/java/org/elasticsearch/action/ActionModule.java

+16
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323
import org.apache.logging.log4j.LogManager;
2424
import org.elasticsearch.action.admin.cluster.allocation.ClusterAllocationExplainAction;
2525
import org.elasticsearch.action.admin.cluster.allocation.TransportClusterAllocationExplainAction;
26+
import org.elasticsearch.action.admin.cluster.bootstrap.BootstrapClusterAction;
27+
import org.elasticsearch.action.admin.cluster.bootstrap.GetDiscoveredNodesAction;
28+
import org.elasticsearch.action.admin.cluster.bootstrap.TransportBootstrapClusterAction;
29+
import org.elasticsearch.action.admin.cluster.bootstrap.TransportGetDiscoveredNodesAction;
30+
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsAction;
31+
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsAction;
32+
import org.elasticsearch.action.admin.cluster.configuration.TransportAddVotingConfigExclusionsAction;
33+
import org.elasticsearch.action.admin.cluster.configuration.TransportClearVotingConfigExclusionsAction;
2634
import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction;
2735
import org.elasticsearch.action.admin.cluster.health.TransportClusterHealthAction;
2836
import org.elasticsearch.action.admin.cluster.node.hotthreads.NodesHotThreadsAction;
@@ -217,6 +225,7 @@
217225
import org.elasticsearch.rest.action.RestFieldCapabilitiesAction;
218226
import org.elasticsearch.rest.action.RestMainAction;
219227
import org.elasticsearch.rest.action.admin.cluster.RestCancelTasksAction;
228+
import org.elasticsearch.rest.action.admin.cluster.RestClearVotingConfigExclusionsAction;
220229
import org.elasticsearch.rest.action.admin.cluster.RestClusterAllocationExplainAction;
221230
import org.elasticsearch.rest.action.admin.cluster.RestClusterGetSettingsAction;
222231
import org.elasticsearch.rest.action.admin.cluster.RestClusterHealthAction;
@@ -246,6 +255,7 @@
246255
import org.elasticsearch.rest.action.admin.cluster.RestRestoreSnapshotAction;
247256
import org.elasticsearch.rest.action.admin.cluster.RestSnapshotsStatusAction;
248257
import org.elasticsearch.rest.action.admin.cluster.RestVerifyRepositoryAction;
258+
import org.elasticsearch.rest.action.admin.cluster.RestAddVotingConfigExclusionAction;
249259
import org.elasticsearch.rest.action.admin.indices.RestAnalyzeAction;
250260
import org.elasticsearch.rest.action.admin.indices.RestClearIndicesCacheAction;
251261
import org.elasticsearch.rest.action.admin.indices.RestCloseIndexAction;
@@ -423,6 +433,10 @@ public <Request extends ActionRequest, Response extends ActionResponse> void reg
423433
actions.register(GetTaskAction.INSTANCE, TransportGetTaskAction.class);
424434
actions.register(CancelTasksAction.INSTANCE, TransportCancelTasksAction.class);
425435

436+
actions.register(GetDiscoveredNodesAction.INSTANCE, TransportGetDiscoveredNodesAction.class);
437+
actions.register(BootstrapClusterAction.INSTANCE, TransportBootstrapClusterAction.class);
438+
actions.register(AddVotingConfigExclusionsAction.INSTANCE, TransportAddVotingConfigExclusionsAction.class);
439+
actions.register(ClearVotingConfigExclusionsAction.INSTANCE, TransportClearVotingConfigExclusionsAction.class);
426440
actions.register(ClusterAllocationExplainAction.INSTANCE, TransportClusterAllocationExplainAction.class);
427441
actions.register(ClusterStatsAction.INSTANCE, TransportClusterStatsAction.class);
428442
actions.register(ClusterStateAction.INSTANCE, TransportClusterStateAction.class);
@@ -531,6 +545,8 @@ public void initRestHandlers(Supplier<DiscoveryNodes> nodesInCluster) {
531545
catActions.add((AbstractCatAction) a);
532546
}
533547
};
548+
registerHandler.accept(new RestAddVotingConfigExclusionAction(settings, restController));
549+
registerHandler.accept(new RestClearVotingConfigExclusionsAction(settings, restController));
534550
registerHandler.accept(new RestMainAction(settings, restController));
535551
registerHandler.accept(new RestNodesInfoAction(settings, restController, settingsFilter));
536552
registerHandler.accept(new RestRemoteClusterInfoAction(settings, restController));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.elasticsearch.action.admin.cluster.bootstrap;
20+
21+
import org.elasticsearch.action.Action;
22+
import org.elasticsearch.common.io.stream.Writeable.Reader;
23+
24+
public class BootstrapClusterAction extends Action<BootstrapClusterResponse> {
25+
public static final BootstrapClusterAction INSTANCE = new BootstrapClusterAction();
26+
public static final String NAME = "cluster:admin/bootstrap_cluster";
27+
28+
private BootstrapClusterAction() {
29+
super(NAME);
30+
}
31+
32+
@Override
33+
public BootstrapClusterResponse newResponse() {
34+
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
35+
}
36+
37+
@Override
38+
public Reader<BootstrapClusterResponse> getResponseReader() {
39+
return BootstrapClusterResponse::new;
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.elasticsearch.action.admin.cluster.bootstrap;
20+
21+
import org.elasticsearch.action.ActionRequest;
22+
import org.elasticsearch.action.ActionRequestValidationException;
23+
import org.elasticsearch.common.io.stream.StreamInput;
24+
import org.elasticsearch.common.io.stream.StreamOutput;
25+
26+
import java.io.IOException;
27+
28+
/**
29+
* Request to set the initial configuration of master-eligible nodes in a cluster so that the very first master election can take place.
30+
*/
31+
public class BootstrapClusterRequest extends ActionRequest {
32+
private final BootstrapConfiguration bootstrapConfiguration;
33+
34+
public BootstrapClusterRequest(BootstrapConfiguration bootstrapConfiguration) {
35+
this.bootstrapConfiguration = bootstrapConfiguration;
36+
}
37+
38+
public BootstrapClusterRequest(StreamInput in) throws IOException {
39+
super(in);
40+
bootstrapConfiguration = new BootstrapConfiguration(in);
41+
}
42+
43+
/**
44+
* @return the bootstrap configuration: the initial set of master-eligible nodes whose votes are counted in elections.
45+
*/
46+
public BootstrapConfiguration getBootstrapConfiguration() {
47+
return bootstrapConfiguration;
48+
}
49+
50+
@Override
51+
public ActionRequestValidationException validate() {
52+
return null;
53+
}
54+
55+
@Override
56+
public void readFrom(StreamInput in) throws IOException {
57+
throw new UnsupportedOperationException("usage of Streamable is to be replaced by Writeable");
58+
}
59+
60+
@Override
61+
public void writeTo(StreamOutput out) throws IOException {
62+
super.writeTo(out);
63+
bootstrapConfiguration.writeTo(out);
64+
}
65+
}

0 commit comments

Comments
 (0)