[SCB-2285]find publish address may get wrong docker address (#2428)
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java
index 0ec4c2d..90d6301 100644
--- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java
@@ -29,10 +29,13 @@
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.annotations.VisibleForTesting;
+
public final class NetUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(NetUtils.class);
@@ -41,6 +44,8 @@
private static final String IPV6_KEY = "_v6";
+ private static final String PREFERRED_INTERFACE = "eth";
+
// one interface can bind to multiple address
// we only save one ip for each interface name.
// eg:
@@ -70,27 +75,23 @@
// getLocalHost will throw exception in some docker image and sometimes will do a hostname lookup and time consuming
InetAddress localHost = InetAddress.getLocalHost();
hostName = localHost.getHostName();
- if ((localHost.isAnyLocalAddress() || localHost.isLoopbackAddress() || localHost.isMulticastAddress())
- && !allInterfaceAddresses.isEmpty()) {
- allInterfaceAddresses.forEach((key, val) -> {
- if (key.endsWith(IPV4_KEY)) {
- hostAddress = val.getHostAddress();
- LOGGER.warn("cannot find a proper ipv4 host address, choose {} , may not be correct.", hostAddress);
- } else {
- hostAddressIpv6 = val.getHostAddress();
- int index = hostAddressIpv6.indexOf("%");
- if (index > 0) {
- hostAddressIpv6 = hostAddressIpv6.substring(0, index);
- }
- LOGGER.warn("cannot find a proper ipv6 host address, choose {} , may not be correct.", hostAddressIpv6);
- }
- });
- } else {
- LOGGER.info("get localhost address: {}", localHost.getHostAddress());
- hostAddress = localHost.getHostAddress();
- }
+ LOGGER.info("localhost hostName={}, hostAddress={}.", hostName, localHost.getHostAddress());
- LOGGER.info("add host name from localhost:" + hostName + ",host address:" + hostAddress);
+ if (!isLocalAddress(localHost)) {
+ if (Inet6Address.class.isInstance(localHost)) {
+ hostAddressIpv6 = trimIpv6(localHost.getHostAddress());
+ hostAddress = tryGetHostAddressFromNetworkInterface(false, localHost);
+ LOGGER.info("Host address info ipV4={}, ipV6={}.", hostAddress, hostAddressIpv6);
+ return;
+ }
+ hostAddress = localHost.getHostAddress();
+ hostAddressIpv6 = trimIpv6(tryGetHostAddressFromNetworkInterface(true, localHost));
+ LOGGER.info("Host address info ipV4={}, ipV6={}.", hostAddress, hostAddressIpv6);
+ return;
+ }
+ hostAddressIpv6 = trimIpv6(tryGetHostAddressFromNetworkInterface(true, localHost));
+ hostAddress = tryGetHostAddressFromNetworkInterface(false, localHost);
+ LOGGER.info("Host address info ipV4={}, ipV6={}.", hostAddress, hostAddressIpv6);
} catch (Exception e) {
LOGGER.error("got exception when trying to get addresses:", e);
if (allInterfaceAddresses.size() >= 1) {
@@ -103,6 +104,29 @@
}
}
+ private static String tryGetHostAddressFromNetworkInterface(boolean isIpv6, InetAddress localhost) {
+ InetAddress result = null;
+ for (Entry<String, InetAddress> entry : allInterfaceAddresses.entrySet()) {
+ if (isIpv6 && entry.getKey().endsWith(IPV6_KEY)) {
+ result = entry.getValue();
+ if (entry.getKey().startsWith(PREFERRED_INTERFACE)) {
+ return result.getHostAddress();
+ }
+ } else if (!isIpv6 && entry.getKey().endsWith(IPV4_KEY)) {
+ result = entry.getValue();
+ if (entry.getKey().startsWith(PREFERRED_INTERFACE)) {
+ return result.getHostAddress();
+ }
+ }
+ }
+
+ if (result == null) {
+ return localhost.getHostAddress();
+ }
+
+ return result.getHostAddress();
+ }
+
private NetUtils() {
}
@@ -111,36 +135,46 @@
* 此时,通过遍历网卡接口的方式规避,出来的数据不一定对
*/
private static void doGetAddressFromNetworkInterface() throws SocketException {
- Enumeration<NetworkInterface> iterNetwork = NetworkInterface.getNetworkInterfaces();
+ Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
- while (iterNetwork.hasMoreElements()) {
- NetworkInterface network = iterNetwork.nextElement();
+ while (networkInterfaces.hasMoreElements()) {
+ NetworkInterface network = networkInterfaces.nextElement();
if (!network.isUp() || network.isLoopback() || network.isVirtual()) {
continue;
}
- Enumeration<InetAddress> iterAddress = network.getInetAddresses();
- while (iterAddress.hasMoreElements()) {
- InetAddress address = iterAddress.nextElement();
+ Enumeration<InetAddress> addresses = network.getInetAddresses();
+ while (addresses.hasMoreElements()) {
+ InetAddress address = addresses.nextElement();
- if (address.isAnyLocalAddress() || address.isLoopbackAddress() || address.isMulticastAddress()) {
+ if (isLocalAddress(address)) {
continue;
}
- if (Inet4Address.class.isInstance(address)) {
- LOGGER.info(
- "add network interface name:" + network.getName() + ",ipv4 host address:" + address.getHostAddress());
+ if (address instanceof Inet4Address) {
+ LOGGER.info("add ipv4 network interface:" + network.getName() + ",host address:" + address.getHostAddress());
allInterfaceAddresses.put(network.getName() + IPV4_KEY, address);
- } else if (Inet6Address.class.isInstance(address)) {
- LOGGER.info(
- "add network interface name:" + network.getName() + ",ipv6 host address:" + address.getHostAddress());
+ } else if (address instanceof Inet6Address) {
+ LOGGER.info("add ipv6 network interface:" + network.getName() + ",host address:" + address.getHostAddress());
allInterfaceAddresses.put(network.getName() + IPV6_KEY, address);
}
}
}
}
+ private static String trimIpv6(String hostAddress) {
+ int index = hostAddress.indexOf("%");
+ if (index >= 0) {
+ return hostAddress.substring(0, index);
+ }
+ return hostAddress;
+ }
+
+ private static boolean isLocalAddress(InetAddress address) {
+ return address.isAnyLocalAddress() || address.isLoopbackAddress() || address.isMulticastAddress();
+ }
+
/**
* The format of address should be {@code IPv4:port} or {@code [IPv6]:port}, or {@code host:port},
* or you will not get expected result.
@@ -237,11 +271,9 @@
}
try {
URI originalURI = new URI(schema + "://" + address);
- IpPort ipPort = NetUtils.parseIpPort(originalURI);
- if (ipPort == null) {
- LOGGER.error("address {} is not valid.", address);
- return null;
- }
+ // validate original url
+ NetUtils.parseIpPort(originalURI);
+
return originalURI.toString();
} catch (URISyntaxException e) {
LOGGER.error("address {} is not valid.", address);
@@ -258,6 +290,11 @@
return hostName;
}
+ @VisibleForTesting
+ static void resetHostName() {
+ hostName = null;
+ }
+
public static String getHostAddress() {
//If failed to get host address ,micro-service will registry failed
//So I add retry mechanism
@@ -303,7 +340,7 @@
return String.valueOf(bytes);
}
int exp = (int) (Math.log(bytes) / Math.log(unit));
- char pre = "KMGTPE".charAt(exp - 1);
+ char pre = "KMGTPE" .charAt(exp - 1);
return String.format("%.3f%c", bytes / Math.pow(unit, exp), pre);
}
}
diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java
index a363747..90bce85 100644
--- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java
+++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java
@@ -34,6 +34,24 @@
public class TestNetUtils {
@Test
+ public void testFindProperHostAddress() {
+ NetUtils.resetHostName();
+ String result = NetUtils.getHostName();
+ System.out.println(result);
+ Assert.assertNotNull(result);
+
+ result = NetUtils.getHostAddress();
+ System.out.println(result);
+ Assert.assertNotNull(result);
+
+ result = NetUtils.getIpv6HostAddress();
+ System.out.println(result);
+ if (result != null) {
+ Assert.assertFalse(result.contains("%"));
+ }
+ }
+
+ @Test
public void testIpPort() {
IpPort oIPPort = new IpPort("10.145.154.45", 8080);
Assert.assertEquals("10.145.154.45", oIPPort.getHostOrIp());