Add host address to BindTransportException message ()

When bind fails, show the host address in addition to the port. This
helps debugging cases with wrong "network.host" values.

Closes 
This commit is contained in:
Maria Ralli 2020-02-04 10:48:13 +02:00 committed by David Turner
parent 337153b29f
commit 8d3e73b3a0
8 changed files with 108 additions and 14 deletions
buildSrc/src/main/resources/forbidden
modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4
plugins/transport-nio/src/test/java/org/elasticsearch/http/nio
server/src
main/java/org/elasticsearch
test/java/org/elasticsearch/common/network
test/framework/src/main/java/org/elasticsearch/transport

@ -59,7 +59,7 @@ java.net.MulticastSocket#<init>(int)
java.net.ServerSocket#<init>(int)
java.net.ServerSocket#<init>(int,int)
@defaultMessage use NetworkAddress format/formatAddress to print IP or IP+ports
@defaultMessage use NetworkAddress format() to print IP or IP+ports
java.net.InetAddress#toString()
java.net.InetAddress#getHostAddress()
java.net.Inet4Address#getHostAddress()

@ -41,6 +41,7 @@ import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
@ -195,11 +196,17 @@ public class Netty4HttpServerTransportTests extends ESTestCase {
xContentRegistry(), new NullDispatcher())) {
transport.start();
TransportAddress remoteAddress = randomFrom(transport.boundAddress().boundAddresses());
Settings settings = Settings.builder().put("http.port", remoteAddress.getPort()).build();
Settings settings = Settings.builder()
.put("http.port", remoteAddress.getPort())
.put("network.host", remoteAddress.getAddress())
.build();
try (Netty4HttpServerTransport otherTransport = new Netty4HttpServerTransport(settings, networkService, bigArrays, threadPool,
xContentRegistry(), new NullDispatcher())) {
BindHttpException bindHttpException = expectThrows(BindHttpException.class, otherTransport::start);
assertEquals("Failed to bind to [" + remoteAddress.getPort() + "]", bindHttpException.getMessage());
assertEquals(
"Failed to bind to " + NetworkAddress.format(remoteAddress.address()),
bindHttpException.getMessage()
);
}
}
}

@ -33,6 +33,7 @@ import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
@ -190,11 +191,17 @@ public class NioHttpServerTransportTests extends ESTestCase {
threadPool, xContentRegistry(), new NullDispatcher(), new NioGroupFactory(Settings.EMPTY, logger))) {
transport.start();
TransportAddress remoteAddress = randomFrom(transport.boundAddress().boundAddresses());
Settings settings = Settings.builder().put("http.port", remoteAddress.getPort()).build();
Settings settings = Settings.builder()
.put("http.port", remoteAddress.getPort())
.put("network.host", remoteAddress.getAddress())
.build();
try (NioHttpServerTransport otherTransport = new NioHttpServerTransport(settings, networkService, bigArrays, pageRecycler,
threadPool, xContentRegistry(), new NullDispatcher(), new NioGroupFactory(Settings.EMPTY, logger))) {
BindHttpException bindHttpException = expectThrows(BindHttpException.class, () -> otherTransport.start());
assertEquals("Failed to bind to [" + remoteAddress.getPort() + "]", bindHttpException.getMessage());
assertEquals(
"Failed to bind to " + NetworkAddress.format(remoteAddress.address()),
bindHttpException.getMessage()
);
}
}
}

@ -19,6 +19,8 @@
package org.elasticsearch.common.network;
import org.elasticsearch.common.transport.PortsRange;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@ -66,7 +68,7 @@ public final class NetworkAddress {
* @return formatted string
*/
public static String format(InetAddress address) {
return format(address, -1);
return format(address, new PortsRange(""));
}
/**
@ -88,21 +90,64 @@ public final class NetworkAddress {
return format(address.getAddress(), address.getPort());
}
// note, we don't validate port, because we only allow InetSocketAddress
static String format(InetAddress address, int port) {
/**
* Formats a network address and port for display purposes.
* <p>
* This formats the address with {@link #format(InetAddress)}
* and appends the port number. IPv6 addresses will be bracketed.
* Any host information, if present is ignored.
* <p>
* Example output:
* <ul>
* <li>IPv4: {@code 127.0.0.1:9300}</li>
* <li>IPv6: {@code [::1]:9300}</li>
* </ul>
* @param address IPv4 or IPv6 address
* @param port port
* @return formatted string
*/
public static String format(InetAddress address, int port) {
return format(address, new PortsRange(String.valueOf(port)));
}
/**
* Formats a network address and port range for display purposes.
* <p>
* This formats the address with {@link #format(InetAddress)}
* and appends the port range in brackets. In case there is only one
* port, the result is the same with {@link #format(InetAddress, int)}.
* <p>
* Example output:
* <ul>
* <li>IPv4 no port: {@code 127.0.0.1}</li>
* <li>IPv4 single port: {@code 127.0.0.1:9300}</li>
* <li>IPv4 multiple ports: {@code 127.0.0.1:[9300-9400]}</li>
* <li>IPv6 multiple ports: {@code [::1]:[9300-9400]}</li>
* </ul>
* @param address IPv4 or IPv6 address
* @param portsRange range of ports
* @return formatted string
*/
public static String format(InetAddress address, PortsRange portsRange) {
Objects.requireNonNull(address);
StringBuilder builder = new StringBuilder();
if (port != -1 && address instanceof Inet6Address) {
int numberOfPorts = portsRange.ports().length;
if (numberOfPorts != 0 && address instanceof Inet6Address) {
builder.append(InetAddresses.toUriString(address));
} else {
builder.append(InetAddresses.toAddrString(address));
}
if (port != -1) {
if (numberOfPorts != 0) {
builder.append(':');
builder.append(port);
if (numberOfPorts == 1) {
builder.append(portsRange.getPortRangeString());
} else {
builder.append("[").append(portsRange.getPortRangeString()).append("]");
}
}
return builder.toString();

@ -174,7 +174,10 @@ public abstract class AbstractHttpServerTransport extends AbstractLifecycleCompo
return true;
});
if (!success) {
throw new BindHttpException("Failed to bind to [" + port.getPortRangeString() + "]", lastException.get());
throw new BindHttpException(
"Failed to bind to " + NetworkAddress.format(hostAddress, port),
lastException.get()
);
}
if (logger.isDebugEnabled()) {

@ -387,7 +387,10 @@ public abstract class TcpTransport extends AbstractLifecycleComponent implements
return true;
});
if (!success) {
throw new BindTransportException("Failed to bind to [" + port + "]", lastException.get());
throw new BindTransportException(
"Failed to bind to " + NetworkAddress.format(hostAddress, portsRange),
lastException.get()
);
}
} finally {
closeLock.writeLock().unlock();

@ -19,6 +19,7 @@
package org.elasticsearch.common.network;
import org.elasticsearch.common.transport.PortsRange;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
@ -52,12 +53,36 @@ public class NetworkAddressTests extends ESTestCase {
assertEquals("[::1]:1234", NetworkAddress.format(new InetSocketAddress(forge(null, "::1"), 1234)));
}
public void testFormatPortsRangeV4() throws Exception {
assertEquals("127.0.0.1", NetworkAddress.format(forge("localhost", "127.0.0.1"), new PortsRange("")));
assertEquals("127.0.0.1", NetworkAddress.format(forge(null, "127.0.0.1"), new PortsRange("")));
assertEquals("127.0.0.1:9300", NetworkAddress.format(forge("localhost", "127.0.0.1"), new PortsRange("9300")));
assertEquals("127.0.0.1:9300", NetworkAddress.format(forge(null, "127.0.0.1"), new PortsRange("9300")));
assertEquals("127.0.0.1:[9300-9400]", NetworkAddress.format(forge("localhost", "127.0.0.1"), new PortsRange("9300-9400")));
assertEquals("127.0.0.1:[9300-9400]", NetworkAddress.format(forge(null, "127.0.0.1"), new PortsRange("9300-9400")));
}
public void testFormatPortsRangeV6() throws Exception {
assertEquals("::1", NetworkAddress.format(forge("localhost", "::1"), new PortsRange("")));
assertEquals("::1", NetworkAddress.format(forge(null, "::1"), new PortsRange("")));
assertEquals("[::1]:9300", NetworkAddress.format(forge("localhost", "::1"), new PortsRange("9300")));
assertEquals("[::1]:9300", NetworkAddress.format(forge(null, "::1"), new PortsRange("9300")));
assertEquals("[::1]:[9300-9400]", NetworkAddress.format(forge("localhost", "::1"), new PortsRange("9300-9400")));
assertEquals("[::1]:[9300-9400]", NetworkAddress.format(forge(null, "::1"), new PortsRange("9300-9400")));
}
public void testNoScopeID() throws Exception {
assertEquals("::1", NetworkAddress.format(forgeScoped(null, "::1", 5)));
assertEquals("::1", NetworkAddress.format(forgeScoped("localhost", "::1", 5)));
assertEquals("::1", NetworkAddress.format(forgeScoped("localhost", "::1", 5), new PortsRange("")));
assertEquals("[::1]:1234", NetworkAddress.format(new InetSocketAddress(forgeScoped(null, "::1", 5), 1234)));
assertEquals("[::1]:1234", NetworkAddress.format(new InetSocketAddress(forgeScoped("localhost", "::1", 5), 1234)));
assertEquals("[::1]:[9300-9400]", NetworkAddress.format(forgeScoped("localhost", "::1", 5), new PortsRange("9300-9400")));
}
/** Test that ipv4 address formatting round trips */

@ -38,6 +38,7 @@ import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.network.CloseableChannel;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.network.NetworkUtils;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Setting;
@ -2701,13 +2702,16 @@ public abstract class AbstractSimpleTransportTestCase extends ESTestCase {
public void testBindUnavailableAddress() {
int port = serviceA.boundAddress().publishAddress().getPort();
String address = serviceA.boundAddress().publishAddress().getAddress();
Settings settings = Settings.builder()
.put(Node.NODE_NAME_SETTING.getKey(), "foobar")
.put(TransportSettings.HOST.getKey(), address)
.put(TransportSettings.PORT.getKey(), port)
.build();
BindTransportException bindTransportException = expectThrows(BindTransportException.class,
() -> buildService("test", Version.CURRENT, settings));
assertEquals("Failed to bind to ["+ port + "]", bindTransportException.getMessage());
InetSocketAddress inetSocketAddress = serviceA.boundAddress().publishAddress().address();
assertEquals("Failed to bind to " + NetworkAddress.format(inetSocketAddress), bindTransportException.getMessage());
}
public void testChannelCloseWhileConnecting() {