Allow configurable ignoring of network interfaces.
fixes gh-67
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package org.springframework.cloud;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.util.InetUtils;
|
||||
import org.springframework.cloud.util.InetUtilsProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.cloud.util.enabled", matchIfMissing = true)
|
||||
@AutoConfigureOrder(0)
|
||||
@EnableConfigurationProperties
|
||||
public class UtilAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public InetUtilsProperties inetUtilsProperties() {
|
||||
return new InetUtilsProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public InetUtils inetUtils(InetUtilsProperties properties) {
|
||||
return new InetUtils(properties);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,103 @@ import lombok.extern.apachecommons.CommonsLog;
|
||||
@CommonsLog
|
||||
public class InetUtils {
|
||||
|
||||
private final ExecutorService executorService;
|
||||
private final InetUtilsProperties properties;
|
||||
|
||||
public InetUtils(final InetUtilsProperties properties) {
|
||||
this.properties = properties;
|
||||
this.executorService = Executors
|
||||
.newSingleThreadExecutor(new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread thread = new Thread(r);
|
||||
thread.setName(properties.getExecutorThreadName());
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public HostInfo findFirstNonLoopbackHostInfo() {
|
||||
InetAddress address = findFirstNonLoopbackAddress();
|
||||
if (address != null) {
|
||||
return convertAddress(address);
|
||||
}
|
||||
HostInfo hostInfo = new HostInfo();
|
||||
hostInfo.setHostname(this.properties.getDefaultHostname());
|
||||
hostInfo.setIpAddress(this.properties.getDefaultIpAddress());
|
||||
return hostInfo;
|
||||
}
|
||||
|
||||
public InetAddress findFirstNonLoopbackAddress() {
|
||||
try {
|
||||
for (Enumeration<NetworkInterface> nics = NetworkInterface
|
||||
.getNetworkInterfaces(); nics.hasMoreElements();) {
|
||||
NetworkInterface ifc = nics.nextElement();
|
||||
if (ifc.isUp()) {
|
||||
log.debug("Testing interface: " + ifc.getDisplayName());
|
||||
|
||||
// @formatter:off
|
||||
if (!ignoreInterface(ifc.getDisplayName())) {
|
||||
for (Enumeration<InetAddress> addrs = ifc .getInetAddresses(); addrs.hasMoreElements(); ) {
|
||||
InetAddress address = addrs.nextElement();
|
||||
if (address instanceof Inet4Address && !address.isLoopbackAddress()) {
|
||||
log.debug("Found non-loopback interface: " + ifc.getDisplayName());
|
||||
return address;
|
||||
}
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
log.error("Cannot get first non-loopback address", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
return InetAddress.getLocalHost();
|
||||
}
|
||||
catch (UnknownHostException e) {
|
||||
log.warn("Unable to retrieve localhost");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean ignoreInterface(String interfaceName) {
|
||||
for (String regex : this.properties.getIgnoredInterfaces()) {
|
||||
if (interfaceName.matches(regex)) {
|
||||
log.debug("Ignoring interface: " + interfaceName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public HostInfo convertAddress(final InetAddress address) {
|
||||
HostInfo hostInfo = new HostInfo();
|
||||
Future<String> result = this.executorService.submit(new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return address.getHostName();
|
||||
}
|
||||
});
|
||||
|
||||
String hostname;
|
||||
try {
|
||||
hostname = result.get(this.properties.getTimeoutSeconds(), TimeUnit.SECONDS);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.info("Cannot determine local hostname");
|
||||
hostname = "localhost";
|
||||
}
|
||||
hostInfo.setHostname(hostname);
|
||||
hostInfo.setIpAddress(address.getHostAddress());
|
||||
return hostInfo;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private static ExecutorService executor = Executors
|
||||
.newSingleThreadExecutor(new ThreadFactory() {
|
||||
@Override
|
||||
@@ -41,6 +138,7 @@ public class InetUtils {
|
||||
* Find the first non-loopback host info. If there were errors return a hostinfo with
|
||||
* 'localhost' and '127.0.0.1' for hostname and ipAddress respectively.
|
||||
*/
|
||||
@Deprecated
|
||||
public static HostInfo getFirstNonLoopbackHostInfo() {
|
||||
InetAddress address = getFirstNonLoopbackAddress();
|
||||
if (address != null) {
|
||||
@@ -56,6 +154,7 @@ public class InetUtils {
|
||||
* Find the first non-loopback InetAddress
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Deprecated
|
||||
public static InetAddress getFirstNonLoopbackAddress() {
|
||||
try {
|
||||
for (Enumeration<NetworkInterface> enumNic = NetworkInterface
|
||||
@@ -90,6 +189,7 @@ public class InetUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static HostInfo convert(final InetAddress address) {
|
||||
HostInfo hostInfo = new HostInfo();
|
||||
Future<String> result = executor.submit(new Callable<String>() {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.springframework.cloud.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(InetUtilsProperties.PREFIX)
|
||||
public class InetUtilsProperties {
|
||||
public static final String PREFIX = "spring.cloud.inetutils";
|
||||
|
||||
/**
|
||||
* Name of InetUtils executor thread
|
||||
*/
|
||||
private String executorThreadName = PREFIX;
|
||||
|
||||
/**
|
||||
* The default hostname. Used in case of errors.
|
||||
*/
|
||||
private String defaultHostname = "localhost";
|
||||
|
||||
/**
|
||||
* The default ipaddress. Used in case of errors.
|
||||
*/
|
||||
private String defaultIpAddress = "127.0.0.1";
|
||||
|
||||
/**
|
||||
* Timeout in seconds for calculating hostname.
|
||||
*/
|
||||
@Value("${spring.util.timeout.sec:${SPRING_UTIL_TIMEOUT_SEC:1}}")
|
||||
private int timeoutSeconds = 1;
|
||||
|
||||
/**
|
||||
* List of Java regex expressions for network interfaces that will be ignored.
|
||||
*/
|
||||
private List<String> ignoredInterfaces = new ArrayList<>();
|
||||
}
|
||||
@@ -16,13 +16,16 @@
|
||||
|
||||
package org.springframework.cloud.util;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.util.InetUtils.HostInfo;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
@@ -31,23 +34,51 @@ public class InetUtilsTests {
|
||||
|
||||
@Test
|
||||
public void testGetFirstNonLoopbackHostInfo() {
|
||||
assertNotNull(new InetUtils(new InetUtilsProperties())
|
||||
.findFirstNonLoopbackHostInfo());
|
||||
assertNotNull(InetUtils.getFirstNonLoopbackHostInfo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFirstNonLoopbackAddress() {
|
||||
assertNotNull(new InetUtils(new InetUtilsProperties())
|
||||
.findFirstNonLoopbackAddress());
|
||||
assertNotNull(InetUtils.getFirstNonLoopbackAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvert() throws Exception {
|
||||
assertNotNull(new InetUtils(new InetUtilsProperties()).convertAddress(InetAddress
|
||||
.getByName("localhost")));
|
||||
assertNotNull(InetUtils.convert(InetAddress.getByName("localhost")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostInfo() throws Exception {
|
||||
HostInfo info = InetUtils.getFirstNonLoopbackHostInfo();
|
||||
HostInfo info = new InetUtils(new InetUtilsProperties())
|
||||
.findFirstNonLoopbackHostInfo();
|
||||
assertNotNull(info.getIpAddressAsInt());
|
||||
|
||||
info = InetUtils.getFirstNonLoopbackHostInfo();
|
||||
assertNotNull(info.getIpAddressAsInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreInterface() {
|
||||
InetUtilsProperties properties = new InetUtilsProperties();
|
||||
// These interfaces are not usable for "outside" communication, so they're
|
||||
// probably not a good fit for the simple strategy of getting the first "usable"
|
||||
// interface.
|
||||
// https://docs.docker.com/v1.7/articles/networking/
|
||||
properties.setIgnoredInterfaces(Arrays.asList("docker0", "veth.*"));
|
||||
InetUtils inetUtils = new InetUtils(properties);
|
||||
|
||||
assertTrue("docker0 not ignored", inetUtils.ignoreInterface("docker0"));
|
||||
assertTrue("vethAQI2QT0 not ignored", inetUtils.ignoreInterface("vethAQI2QT"));
|
||||
assertFalse("docker1 ignored", inetUtils.ignoreInterface("docker1"));
|
||||
|
||||
assertFalse("docker0 ignored",
|
||||
new InetUtils(new InetUtilsProperties()).ignoreInterface("docker0"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user