[test] check node ports to see if they are already bound

A large number of recent test failures have been caused by failure to bind
a port in the range 32900 to 32999. The ports are now tested to see if they
can be bound by this JVM and if not tries to bind another port. This will
decrease the likelihood of a port bind failure but another application could
still bind a port before the node starts up.

Closes elastic/elasticsearch#737

Original commit: elastic/x-pack-elasticsearch@aaf098758f
This commit is contained in:
jaymode 2015-02-25 10:58:17 -05:00
parent 121a20ca87
commit 82beae9c0c
1 changed files with 41 additions and 8 deletions

View File

@ -7,6 +7,7 @@ package org.elasticsearch.test.discovery;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import com.google.common.primitives.Ints;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
@ -15,6 +16,8 @@ import org.elasticsearch.test.InternalTestCluster;
import org.elasticsearch.test.SettingsSource;
import org.elasticsearch.transport.local.LocalTransport;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@ -55,7 +58,8 @@ public class ClusterDiscoveryConfiguration extends SettingsSource {
private static final AtomicInteger portCounter = new AtomicInteger();
private final int[] unicastHostOrdinals;
private final int basePort;
private final int[] unicastHostPorts;
private final boolean localMode;
public UnicastZen(int numOfNodes, ElasticsearchIntegrationTest.Scope scope) {
this(numOfNodes, numOfNodes, scope);
@ -83,7 +87,9 @@ public class ClusterDiscoveryConfiguration extends SettingsSource {
}
unicastHostOrdinals = Ints.toArray(ordinals);
}
this.basePort = calcBasePort(scope);
this.localMode = nodeSettings.get("node.mode", InternalTestCluster.NODE_MODE).equals("local");
this.unicastHostPorts = localMode ? new int[0] : unicastHostPorts(calcBasePort(scope), numOfNodes);
assert unicastHostOrdinals.length <= unicastHostPorts.length;
}
public UnicastZen(int numOfNodes, int[] unicastHostOrdinals, ElasticsearchIntegrationTest.Scope scope) {
@ -93,7 +99,9 @@ public class ClusterDiscoveryConfiguration extends SettingsSource {
public UnicastZen(int numOfNodes, Settings extraSettings, int[] unicastHostOrdinals, ElasticsearchIntegrationTest.Scope scope) {
super(numOfNodes, extraSettings);
this.unicastHostOrdinals = unicastHostOrdinals;
this.basePort = calcBasePort(scope);
this.localMode = nodeSettings.get("node.mode", InternalTestCluster.NODE_MODE).equals("local");
this.unicastHostPorts = localMode ? new int[0] : unicastHostPorts(calcBasePort(scope), numOfNodes);
assert unicastHostOrdinals.length <= unicastHostPorts.length;
}
private static int calcBasePort(ElasticsearchIntegrationTest.Scope scope) {
@ -124,22 +132,47 @@ public class ClusterDiscoveryConfiguration extends SettingsSource {
.put("discovery.zen.ping.multicast.enabled", false);
String[] unicastHosts = new String[unicastHostOrdinals.length];
String mode = nodeSettings.get("node.mode", InternalTestCluster.NODE_MODE);
if (mode.equals("local")) {
if (localMode) {
builder.put(LocalTransport.TRANSPORT_LOCAL_ADDRESS, "node_" + nodeOrdinal);
for (int i = 0; i < unicastHosts.length; i++) {
unicastHosts[i] = "node_" + unicastHostOrdinals[i];
}
} else {
// we need to pin the node port & host so we'd know where to point things
builder.put("transport.tcp.port", basePort + nodeOrdinal);
builder.put("transport.tcp.port", unicastHostPorts[nodeOrdinal]);
builder.put("transport.host", "localhost");
for (int i = 0; i < unicastHosts.length; i++) {
unicastHosts[i] = "localhost:" + (basePort + unicastHostOrdinals[i]);
for (int i = 0; i < unicastHostOrdinals.length; i++) {
unicastHosts[i] = "localhost:" + (unicastHostPorts[unicastHostOrdinals[i]]);
}
}
builder.putArray("discovery.zen.ping.unicast.hosts", unicastHosts);
return builder.put(super.node(nodeOrdinal)).build();
}
protected static int[] unicastHostPorts(int basePort, int numHosts) {
int[] unicastHostPorts = new int[numHosts];
final int maxPort = basePort + 99;
int currentPort = basePort;
for (int i = 0; i < unicastHostPorts.length; i++) {
boolean foundPortInRange = false;
while (currentPort <= maxPort && !foundPortInRange) {
try (ServerSocket socket = new ServerSocket(currentPort)) {
// bind was a success
foundPortInRange = true;
unicastHostPorts[i] = currentPort;
} catch (IOException e) {
// Do nothing
}
currentPort++;
}
if (!foundPortInRange) {
throw new ElasticsearchException("could not find enough open ports in range [" + basePort + "-" + maxPort + "]");
}
}
return unicastHostPorts;
}
}
}