Provide links for actuators at / when using a separate management port

See gh-17418
pull/17431/head
HaiTao Zhang 5 years ago committed by Madhura Bhave
parent edea223841
commit c108629311

@ -26,6 +26,7 @@ import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
@ -42,6 +43,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer; import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
/** /**
* {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jersey * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jersey
@ -62,14 +64,16 @@ class JerseyWebEndpointManagementContextConfiguration {
@Bean @Bean
ResourceConfigCustomizer webEndpointRegistrar(WebEndpointsSupplier webEndpointsSupplier, ResourceConfigCustomizer webEndpointRegistrar(WebEndpointsSupplier webEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, ServletEndpointsSupplier servletEndpointsSupplier, EndpointMediaTypes endpointMediaTypes,
WebEndpointProperties webEndpointProperties) { WebEndpointProperties webEndpointProperties, Environment environment) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(); List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
allEndpoints.addAll(webEndpointsSupplier.getEndpoints()); allEndpoints.addAll(webEndpointsSupplier.getEndpoints());
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints()); allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
return (resourceConfig) -> { return (resourceConfig) -> {
JerseyEndpointResourceFactory resourceFactory = new JerseyEndpointResourceFactory(); JerseyEndpointResourceFactory resourceFactory = new JerseyEndpointResourceFactory();
String basePath = webEndpointProperties.getBasePath(); String basePath = webEndpointProperties.getBasePath();
EndpointMapping endpointMapping = new EndpointMapping(basePath); ManagementPortType type = ManagementPortType.get(environment);
Boolean samePort = type == ManagementPortType.SAME;
EndpointMapping endpointMapping = new EndpointMapping(basePath, samePort);
Collection<ExposableWebEndpoint> webEndpoints = Collections Collection<ExposableWebEndpoint> webEndpoints = Collections
.unmodifiableCollection(webEndpointsSupplier.getEndpoints()); .unmodifiableCollection(webEndpointsSupplier.getEndpoints());
resourceConfig.registerResources(new HashSet<>(resourceFactory.createEndpointResources(endpointMapping, resourceConfig.registerResources(new HashSet<>(resourceFactory.createEndpointResources(endpointMapping,

@ -23,6 +23,7 @@ import java.util.List;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
@ -40,6 +41,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.http.server.reactive.HttpHandler; import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.reactive.DispatcherHandler;
@ -62,8 +64,11 @@ public class WebFluxEndpointManagementContextConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
public WebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping(WebEndpointsSupplier webEndpointsSupplier, public WebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes,
CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties) { CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties,
EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath()); Environment environment) {
ManagementPortType type = ManagementPortType.get(environment);
Boolean samePort = type == ManagementPortType.SAME;
EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath(), samePort);
Collection<ExposableWebEndpoint> endpoints = webEndpointsSupplier.getEndpoints(); Collection<ExposableWebEndpoint> endpoints = webEndpointsSupplier.getEndpoints();
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(); List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
allEndpoints.addAll(endpoints); allEndpoints.addAll(endpoints);

@ -23,6 +23,7 @@ import java.util.List;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver; import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
@ -41,6 +42,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
/** /**
@ -63,13 +65,15 @@ public class WebMvcEndpointManagementContextConfiguration {
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier, public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties) { WebEndpointProperties webEndpointProperties, Environment environment) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(); List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints(); Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
allEndpoints.addAll(webEndpoints); allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints()); allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints()); allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath()); ManagementPortType type = ManagementPortType.get(environment);
Boolean samePort = type == ManagementPortType.SAME;
EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath(), samePort);
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes, return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
corsProperties.toCorsConfiguration(), corsProperties.toCorsConfiguration(),
new EndpointLinksResolver(allEndpoints, webEndpointProperties.getBasePath())); new EndpointLinksResolver(allEndpoints, webEndpointProperties.getBasePath()));

@ -28,12 +28,20 @@ public class EndpointMapping {
private final String path; private final String path;
private final Boolean samePort;
/** /**
* Creates a new {@code EndpointMapping} using the given {@code path}. * Creates a new {@code EndpointMapping} using the given {@code path}.
* @param path the path * @param path the path
* @param samePort states true or false for same port as server
*/ */
public EndpointMapping(String path) { public EndpointMapping(String path, Boolean samePort) {
this.path = normalizePath(path); this.path = normalizePath(path);
this.samePort = samePort;
}
public EndpointMapping(String path) {
this(path, true);
} }
/** /**
@ -44,6 +52,10 @@ public class EndpointMapping {
return this.path; return this.path;
} }
public boolean isSamePort() {
return this.samePort;
}
public String createSubPath(String path) { public String createSubPath(String path) {
return this.path + normalizePath(path); return this.path + normalizePath(path);
} }

@ -79,7 +79,7 @@ public class JerseyEndpointResourceFactory {
List<Resource> resources = new ArrayList<>(); List<Resource> resources = new ArrayList<>();
endpoints.stream().flatMap((endpoint) -> endpoint.getOperations().stream()) endpoints.stream().flatMap((endpoint) -> endpoint.getOperations().stream())
.map((operation) -> createResource(endpointMapping, operation)).forEach(resources::add); .map((operation) -> createResource(endpointMapping, operation)).forEach(resources::add);
if (StringUtils.hasText(endpointMapping.getPath())) { if (StringUtils.hasText(endpointMapping.getPath()) || !endpointMapping.isSamePort()) {
Resource resource = createEndpointLinksResource(endpointMapping.getPath(), endpointMediaTypes, Resource resource = createEndpointLinksResource(endpointMapping.getPath(), endpointMediaTypes,
linksResolver); linksResolver);
resources.add(resource); resources.add(resource);

@ -120,7 +120,7 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
registerMappingForOperation(endpoint, operation); registerMappingForOperation(endpoint, operation);
} }
} }
if (StringUtils.hasText(this.endpointMapping.getPath())) { if (StringUtils.hasText(this.endpointMapping.getPath()) || !this.endpointMapping.isSamePort()) {
registerLinksMapping(); registerLinksMapping();
} }
} }

@ -123,7 +123,7 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
registerMappingForOperation(endpoint, operation); registerMappingForOperation(endpoint, operation);
} }
} }
if (StringUtils.hasText(this.endpointMapping.getPath())) { if (StringUtils.hasText(this.endpointMapping.getPath()) || !this.endpointMapping.isSamePort()) {
registerLinksMapping(); registerLinksMapping();
} }
} }

@ -77,4 +77,9 @@ class EndpointMappingTests {
assertThat(new EndpointMapping("/test").createSubPath("one/")).isEqualTo("/test/one"); assertThat(new EndpointMapping("/test").createSubPath("one/")).isEqualTo("/test/one");
} }
@Test
void setDifferentPort() {
assertThat(new EndpointMapping("/test", false).isSamePort()).isFalse();
}
} }

@ -0,0 +1,37 @@
package smoketest.actuator;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = { "management.endpoints.web.base-path=/","management.server.port=0"})
public class ManagementDifferentPortSampleActuatorApplicationTests {
@LocalServerPort
private int port;
@LocalManagementPort
private int managementPort;
@Test
void testDifferentServerPort(){
if(this.managementPort != this.port) {
ResponseEntity<String> entity = new TestRestTemplate("user", getPassword())
.getForEntity("http://localhost:" + this.managementPort + "/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("\"_links\"");
}
}
private String getPassword(){
return "password";
}
}

@ -0,0 +1,35 @@
package smoketest.jersey;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {"management.server.port=0","management.endpoints.web.base-path=/"})
public class JerseyDifferentPortSampleActuatorApplicationTests {
@LocalManagementPort
private int managementPort;
@LocalServerPort
private int port;
@Test
void testDifferentServerPort(){
if(this.managementPort != this.port) {
ResponseEntity<String> entity = new TestRestTemplate("user", getPassword())
.getForEntity("http://localhost:" + this.managementPort + "/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("\"_links\"");
}
}
private String getPassword(){
return "password";
}
}

@ -0,0 +1,35 @@
package smoketest.webflux;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {"management.server.port=0","management.endpoints.web.base-path=/"})
public class WebFluxDifferentPortSampleActuatorApplicationTests {
@LocalManagementPort
private int managementPort;
@LocalServerPort
private int port;
@Test
void testDifferentServerPort(){
if(this.managementPort != this.port) {
ResponseEntity<String> entity = new TestRestTemplate("user", getPassword())
.getForEntity("http://localhost:" + this.managementPort + "/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("\"_links\"");
}
}
private String getPassword(){
return "password";
}
}
Loading…
Cancel
Save