Commit 2848a637 by Johannes Edmeier

Improve the client configuration for usage in war-file deployments

With this commit two new properties were added to ease the client configuration when used in servlet containers: `spring.boot.admin.client.management-base-url` and `spring.boot.admin.client.service-base-url`. Both properties can be used to specify protocol, host and port for the urls. The paths will still be guessed and appended to the base-urls. Additionally the servlet context path is not read from the properties but from the ServletContext itself. closes #488
parent 3f02e73f
......@@ -101,13 +101,21 @@ spring.boot.admin.password
| Client-health-url to register with. Can be overridden in case the reachable URL is different (e.g. Docker). Must be unique in registry.
| Guessed based on management-url and `endpoints.health.id`.
| spring.boot.admin.client.management-base-url
| Base url for computing the management-url to register with. The path is inferred at runtime, and appended to the base url.
| Guessed based on `management.port`, service-url and `server.servlet-path`.
| spring.boot.admin.client.management-url
| Client-management-url to register with. Can be overridden in case the reachable url is different (e.g. Docker).
| Guessed based on service-url, `server.servlet-path`, `management.port` and `management.context-path`.
| Management-url to register with. Can be overridden in case the reachable url is different (e.g. Docker).
| Guessed based on managment-base-url and `management.context-path`.
| spring.boot.admin.client.service-base-url
| Base url for computing the service-url to register with. The path is inferred at runtime, and appended to the base url.
| Guessed based on hostname, `server.port`.
| spring.boot.admin.client.service-url
| Client-service-url to register with. Can be overridden in case the reachable url is different (e.g. Docker).
| Guessed based on hostname, `server.port` and `server.context-path`.
| Guessed based on service-base-url and `server.context-path`.
| spring.boot.admin.client.name
| Name to register with.
......
......@@ -15,10 +15,11 @@
*/
package de.codecentric.boot.admin.notify;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
......@@ -29,8 +30,6 @@ import org.springframework.http.MediaType;
import org.springframework.util.Base64Utils;
import org.springframework.web.client.RestTemplate;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
/**
* Notifier submitting events to let´s Chat.
......
......@@ -17,91 +17,116 @@ package de.codecentric.boot.admin.client.config;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring.boot.admin.client")
public class AdminClientProperties {
/**
* Client-management-URL to register with. Inferred at runtime, can be overridden in case the
* reachable URL is different (e.g. Docker).
*/
private String managementUrl;
/**
* Client-service-URL register with. Inferred at runtime, can be overridden in case the reachable
* URL is different (e.g. Docker).
*/
private String serviceUrl;
/**
* Client-health-URL to register with. Inferred at runtime, can be overridden in case the
* reachable URL is different (e.g. Docker). Must be unique in registry.
*/
private String healthUrl;
/**
* Name to register with. Defaults to ${spring.application.name}
*/
@Value("${spring.application.name:spring-boot-application}")
private String name;
/**
* Should the registered urls be built with server.address or with hostname.
*/
private boolean preferIp = false;
/**
* Metadata that should be associated with this application
*/
private Map<String, String> metadata = new HashMap<>();
public String getManagementUrl() {
return managementUrl;
}
public void setManagementUrl(String managementUrl) {
this.managementUrl = managementUrl;
}
public String getServiceUrl() {
return serviceUrl;
}
public void setServiceUrl(String serviceUrl) {
this.serviceUrl = serviceUrl;
}
public String getHealthUrl() {
return healthUrl;
}
public void setHealthUrl(String healthUrl) {
this.healthUrl = healthUrl;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isPreferIp() {
return preferIp;
}
public void setPreferIp(boolean preferIp) {
this.preferIp = preferIp;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
/**
* Management-url to register with. Inferred at runtime, can be overridden in case the
* reachable URL is different (e.g. Docker).
*/
private String managementUrl;
/**
* Base url for computing the management-url to register with. The path is inferred at runtime, and appended to the base url.
*/
private String managementBaseUrl;
/**
* Client-service-URL register with. Inferred at runtime, can be overridden in case the reachable
* URL is different (e.g. Docker).
*/
private String serviceUrl;
/**
* Base url for computing the service-url to register with. The path is inferred at runtime, and appended to the base url.
*/
private String serviceBaseUrl;
/**
* Client-health-URL to register with. Inferred at runtime, can be overridden in case the
* reachable URL is different (e.g. Docker). Must be unique in registry.
*/
private String healthUrl;
/**
* Name to register with. Defaults to ${spring.application.name}
*/
@Value("${spring.application.name:spring-boot-application}")
private String name;
/**
* Should the registered urls be built with server.address or with hostname.
*/
private boolean preferIp = false;
/**
* Metadata that should be associated with this application
*/
private Map<String, String> metadata = new HashMap<>();
public String getManagementUrl() {
return managementUrl;
}
public void setManagementUrl(String managementUrl) {
this.managementUrl = managementUrl;
}
public String getServiceUrl() {
return serviceUrl;
}
public void setServiceUrl(String serviceUrl) {
this.serviceUrl = serviceUrl;
}
public String getHealthUrl() {
return healthUrl;
}
public void setHealthUrl(String healthUrl) {
this.healthUrl = healthUrl;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isPreferIp() {
return preferIp;
}
public void setPreferIp(boolean preferIp) {
this.preferIp = preferIp;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
public String getManagementBaseUrl() {
return managementBaseUrl;
}
public void setManagementBaseUrl(String managementBaseUrl) {
this.managementBaseUrl = managementBaseUrl;
}
public String getServiceBaseUrl() {
return serviceBaseUrl;
}
public void setServiceBaseUrl(String serviceBaseUrl) {
this.serviceBaseUrl = serviceBaseUrl;
}
}
......@@ -15,6 +15,12 @@
*/
package de.codecentric.boot.admin.client.config;
import de.codecentric.boot.admin.client.registration.ApplicationFactory;
import de.codecentric.boot.admin.client.registration.ApplicationRegistrator;
import de.codecentric.boot.admin.client.registration.DefaultApplicationFactory;
import de.codecentric.boot.admin.client.registration.RegistrationApplicationListener;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties;
......@@ -30,56 +36,53 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import de.codecentric.boot.admin.client.registration.ApplicationFactory;
import de.codecentric.boot.admin.client.registration.ApplicationRegistrator;
import de.codecentric.boot.admin.client.registration.DefaultApplicationFactory;
import de.codecentric.boot.admin.client.registration.RegistrationApplicationListener;
@Configuration
@EnableConfigurationProperties({ AdminProperties.class, AdminClientProperties.class })
@EnableConfigurationProperties({AdminProperties.class, AdminClientProperties.class})
@Conditional(SpringBootAdminClientEnabledCondition.class)
public class SpringBootAdminClientAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public ApplicationRegistrator registrator(AdminProperties admin,
ApplicationFactory applicationFactory, RestTemplateBuilder restTemplBuilder) {
RestTemplateBuilder builder = restTemplBuilder
.messageConverters(new MappingJackson2HttpMessageConverter())
.requestFactory(SimpleClientHttpRequestFactory.class);
if (admin.getUsername() != null) {
builder = builder.basicAuthorization(admin.getUsername(), admin.getPassword());
}
return new ApplicationRegistrator(builder.build(), admin, applicationFactory);
}
@Bean
@ConditionalOnMissingBean
public ApplicationRegistrator registrator(AdminProperties admin,
ApplicationFactory applicationFactory,
RestTemplateBuilder restTemplBuilder) {
RestTemplateBuilder builder = restTemplBuilder.messageConverters(new MappingJackson2HttpMessageConverter())
.requestFactory(SimpleClientHttpRequestFactory.class);
if (admin.getUsername() != null) {
builder = builder.basicAuthorization(admin.getUsername(), admin.getPassword());
}
return new ApplicationRegistrator(builder.build(), admin, applicationFactory);
}
@Bean
@ConditionalOnMissingBean
public ApplicationFactory applicationFactory(AdminClientProperties client,
ManagementServerProperties management, ServerProperties server,
@Value("${endpoints.health.path:/${endpoints.health.id:health}}") String healthEndpointPath) {
return new DefaultApplicationFactory(client, management, server, healthEndpointPath);
}
@Bean
@ConditionalOnMissingBean
public ApplicationFactory applicationFactory(AdminClientProperties client,
ManagementServerProperties management,
ServerProperties server,
@Value("${endpoints.health.path:/${endpoints.health.id:health}}") String healthEndpointPath,
ServletContext servletContext) {
return new DefaultApplicationFactory(client, management, server, servletContext, healthEndpointPath);
}
@Bean
@Qualifier("registrationTaskScheduler")
public TaskScheduler registrationTaskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(1);
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setThreadNamePrefix("registrationTask");
return taskScheduler;
}
@Bean
@Qualifier("registrationTaskScheduler")
public TaskScheduler registrationTaskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(1);
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setThreadNamePrefix("registrationTask");
return taskScheduler;
}
@Bean
@ConditionalOnMissingBean
public RegistrationApplicationListener registrationListener(AdminProperties admin,
ApplicationRegistrator registrator) {
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator,
registrationTaskScheduler());
listener.setAutoRegister(admin.isAutoRegistration());
listener.setAutoDeregister(admin.isAutoDeregistration());
listener.setRegisterPeriod(admin.getPeriod());
return listener;
}
@Bean
@ConditionalOnMissingBean
public RegistrationApplicationListener registrationListener(AdminProperties admin,
ApplicationRegistrator registrator) {
RegistrationApplicationListener listener = new RegistrationApplicationListener(registrator,
registrationTaskScheduler());
listener.setAutoRegister(admin.isAutoRegistration());
listener.setAutoDeregister(admin.isAutoDeregistration());
listener.setRegisterPeriod(admin.getPeriod());
return listener;
}
}
package de.codecentric.boot.admin.client.config;
import static org.junit.Assert.assertTrue;
import de.codecentric.boot.admin.client.registration.ApplicationRegistrator;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration.RestTemplateConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration;
import de.codecentric.boot.admin.client.registration.ApplicationRegistrator;
import static org.junit.Assert.assertTrue;
public class SpringBootAdminClientAutoConfigurationTest {
private AnnotationConfigWebApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void not_active() {
load();
assertTrue(context.getBeansOfType(ApplicationRegistrator.class).isEmpty());
}
@Test
public void active() {
load("spring.boot.admin.url:http://localhost:8081");
context.getBean(ApplicationRegistrator.class);
}
@Test
public void disabled() {
load("spring.boot.admin.url:http://localhost:8081",
"spring.boot.admin.client.enabled:false");
assertTrue(context.getBeansOfType(ApplicationRegistrator.class).isEmpty());
}
private void load(String... environment) {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(ServerPropertiesAutoConfiguration.class);
applicationContext.register(RestTemplateConfiguration.class);
applicationContext.register(ManagementServerPropertiesAutoConfiguration.class);
applicationContext.register(EndpointAutoConfiguration.class);
applicationContext.register(EndpointWebMvcManagementContextConfiguration.class);
applicationContext.register(SpringBootAdminClientAutoConfiguration.class);
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
applicationContext.refresh();
this.context = applicationContext;
}
private ConfigurableApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void not_active() {
load();
assertTrue(context.getBeansOfType(ApplicationRegistrator.class).isEmpty());
}
@Test
public void active() {
load("spring.boot.admin.url:http://localhost:8081");
context.getBean(ApplicationRegistrator.class);
}
@Test
public void disabled() {
load("spring.boot.admin.url:http://localhost:8081", "spring.boot.admin.client.enabled:false");
assertTrue(context.getBeansOfType(ApplicationRegistrator.class).isEmpty());
}
private void load(final String... environment) {
SpringApplication springApplication = new SpringApplication(TestClientApplication.class);
springApplication.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
}
});
this.context = springApplication.run("--server.port=0");
}
@Configuration
@EnableAutoConfiguration
static class TestClientApplication {
}
}
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