Add host address to BindTransportException message (#51269)

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

Closes #48001
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

View File

@ -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()

View File

@ -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()
);
}
}
}

View File

@ -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()
);
}
}
}

View File

@ -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();

View File

@ -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()) {

View File

@ -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();

View File

@ -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 */

View File

@ -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() {