Commit 7fe777db by Johannes Stelzer

Add spring.boot.admin.client.preferIp

In conjuntion with server.address / management.address this plays more nicely with interfaces with multiple ipAdrresses. Also remove spring.boot.admin.client.useAddressOf. fixes #112
parent 8bed0d18
......@@ -21,7 +21,7 @@ The main service that is used is a registrar that registeres the application at
| spring.boot.admin.client.managementUrl | Client-management-URL to register with. Can be overriden in case the reachable URL is different (e.g. Docker). Must be unique in registry.<br>Default: is guessed based on serviceUrl management.port and management.context-path|
| spring.boot.admin.client.healthUrl | Client-management-URL to register with. Can be overriden in case the reachable URL is different (e.g. Docker). Must be unique in registry.<br>Default: is guessed based on managementUrl and endpoints.health.id |
| spring.boot.admin.client.name | Name to register with. Defaults to the ApplicationContexts name. Only set when it should differ.<br>Default: _${spring.application.name}_ if set, spring-boot-application otherwise. |
| spring.boot.admin.client.useIpAddressOf | If an network-interface name is specified, its ip-address wil be used for the guessed url (instead of hostname).|
| spring.boot.admin.client.preferIpAddress | Use the ip-address rather then the hostname in the guessed urls. It's required to set `server.address` and `management.address`respectively. |
### Other configuration properties
Options from other spring boot features. These should be set to enable all features.
......
......@@ -16,9 +16,6 @@
package de.codecentric.boot.admin.config;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -34,27 +31,27 @@ import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@ConfigurationProperties(prefix = "spring.boot.admin.client", ignoreUnknownFields = false)
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class AdminClientProperties implements ApplicationListener<ApplicationEvent> {
/**
* Client-management-URL to register with. Inferred at runtime, can be overriden in
* case the reachable URL is different (e.g. Docker).
* Client-management-URL to register with. Inferred at runtime, can be overriden in case the
* reachable URL is different (e.g. Docker).
*/
private String managementUrl;
/**
* Client-service-URL register with. Inferred at runtime, can be overriden in case the
* reachable URL is different (e.g. Docker).
* Client-service-URL register with. Inferred at runtime, can be overriden in case the reachable
* URL is different (e.g. Docker).
*/
private String serviceUrl;
/**
* Client-health-URL to register with. Inferred at runtime, can be overriden in case
* the reachable URL is different (e.g. Docker). Must be unique in registry.
* Client-health-URL to register with. Inferred at runtime, can be overriden in case the
* reachable URL is different (e.g. Docker). Must be unique in registry.
*/
private String healthUrl;
......@@ -68,10 +65,9 @@ public class AdminClientProperties implements ApplicationListener<ApplicationEve
private String healthEndpointId;
/**
* If set, the address of the specified interface is used in url inference
* instead of the hostname.
* Should the registered urls be built with server.address or with hostname.
*/
private String useIpAddressOf = null;
private boolean preferIp = false;
@Autowired
private ManagementServerProperties management;
......@@ -117,17 +113,21 @@ public class AdminClientProperties implements ApplicationListener<ApplicationEve
}
public String getManagementUrl() {
if (managementUrl == null) {
if (managementPort != -1) {
return createLocalUri(managementPort,
management.getContextPath());
if (managementUrl != null) {
return managementUrl;
}
else {
if (managementPort == -1) {
return append(getServiceUrl(), management.getContextPath());
}
}
return managementUrl;
if (preferIp) {
Assert.notNull(management.getAddress(),
"management.address must be set when using preferIp");
return append(createLocalUri(management.getAddress().getHostAddress(), managementPort),
management.getContextPath());
}
return append(createLocalUri(getHostname(), managementPort), management.getContextPath());
}
public void setManagementUrl(String managementUrl) {
......@@ -135,27 +135,33 @@ public class AdminClientProperties implements ApplicationListener<ApplicationEve
}
public String getHealthUrl() {
if (healthUrl == null) {
return append(getManagementUrl(), healthEndpointId);
}
if (healthUrl != null) {
return healthUrl;
}
return append(getManagementUrl(), healthEndpointId);
}
public void setHealthUrl(String healthUrl) {
this.healthUrl = healthUrl;
}
public String getServiceUrl() {
if (serviceUrl == null) {
if (serverPort != -1){
return createLocalUri(serverPort, server.getContextPath());
} else {
if (serviceUrl != null) {
return serviceUrl;
}
if (serverPort == -1) {
throw new IllegalStateException(
"EmbeddedServletContainer has not been initialized yet!");
}
}
return serviceUrl;
if (preferIp) {
Assert.notNull(server.getAddress(), "server.address must be set when using preferIp");
return append(createLocalUri(server.getAddress().getHostAddress(), serverPort),
server.getContextPath());
}
return append(createLocalUri(getHostname(), serverPort), server.getContextPath());
}
public void setServiceUrl(String serviceUrl) {
......@@ -174,14 +180,13 @@ public class AdminClientProperties implements ApplicationListener<ApplicationEve
this.name = name;
}
public void setUseIpAddressOf(String useIpAddressOf) {
this.useIpAddressOf = useIpAddressOf;
public void setPreferIp(boolean preferIp) {
this.preferIp = preferIp;
}
private String createLocalUri(int port, String path) {
String scheme = server.getSsl() != null && server.getSsl().isEnabled() ? "https"
: "http";
return append(scheme + "://" + getHost() + ":" + port, path);
private String createLocalUri(String host, int port) {
String scheme = server.getSsl() != null && server.getSsl().isEnabled() ? "https" : "http";
return scheme + "://" + host + ":" + port;
}
private String append(String uri, String path) {
......@@ -194,15 +199,6 @@ public class AdminClientProperties implements ApplicationListener<ApplicationEve
return baseUri + "/" + normPath;
}
private String getHost() {
if (useIpAddressOf == null) {
return getHostname();
} else {
return getHostIp();
}
}
private String getHostname() {
try {
return InetAddress.getLocalHost().getCanonicalHostName();
......@@ -211,47 +207,4 @@ public class AdminClientProperties implements ApplicationListener<ApplicationEve
}
}
private String getHostIp() {
NetworkInterface nic;
try {
nic = NetworkInterface.getByName(useIpAddressOf);
} catch (SocketException ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
if (nic != null) {
InetAddress address = findIp(nic);
if (address != null) {
return address.getHostAddress();
}
throw new IllegalStateException(
"Couldn't determin InetAdress for network interface '"
+ useIpAddressOf + "'");
} else {
throw new IllegalArgumentException(
"Network interface"
+ useIpAddressOf
+ " not found! Please specify correct interface for spring.boot.admin.client.useIpAddressOf");
}
}
private InetAddress findIp(NetworkInterface nic) {
InetAddress candidate = null;
for (InterfaceAddress address : nic.getInterfaceAddresses()) {
if (!address.getAddress().isLoopbackAddress()) {
if (address.getAddress().isSiteLocalAddress()) {
return address.getAddress();
}
candidate = address.getAddress();
}
}
if (candidate != null) {
return candidate;
}
return null;
}
}
\ No newline at end of file
......@@ -69,12 +69,11 @@ public class AdminClientPropertiesTest {
publishServletContainerInitializedEvent(clientProperties, 8080, null);
publishServletContainerInitializedEvent(clientProperties, 8081, "management");
assertThat(clientProperties.getManagementUrl(), is("http://" + getHostname()
+ ":8081/admin"));
assertThat(clientProperties.getHealthUrl(), is("http://" + getHostname()
+ ":8081/admin/alive"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname()
+ ":8080"));
assertThat(clientProperties.getManagementUrl(),
is("http://" + getHostname() + ":8081/admin"));
assertThat(clientProperties.getHealthUrl(),
is("http://" + getHostname() + ":8081/admin/alive"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname() + ":8080"));
}
@Test
......@@ -86,29 +85,24 @@ public class AdminClientPropertiesTest {
publishServletContainerInitializedEvent(clientProperties, 8080, null);
publishServletContainerInitializedEvent(clientProperties, 8081, "management");
assertThat(clientProperties.getManagementUrl(), is("http://" + getHostname()
+ ":8081"));
assertThat(clientProperties.getHealthUrl(), is("http://" + getHostname()
+ ":8081/health"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname()
+ ":8080"));
assertThat(clientProperties.getManagementUrl(), is("http://" + getHostname() + ":8081"));
assertThat(clientProperties.getHealthUrl(), is("http://" + getHostname() + ":8081/health"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname() + ":8080"));
}
@Test
public void test_contextPath_mgmtPath() {
load("server.context-path=app",
"management.context-path=/admin");
load("server.context-path=app", "management.context-path=/admin");
AdminClientProperties clientProperties = new AdminClientProperties();
context.getAutowireCapableBeanFactory().autowireBean(clientProperties);
publishServletContainerInitializedEvent(clientProperties, 8080, null);
assertThat(clientProperties.getManagementUrl(), is("http://" + getHostname()
+ ":8080/app/admin"));
assertThat(clientProperties.getHealthUrl(), is("http://" + getHostname()
+ ":8080/app/admin/health"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname()
+ ":8080/app"));
assertThat(clientProperties.getManagementUrl(),
is("http://" + getHostname() + ":8080/app/admin"));
assertThat(clientProperties.getHealthUrl(),
is("http://" + getHostname() + ":8080/app/admin/health"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname() + ":8080/app"));
}
@Test
......@@ -119,12 +113,10 @@ public class AdminClientPropertiesTest {
publishServletContainerInitializedEvent(clientProperties, 80, null);
assertThat(clientProperties.getManagementUrl(), is("http://" + getHostname()
+ ":80/app"));
assertThat(clientProperties.getHealthUrl(), is("http://" + getHostname()
+ ":80/app/health"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname()
+ ":80/app"));
assertThat(clientProperties.getManagementUrl(), is("http://" + getHostname() + ":80/app"));
assertThat(clientProperties.getHealthUrl(),
is("http://" + getHostname() + ":80/app/health"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname() + ":80/app"));
}
@Test
......@@ -135,12 +127,9 @@ public class AdminClientPropertiesTest {
publishServletContainerInitializedEvent(clientProperties, 8080, null);
assertThat(clientProperties.getManagementUrl(), is("http://" + getHostname()
+ ":8080"));
assertThat(clientProperties.getHealthUrl(), is("http://" + getHostname()
+ ":8080/health"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname()
+ ":8080"));
assertThat(clientProperties.getManagementUrl(), is("http://" + getHostname() + ":8080"));
assertThat(clientProperties.getHealthUrl(), is("http://" + getHostname() + ":8080/health"));
assertThat(clientProperties.getServiceUrl(), is("http://" + getHostname() + ":8080"));
}
@Test
......@@ -151,51 +140,75 @@ public class AdminClientPropertiesTest {
publishServletContainerInitializedEvent(clientProperties, 8080, null);
assertThat(clientProperties.getManagementUrl(), is("https://" + getHostname()
+ ":8080"));
assertThat(clientProperties.getHealthUrl(), is("https://" + getHostname()
+ ":8080/health"));
assertThat(clientProperties.getServiceUrl(), is("https://" + getHostname()
+ ":8080"));
assertThat(clientProperties.getManagementUrl(), is("https://" + getHostname() + ":8080"));
assertThat(clientProperties.getHealthUrl(),
is("https://" + getHostname() + ":8080/health"));
assertThat(clientProperties.getServiceUrl(), is("https://" + getHostname() + ":8080"));
}
@Test(expected = IllegalArgumentException.class)
public void test_preferIpAddress_nic_not_exsts() {
public void test_preferIpAddress_serveraddress_missing() {
load();
AdminClientProperties clientProperties = new AdminClientProperties();
clientProperties.setUseIpAddressOf("eth-not-exist");
clientProperties.setPreferIp(true);
context.getAutowireCapableBeanFactory().autowireBean(clientProperties);
publishServletContainerInitializedEvent(clientProperties, 8080, null);
clientProperties.getServiceUrl();
}
@Test(expected = IllegalArgumentException.class)
public void test_preferIpAddress_managementaddress_missing() {
load();
AdminClientProperties clientProperties = new AdminClientProperties();
clientProperties.setPreferIp(true);
context.getAutowireCapableBeanFactory().autowireBean(clientProperties);
publishServletContainerInitializedEvent(clientProperties, 8080, null);
publishServletContainerInitializedEvent(clientProperties, 8081, "management");
clientProperties.getManagementUrl();
}
@Test
public void test_preferIpAddress() {
load("server.address=127.0.0.1", "management.address=127.0.0.2");
AdminClientProperties clientProperties = new AdminClientProperties();
clientProperties.setPreferIp(true);
context.getAutowireCapableBeanFactory().autowireBean(clientProperties);
publishServletContainerInitializedEvent(clientProperties, 8080, null);
publishServletContainerInitializedEvent(clientProperties, 8081, "management");
assertThat(clientProperties.getManagementUrl(), is("http://127.0.0.2:8081"));
assertThat(clientProperties.getHealthUrl(), is("http://127.0.0.2:8081/health"));
assertThat(clientProperties.getServiceUrl(), is("http://127.0.0.1:8080"));
}
private String getHostname() {
try {
return InetAddress.getLocalHost().getCanonicalHostName();
}
catch (UnknownHostException e) {
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
private void publishServletContainerInitializedEvent(AdminClientProperties client,
int port, String namespace) {
private void publishServletContainerInitializedEvent(AdminClientProperties client, int port,
String namespace) {
EmbeddedServletContainer eventSource = mock(EmbeddedServletContainer.class);
when(eventSource.getPort()).thenReturn(port);
EmbeddedWebApplicationContext eventContext = mock(EmbeddedWebApplicationContext.class);
when(eventContext.getNamespace()).thenReturn(namespace);
when(eventContext.getEmbeddedServletContainer()).thenReturn(eventSource);
client.onApplicationEvent(new EmbeddedServletContainerInitializedEvent(
eventContext,
eventSource));
client.onApplicationEvent(
new EmbeddedServletContainerInitializedEvent(eventContext, eventSource));
}
private void publishContextRefreshedEvent(AdminClientProperties client) {
client.onApplicationEvent(new ContextRefreshedEvent(
mock(EmbeddedWebApplicationContext.class)));
client.onApplicationEvent(
new ContextRefreshedEvent(mock(EmbeddedWebApplicationContext.class)));
}
private void load(String... environment) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment