Universal cluster bootstrap method for tests with autoMinMasterNodes=false (#38038)

Currently, there are a few tests that use autoMinMasterNodes=false and
hence override addExtraClusterBootstrapSettings, mostly this is 10-30
lines of codes that are copy-pasted from class to class.

This PR introduces `InternalTestCluster.setBootstrapMasterNodeIndex`
which is suitable for all classes and copy-paste could be removed.

Removing code is always a good thing!
This commit is contained in:
Andrey Ershov 2019-02-01 11:34:31 +01:00 committed by GitHub
parent 0e6a7c20a1
commit bfd618cf83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 105 additions and 213 deletions

View File

@ -28,7 +28,6 @@ import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.cluster.coordination.ClusterBootstrapService;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.routing.UnassignedInfo;
import org.elasticsearch.common.Priority;
@ -41,10 +40,8 @@ import org.elasticsearch.test.discovery.TestZenDiscovery;
import org.hamcrest.Matchers;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.hamcrest.core.Is.is;
@ -59,30 +56,13 @@ public class Zen2RestApiIT extends ESNetty4IntegTestCase {
return Settings.builder().put(super.nodeSettings(nodeOrdinal)).put(TestZenDiscovery.USE_ZEN2.getKey(), true).build();
}
@Override
protected List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
final Settings firstNodeSettings = allNodesSettings.get(0);
final List<Settings> otherNodesSettings = allNodesSettings.subList(1, allNodesSettings.size());
final List<String> masterNodeNames = allNodesSettings.stream()
.filter(org.elasticsearch.node.Node.NODE_MASTER_SETTING::get)
.map(org.elasticsearch.node.Node.NODE_NAME_SETTING::get)
.collect(Collectors.toList());
final List<Settings> updatedSettings = new ArrayList<>();
updatedSettings.add(Settings.builder().put(firstNodeSettings)
.putList(ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING.getKey(), masterNodeNames)
.build());
updatedSettings.addAll(otherNodesSettings);
return updatedSettings;
}
@Override
protected boolean addMockHttpTransport() {
return false; // enable http
}
public void testRollingRestartOfTwoNodeCluster() throws Exception {
internalCluster().setBootstrapMasterNodeIndex(1);
final List<String> nodes = internalCluster().startNodes(2);
createIndex("test",
Settings.builder()
@ -142,6 +122,7 @@ public class Zen2RestApiIT extends ESNetty4IntegTestCase {
}
public void testClearVotingTombstonesNotWaitingForRemoval() throws Exception {
internalCluster().setBootstrapMasterNodeIndex(2);
List<String> nodes = internalCluster().startNodes(3);
RestClient restClient = getRestClient();
Response response = restClient.performRequest(new Request("POST", "/_cluster/voting_config_exclusions/" + nodes.get(2)));
@ -154,6 +135,7 @@ public class Zen2RestApiIT extends ESNetty4IntegTestCase {
}
public void testClearVotingTombstonesWaitingForRemoval() throws Exception {
internalCluster().setBootstrapMasterNodeIndex(2);
List<String> nodes = internalCluster().startNodes(3);
RestClient restClient = getRestClient();
String nodeToWithdraw = nodes.get(randomIntBetween(0, 2));
@ -167,6 +149,7 @@ public class Zen2RestApiIT extends ESNetty4IntegTestCase {
}
public void testFailsOnUnknownNode() throws Exception {
internalCluster().setBootstrapMasterNodeIndex(2);
internalCluster().startNodes(3);
RestClient restClient = getRestClient();
try {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.action.admin.indices.exists;
import org.elasticsearch.cluster.coordination.ClusterBootstrapService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.discovery.MasterNotDiscoveredException;
@ -29,26 +28,14 @@ import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.InternalTestCluster;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import static org.elasticsearch.node.Node.NODE_MASTER_SETTING;
import static org.elasticsearch.node.Node.NODE_NAME_SETTING;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows;
@ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, numClientNodes = 0, transportClientRatio = 0.0,
autoMinMasterNodes = false)
public class IndicesExistsIT extends ESIntegTestCase {
@Override
protected List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
final List<String> masterNodeNames
= allNodesSettings.stream().filter(NODE_MASTER_SETTING::get).map(NODE_NAME_SETTING::get).collect(Collectors.toList());
return allNodesSettings.stream().map(s -> Settings.builder().put(s)
.putList(ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING.getKey(), masterNodeNames).build()).collect(Collectors.toList());
}
public void testIndexExistsWithBlocksInPlace() throws IOException {
internalCluster().setBootstrapMasterNodeIndex(0);
Settings settings = Settings.builder()
.put(GatewayService.RECOVER_AFTER_NODES_SETTING.getKey(), 99).build();
String node = internalCluster().startNode(settings);

View File

@ -25,7 +25,6 @@ import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExc
import org.elasticsearch.action.admin.cluster.configuration.ClearVotingConfigExclusionsRequest;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.coordination.ClusterBootstrapService;
import org.elasticsearch.cluster.coordination.FailedToCommitClusterStateException;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
@ -35,7 +34,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.discovery.DiscoverySettings;
import org.elasticsearch.discovery.zen.ZenDiscovery;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.node.Node;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
@ -46,12 +44,10 @@ import org.elasticsearch.test.disruption.NetworkDisruption.TwoPartitions;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.test.transport.MockTransportService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
@ -68,8 +64,6 @@ import static org.hamcrest.Matchers.nullValue;
@TestLogging("_root:DEBUG,org.elasticsearch.cluster.service:TRACE,org.elasticsearch.discovery.zen:TRACE")
public class MinimumMasterNodesIT extends ESIntegTestCase {
private int bootstrapNodeId;
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
final HashSet<Class<? extends Plugin>> classes = new HashSet<>(super.nodePlugins());
@ -77,28 +71,8 @@ public class MinimumMasterNodesIT extends ESIntegTestCase {
return classes;
}
@Override
protected List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
if (internalCluster().size() + allNodesSettings.size() == bootstrapNodeId) {
List<String> nodeNames = new ArrayList<>();
Collections.addAll(nodeNames, internalCluster().getNodeNames());
allNodesSettings.forEach(settings -> nodeNames.add(Node.NODE_NAME_SETTING.get(settings)));
List<Settings> otherNodesSettings = allNodesSettings.subList(0, allNodesSettings.size() - 1);
Settings lastNodeSettings = allNodesSettings.get(allNodesSettings.size()-1);
List<Settings> newSettings = new ArrayList<>();
newSettings.addAll(otherNodesSettings);
newSettings.add(Settings.builder().put(lastNodeSettings)
.putList(ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING.getKey(), nodeNames)
.build());
return newSettings;
}
return allNodesSettings;
}
public void testTwoNodesNoMasterBlock() throws Exception {
//bootstrap cluster once second node is started
bootstrapNodeId = 2;
internalCluster().setBootstrapMasterNodeIndex(1);
Settings settings = Settings.builder()
.put(ZenDiscovery.PING_TIMEOUT_SETTING.getKey(), "200ms")
@ -231,8 +205,7 @@ public class MinimumMasterNodesIT extends ESIntegTestCase {
}
public void testThreeNodesNoMasterBlock() throws Exception {
//bootstrap cluster once 3rd node is started
bootstrapNodeId = 3;
internalCluster().setBootstrapMasterNodeIndex(2);
Settings settings = Settings.builder()
.put(ZenDiscovery.PING_TIMEOUT_SETTING.getKey(), "1s")
@ -307,8 +280,7 @@ public class MinimumMasterNodesIT extends ESIntegTestCase {
}
public void testCannotCommitStateThreeNodes() throws Exception {
//bootstrap cluster once 3rd node is started
bootstrapNodeId = 3;
internalCluster().setBootstrapMasterNodeIndex(2);
Settings settings = Settings.builder()
.put(ZenDiscovery.PING_TIMEOUT_SETTING.getKey(), "200ms")

View File

@ -22,7 +22,6 @@ package org.elasticsearch.cluster;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsAction;
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsRequest;
import org.elasticsearch.cluster.coordination.ClusterBootstrapService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.discovery.MasterNotDiscoveredException;
@ -35,8 +34,6 @@ import org.elasticsearch.test.InternalTestCluster;
import org.elasticsearch.test.junit.annotations.TestLogging;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.equalTo;
@ -46,20 +43,8 @@ import static org.hamcrest.Matchers.nullValue;
@TestLogging("_root:DEBUG,org.elasticsearch.action.admin.cluster.state:TRACE")
public class SpecificMasterNodesIT extends ESIntegTestCase {
@Override
protected List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
// if it's the first master in the cluster bootstrap the cluster with this node name
Settings settings = allNodesSettings.get(0);
if (internalCluster().numMasterNodes() == 0 && settings.getAsBoolean(Node.NODE_MASTER_SETTING.getKey(), false)) {
return Collections.singletonList(Settings.builder()
.put(settings)
.put(ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING.getKey(), settings.get(Node.NODE_NAME_SETTING.getKey()))
.build());
}
return allNodesSettings;
}
public void testSimpleOnlyMasterNodeElection() throws IOException {
internalCluster().setBootstrapMasterNodeIndex(0);
logger.info("--> start data node / non master node");
internalCluster().startNode(Settings.builder().put(Node.NODE_DATA_SETTING.getKey(), true)
.put(Node.NODE_MASTER_SETTING.getKey(), false)
@ -100,6 +85,7 @@ public class SpecificMasterNodesIT extends ESIntegTestCase {
}
public void testElectOnlyBetweenMasterNodes() throws Exception {
internalCluster().setBootstrapMasterNodeIndex(0);
logger.info("--> start data node / non master node");
internalCluster().startNode(Settings.builder().put(Node.NODE_DATA_SETTING.getKey(), true)
.put(Node.NODE_MASTER_SETTING.getKey(), false).put("discovery.initial_state_timeout", "1s"));
@ -146,6 +132,7 @@ public class SpecificMasterNodesIT extends ESIntegTestCase {
}
public void testAliasFilterValidation() {
internalCluster().setBootstrapMasterNodeIndex(0);
logger.info("--> start master node / non data");
internalCluster().startNode(Settings.builder()
.put(Node.NODE_DATA_SETTING.getKey(), false).put(Node.NODE_MASTER_SETTING.getKey(), true));

View File

@ -36,11 +36,8 @@ import org.elasticsearch.node.Node;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.InternalTestCluster;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@ -50,42 +47,6 @@ import static org.hamcrest.Matchers.containsString;
@TestLogging("_root:DEBUG,org.elasticsearch.cluster.service:TRACE,org.elasticsearch.discovery.zen:TRACE")
public class UnsafeBootstrapMasterIT extends ESIntegTestCase {
private int bootstrapNodeId;
@Before
public void resetBootstrapNodeId() {
bootstrapNodeId = -1;
}
/**
* Performs cluster bootstrap when node with id bootstrapNodeId is started.
* Any node of the batch could be selected as bootstrap target.
*/
@Override
protected List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
if (internalCluster().size() + allNodesSettings.size() == bootstrapNodeId) {
List<String> nodeNames = new ArrayList<>();
Collections.addAll(nodeNames, internalCluster().getNodeNames());
allNodesSettings.forEach(settings -> nodeNames.add(Node.NODE_NAME_SETTING.get(settings)));
List<Settings> newSettings = new ArrayList<>();
int bootstrapIndex = randomInt(allNodesSettings.size() - 1);
for (int i = 0; i < allNodesSettings.size(); i++) {
Settings nodeSettings = allNodesSettings.get(i);
if (i == bootstrapIndex) {
newSettings.add(Settings.builder().put(nodeSettings)
.putList(ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING.getKey(), nodeNames)
.build());
} else {
newSettings.add(nodeSettings);
}
}
return newSettings;
}
return allNodesSettings;
}
private MockTerminal executeCommand(Environment environment, boolean abort) throws Exception {
final UnsafeBootstrapMasterCommand command = new UnsafeBootstrapMasterCommand();
final MockTerminal terminal = new MockTerminal();
@ -169,7 +130,7 @@ public class UnsafeBootstrapMasterIT extends ESIntegTestCase {
}
public void testNoManifestFile() throws IOException {
bootstrapNodeId = 1;
internalCluster().setBootstrapMasterNodeIndex(0);
internalCluster().startNode();
ensureStableCluster(1);
NodeEnvironment nodeEnvironment = internalCluster().getMasterNodeInstance(NodeEnvironment.class);
@ -181,7 +142,7 @@ public class UnsafeBootstrapMasterIT extends ESIntegTestCase {
}
public void testNoMetaData() throws IOException {
bootstrapNodeId = 1;
internalCluster().setBootstrapMasterNodeIndex(0);
internalCluster().startNode();
ensureStableCluster(1);
NodeEnvironment nodeEnvironment = internalCluster().getMasterNodeInstance(NodeEnvironment.class);
@ -194,7 +155,7 @@ public class UnsafeBootstrapMasterIT extends ESIntegTestCase {
}
public void testAbortedByUser() throws IOException {
bootstrapNodeId = 1;
internalCluster().setBootstrapMasterNodeIndex(0);
internalCluster().startNode();
ensureStableCluster(1);
internalCluster().stopRandomDataNode();
@ -204,7 +165,7 @@ public class UnsafeBootstrapMasterIT extends ESIntegTestCase {
}
public void test3MasterNodes2Failed() throws Exception {
bootstrapNodeId = 3;
internalCluster().setBootstrapMasterNodeIndex(2);
List<String> masterNodes = internalCluster().startMasterOnlyNodes(3, Settings.EMPTY);
String dataNode = internalCluster().startDataOnlyNode();

View File

@ -22,7 +22,6 @@ package org.elasticsearch.gateway;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.block.ClusterBlock;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.coordination.ClusterBootstrapService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.node.Node;
@ -30,8 +29,6 @@ import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.Scope;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo;
@ -41,22 +38,6 @@ import static org.hamcrest.Matchers.hasItem;
public class RecoverAfterNodesIT extends ESIntegTestCase {
private static final TimeValue BLOCK_WAIT_TIMEOUT = TimeValue.timeValueSeconds(10);
@Override
protected List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
if (internalCluster().numDataAndMasterNodes() == 0) {
final Settings firstNodeSettings = allNodesSettings.get(0);
final List<Settings> otherNodesSettings = allNodesSettings.subList(1, allNodesSettings.size());
final List<Settings> updatedSettings = new ArrayList<>();
updatedSettings.add(Settings.builder().put(firstNodeSettings)
.putList(ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING.getKey(),
Node.NODE_NAME_SETTING.get(firstNodeSettings)).build());
updatedSettings.addAll(otherNodesSettings);
return updatedSettings;
}
return super.addExtraClusterBootstrapSettings(allNodesSettings);
}
public Set<ClusterBlock> waitForNoBlocksOnNode(TimeValue timeout, Client nodeClient) {
long start = System.currentTimeMillis();
@ -75,6 +56,7 @@ public class RecoverAfterNodesIT extends ESIntegTestCase {
}
public void testRecoverAfterNodes() throws Exception {
internalCluster().setBootstrapMasterNodeIndex(0);
logger.info("--> start node (1)");
Client clientNode1 = startNode(Settings.builder().put("gateway.recover_after_nodes", 3));
assertThat(clientNode1.admin().cluster().prepareState().setLocal(true).execute().actionGet()
@ -100,6 +82,7 @@ public class RecoverAfterNodesIT extends ESIntegTestCase {
}
public void testRecoverAfterMasterNodes() throws Exception {
internalCluster().setBootstrapMasterNodeIndex(0);
logger.info("--> start master_node (1)");
Client master1 = startNode(Settings.builder()
.put("gateway.recover_after_master_nodes", 2).put(Node.NODE_DATA_SETTING.getKey(), false)
@ -145,6 +128,7 @@ public class RecoverAfterNodesIT extends ESIntegTestCase {
}
public void testRecoverAfterDataNodes() throws Exception {
internalCluster().setBootstrapMasterNodeIndex(0);
logger.info("--> start master_node (1)");
Client master1 = startNode(Settings.builder()
.put("gateway.recover_after_data_nodes", 2)

View File

@ -1942,11 +1942,6 @@ public abstract class ESIntegTestCase extends ESTestCase {
.put(ESIntegTestCase.this.nodeSettings(nodeOrdinal)).build();
}
@Override
public List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
return ESIntegTestCase.this.addExtraClusterBootstrapSettings(allNodesSettings);
}
@Override
public Path nodeConfigPath(int nodeOrdinal) {
return ESIntegTestCase.this.nodeConfigPath(nodeOrdinal);
@ -1975,18 +1970,6 @@ public abstract class ESIntegTestCase extends ESTestCase {
};
}
/**
* This method is called before starting a collection of nodes.
* At this point the test has a holistic view on all nodes settings and might perform settings adjustments as needed.
* For instance, the test could retrieve master node names and fill in
* {@link org.elasticsearch.cluster.coordination.ClusterBootstrapService#INITIAL_MASTER_NODES_SETTING} setting.
*
* @param allNodesSettings list of node settings before update
* @return list of node settings after update
*/
protected List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
return allNodesSettings;
}
/**
* Iff this returns true mock transport implementations are used for the test runs. Otherwise not mock transport impls are used.
@ -2214,6 +2197,9 @@ public abstract class ESIntegTestCase extends ESTestCase {
// Deleting indices is going to clear search contexts implicitly so we
// need to check that there are no more in-flight search contexts before
// we remove indices
if (isInternalCluster()) {
internalCluster().setBootstrapMasterNodeIndex(-1);
}
super.ensureAllSearchContextsReleased();
if (runTestScopeLifecycle()) {
printTestMessage("cleaning up after");

View File

@ -43,6 +43,7 @@ import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.action.index.MappingUpdatedAction;
import org.elasticsearch.cluster.coordination.ClusterBootstrapService;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNode.Role;
@ -243,6 +244,8 @@ public final class InternalTestCluster extends TestCluster {
// If set to true only the first node in the cluster will be made a unicast node
private boolean hostsListContainsOnlyFirstNode;
private int bootstrapMasterNodeIndex = -1;
public InternalTestCluster(
final long clusterSeed,
final Path baseDir,
@ -400,6 +403,22 @@ public final class InternalTestCluster extends TestCluster {
EsExecutors.daemonThreadFactory("test_" + clusterName), new ThreadContext(Settings.EMPTY));
}
public int getBootstrapMasterNodeIndex() {
return bootstrapMasterNodeIndex;
}
/**
* Sets {@link #bootstrapMasterNodeIndex} to the given value, see {@link #bootstrapMasterNodeWithSpecifiedIndex(List)}
* for the description of how this field is used.
* It's only possible to change {@link #bootstrapMasterNodeIndex} value if autoManageMinMasterNodes is false.
*/
public void setBootstrapMasterNodeIndex(int bootstrapMasterNodeIndex) {
if (autoManageMinMasterNodes && bootstrapMasterNodeIndex != -1) {
throw new AssertionError("bootstrapMasterNodeIndex should be -1 if autoManageMinMasterNodes is true");
}
this.bootstrapMasterNodeIndex = bootstrapMasterNodeIndex;
}
@Override
public String getClusterName() {
return clusterName;
@ -1146,7 +1165,7 @@ public final class InternalTestCluster extends TestCluster {
settings.add(getNodeSettings(i, sharedNodesSeeds[i], extraSettings.build(), defaultMinMasterNodes));
}
int bootstrapNodeIndex = -1;
int autoBootstrapMasterNodeIndex = -1;
final List<String> masterNodeNames = settings.stream()
.filter(Node.NODE_MASTER_SETTING::get)
.map(Node.NODE_NAME_SETTING::get)
@ -1154,17 +1173,17 @@ public final class InternalTestCluster extends TestCluster {
if (prevNodeCount == 0 && autoManageMinMasterNodes) {
if (numSharedDedicatedMasterNodes > 0) {
bootstrapNodeIndex = RandomNumbers.randomIntBetween(random, 0, numSharedDedicatedMasterNodes - 1);
autoBootstrapMasterNodeIndex = RandomNumbers.randomIntBetween(random, 0, numSharedDedicatedMasterNodes - 1);
} else if (numSharedDataNodes > 0) {
bootstrapNodeIndex = RandomNumbers.randomIntBetween(random, 0, numSharedDataNodes - 1);
autoBootstrapMasterNodeIndex = RandomNumbers.randomIntBetween(random, 0, numSharedDataNodes - 1);
}
}
final List<Settings> updatedSettings = nodeConfigurationSource.addExtraClusterBootstrapSettings(settings);
final List<Settings> updatedSettings = bootstrapMasterNodeWithSpecifiedIndex(settings);
for (int i = 0; i < numSharedDedicatedMasterNodes + numSharedDataNodes + numSharedCoordOnlyNodes; i++) {
Settings nodeSettings = updatedSettings.get(i);
if (i == bootstrapNodeIndex) {
if (i == autoBootstrapMasterNodeIndex) {
nodeSettings = Settings.builder().putList(INITIAL_MASTER_NODES_SETTING.getKey(), masterNodeNames).put(nodeSettings).build();
}
final NodeAndClient nodeAndClient = buildNode(i, nodeSettings, true, onTransportServiceStarted);
@ -1944,6 +1963,54 @@ public final class InternalTestCluster extends TestCluster {
return Collections.emptySet();
}
/**
* Performs cluster bootstrap when node with index {@link #bootstrapMasterNodeIndex} is started
* with the names of all existing and new master-eligible nodes.
* Indexing starts from 0.
* If {@link #bootstrapMasterNodeIndex} is -1 (default), this method does nothing.
*/
private List<Settings> bootstrapMasterNodeWithSpecifiedIndex(List<Settings> allNodesSettings) {
if (getBootstrapMasterNodeIndex() == -1) { // fast-path
return allNodesSettings;
}
int currentNodeId = numMasterNodes() - 1;
List<Settings> newSettings = new ArrayList<>();
for (Settings settings : allNodesSettings) {
if (Node.NODE_MASTER_SETTING.get(settings) == false) {
newSettings.add(settings);
} else {
currentNodeId++;
if (currentNodeId != bootstrapMasterNodeIndex) {
newSettings.add(settings);
} else {
List<String> nodeNames = new ArrayList<>();
for (Settings nodeSettings : getDataOrMasterNodeInstances(Settings.class)) {
if (Node.NODE_MASTER_SETTING.get(nodeSettings)) {
nodeNames.add(Node.NODE_NAME_SETTING.get(nodeSettings));
}
}
for (Settings nodeSettings : allNodesSettings) {
if (Node.NODE_MASTER_SETTING.get(nodeSettings)) {
nodeNames.add(Node.NODE_NAME_SETTING.get(nodeSettings));
}
}
newSettings.add(Settings.builder().put(settings)
.putList(ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING.getKey(), nodeNames)
.build());
setBootstrapMasterNodeIndex(-1);
}
}
}
return newSettings;
}
/**
* Starts a node with default settings and returns its name.
*/
@ -1992,7 +2059,7 @@ public final class InternalTestCluster extends TestCluster {
}
final List<NodeAndClient> nodes = new ArrayList<>();
final int prevMasterCount = getMasterNodesCount();
int bootstrapMasterNodeIndex =
int autoBootstrapMasterNodeIndex =
prevMasterCount == 0 && autoManageMinMasterNodes && newMasterCount > 0 && Arrays.stream(extraSettings)
.allMatch(s -> Node.NODE_MASTER_SETTING.get(s) == false || TestZenDiscovery.USE_ZEN2.get(s) == true)
? RandomNumbers.randomIntBetween(random, 0, newMasterCount - 1) : -1;
@ -2010,16 +2077,16 @@ public final class InternalTestCluster extends TestCluster {
.map(Node.NODE_NAME_SETTING::get)
.collect(Collectors.toList());
final List<Settings> updatedSettings = nodeConfigurationSource.addExtraClusterBootstrapSettings(settings);
final List<Settings> updatedSettings = bootstrapMasterNodeWithSpecifiedIndex(settings);
for (int i = 0; i < numOfNodes; i++) {
final Settings nodeSettings = updatedSettings.get(i);
final Builder builder = Settings.builder();
if (Node.NODE_MASTER_SETTING.get(nodeSettings)) {
if (bootstrapMasterNodeIndex == 0) {
if (autoBootstrapMasterNodeIndex == 0) {
builder.putList(INITIAL_MASTER_NODES_SETTING.getKey(), initialMasterNodes);
}
bootstrapMasterNodeIndex -= 1;
autoBootstrapMasterNodeIndex -= 1;
}
final NodeAndClient nodeAndClient =

View File

@ -24,7 +24,6 @@ import org.elasticsearch.plugins.Plugin;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public abstract class NodeConfigurationSource {
@ -52,10 +51,6 @@ public abstract class NodeConfigurationSource {
public abstract Path nodeConfigPath(int nodeOrdinal);
public List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
return allNodesSettings;
}
/** Returns plugins that should be loaded on the node */
public Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.emptyList();

View File

@ -56,15 +56,11 @@ import java.util.Random;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.elasticsearch.cluster.coordination.ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING;
import static org.elasticsearch.cluster.node.DiscoveryNode.Role.DATA;
import static org.elasticsearch.cluster.node.DiscoveryNode.Role.INGEST;
import static org.elasticsearch.cluster.node.DiscoveryNode.Role.MASTER;
import static org.elasticsearch.discovery.DiscoveryModule.DISCOVERY_HOSTS_PROVIDER_SETTING;
import static org.elasticsearch.node.Node.NODE_MASTER_SETTING;
import static org.elasticsearch.node.Node.NODE_NAME_SETTING;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFileExists;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFileNotExists;
import static org.hamcrest.Matchers.equalTo;
@ -144,21 +140,23 @@ public class InternalTestClusterTests extends ESTestCase {
final boolean masterNodes;
final int minNumDataNodes;
final int maxNumDataNodes;
final int bootstrapMasterNodeIndex;
if (autoManageMinMasterNodes) {
masterNodes = randomBoolean();
minNumDataNodes = randomIntBetween(0, 3);
maxNumDataNodes = randomIntBetween(minNumDataNodes, 4);
bootstrapMasterNodeIndex = -1;
} else {
// if we manage min master nodes, we need to lock down the number of nodes
minNumDataNodes = randomIntBetween(0, 4);
maxNumDataNodes = minNumDataNodes;
masterNodes = false;
bootstrapMasterNodeIndex = maxNumDataNodes == 0 ? -1 : randomIntBetween(0, maxNumDataNodes - 1);
}
final int numClientNodes = randomIntBetween(0, 2);
final String clusterName1 = "shared1";
final String clusterName2 = "shared2";
String transportClient = getTestTransportType();
final long bootstrapNodeSelectionSeed = randomLong();
NodeConfigurationSource nodeConfigurationSource = new NodeConfigurationSource() {
@Override
public Settings nodeSettings(int nodeOrdinal) {
@ -176,14 +174,6 @@ public class InternalTestClusterTests extends ESTestCase {
return settings.build();
}
@Override
public List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
if (autoManageMinMasterNodes) {
return allNodesSettings;
}
return addBootstrapConfiguration(new Random(bootstrapNodeSelectionSeed), allNodesSettings);
}
@Override
public Path nodeConfigPath(int nodeOrdinal) {
return null;
@ -202,9 +192,12 @@ public class InternalTestClusterTests extends ESTestCase {
InternalTestCluster cluster0 = new InternalTestCluster(clusterSeed, baseDir, masterNodes,
autoManageMinMasterNodes, minNumDataNodes, maxNumDataNodes, clusterName1, nodeConfigurationSource, numClientNodes,
nodePrefix, mockPlugins(), Function.identity());
cluster0.setBootstrapMasterNodeIndex(bootstrapMasterNodeIndex);
InternalTestCluster cluster1 = new InternalTestCluster(clusterSeed, baseDir, masterNodes,
autoManageMinMasterNodes, minNumDataNodes, maxNumDataNodes, clusterName2, nodeConfigurationSource, numClientNodes,
nodePrefix, mockPlugins(), Function.identity());
cluster1.setBootstrapMasterNodeIndex(bootstrapMasterNodeIndex);
assertClusters(cluster0, cluster1, false);
long seed = randomLong();
@ -231,19 +224,6 @@ public class InternalTestClusterTests extends ESTestCase {
}
}
private static List<Settings> addBootstrapConfiguration(Random random, List<Settings> allNodesSettings) {
final List<Settings> updatedSettings = new ArrayList<>(allNodesSettings);
final int bootstrapIndex = randomFrom(random, IntStream.range(0, updatedSettings.size())
.filter(i -> NODE_MASTER_SETTING.get(allNodesSettings.get(i))).boxed().collect(Collectors.toList()));
final Settings settings = updatedSettings.get(bootstrapIndex);
assertFalse(INITIAL_MASTER_NODES_SETTING.exists(settings));
assertTrue(NODE_MASTER_SETTING.get(settings));
updatedSettings.set(bootstrapIndex,
Settings.builder().put(settings).putList(INITIAL_MASTER_NODES_SETTING.getKey(), allNodesSettings.stream()
.filter(NODE_MASTER_SETTING::get).map(NODE_NAME_SETTING::get).collect(Collectors.toList())).build());
return updatedSettings;
}
public void testDataFolderAssignmentAndCleaning() throws IOException, InterruptedException {
long clusterSeed = randomLong();
boolean masterNodes = randomBoolean();
@ -353,8 +333,6 @@ public class InternalTestClusterTests extends ESTestCase {
InternalTestCluster cluster = new InternalTestCluster(randomLong(), baseDir, false,
false, 0, 0, "test", new NodeConfigurationSource() {
private boolean bootstrapConfigurationSet;
@Override
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
@ -369,16 +347,6 @@ public class InternalTestClusterTests extends ESTestCase {
.build();
}
@Override
public List<Settings> addExtraClusterBootstrapSettings(List<Settings> allNodesSettings) {
if (bootstrapConfigurationSet || allNodesSettings.stream().noneMatch(NODE_MASTER_SETTING::get)) {
return allNodesSettings;
}
bootstrapConfigurationSet = true;
return addBootstrapConfiguration(random(), allNodesSettings);
}
@Override
public Path nodeConfigPath(int nodeOrdinal) {
return null;
@ -399,6 +367,8 @@ public class InternalTestClusterTests extends ESTestCase {
roles.add(role);
}
cluster.setBootstrapMasterNodeIndex(randomIntBetween(0, (int) roles.stream().filter(role -> role.equals(MASTER)).count() - 1));
try {
Map<DiscoveryNode.Role, Set<String>> pathsPerRole = new HashMap<>();
for (int i = 0; i < numNodes; i++) {