Allow health groups to be configured at an additional path
Closes gh-25471 Co-authored-by: Phillip Webb <pwebb@vmware.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -61,8 +61,9 @@ public class AvailabilityProbesAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AvailabilityProbesHealthEndpointGroupsPostProcessor availabilityProbesHealthEndpointGroupsPostProcessor() {
|
||||
return new AvailabilityProbesHealthEndpointGroupsPostProcessor();
|
||||
public AvailabilityProbesHealthEndpointGroupsPostProcessor availabilityProbesHealthEndpointGroupsPostProcessor(
|
||||
Environment environment) {
|
||||
return new AvailabilityProbesHealthEndpointGroupsPostProcessor(environment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroup;
|
||||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
@@ -35,8 +36,11 @@ class AvailabilityProbesHealthEndpointGroup implements HealthEndpointGroup {
|
||||
|
||||
private final Set<String> members;
|
||||
|
||||
AvailabilityProbesHealthEndpointGroup(String... members) {
|
||||
private final AdditionalHealthEndpointPath additionalPath;
|
||||
|
||||
AvailabilityProbesHealthEndpointGroup(AdditionalHealthEndpointPath additionalPath, String... members) {
|
||||
this.members = new HashSet<>(Arrays.asList(members));
|
||||
this.additionalPath = additionalPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,4 +68,9 @@ class AvailabilityProbesHealthEndpointGroup implements HealthEndpointGroup {
|
||||
return HttpCodeStatusMapper.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdditionalHealthEndpointPath getAdditionalPath() {
|
||||
return this.additionalPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,8 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroup;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -31,29 +33,39 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Brian Clozel
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class AvailabilityProbesHealthEndpointGroups implements HealthEndpointGroups {
|
||||
|
||||
private static final Map<String, AvailabilityProbesHealthEndpointGroup> GROUPS;
|
||||
static {
|
||||
Map<String, AvailabilityProbesHealthEndpointGroup> groups = new LinkedHashMap<>();
|
||||
groups.put("liveness", new AvailabilityProbesHealthEndpointGroup("livenessState"));
|
||||
groups.put("readiness", new AvailabilityProbesHealthEndpointGroup("readinessState"));
|
||||
GROUPS = Collections.unmodifiableMap(groups);
|
||||
}
|
||||
|
||||
private final HealthEndpointGroups groups;
|
||||
|
||||
private final Map<String, HealthEndpointGroup> probeGroups;
|
||||
|
||||
private final Set<String> names;
|
||||
|
||||
AvailabilityProbesHealthEndpointGroups(HealthEndpointGroups groups) {
|
||||
AvailabilityProbesHealthEndpointGroups(HealthEndpointGroups groups, boolean addAdditionalPaths) {
|
||||
Assert.notNull(groups, "Groups must not be null");
|
||||
this.groups = groups;
|
||||
this.probeGroups = createProbeGroups(addAdditionalPaths);
|
||||
Set<String> names = new LinkedHashSet<>(groups.getNames());
|
||||
names.addAll(GROUPS.keySet());
|
||||
names.addAll(this.probeGroups.keySet());
|
||||
this.names = Collections.unmodifiableSet(names);
|
||||
}
|
||||
|
||||
private Map<String, HealthEndpointGroup> createProbeGroups(boolean addAdditionalPaths) {
|
||||
Map<String, HealthEndpointGroup> probeGroups = new LinkedHashMap<>();
|
||||
probeGroups.put("liveness", createProbeGroup(addAdditionalPaths, "/livez", "livenessState"));
|
||||
probeGroups.put("readiness", createProbeGroup(addAdditionalPaths, "/readyz", "readinessState"));
|
||||
return Collections.unmodifiableMap(probeGroups);
|
||||
}
|
||||
|
||||
private AvailabilityProbesHealthEndpointGroup createProbeGroup(boolean addAdditionalPath, String path,
|
||||
String members) {
|
||||
AdditionalHealthEndpointPath additionalPath = (!addAdditionalPath) ? null
|
||||
: AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER, path);
|
||||
return new AvailabilityProbesHealthEndpointGroup(additionalPath, members);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HealthEndpointGroup getPrimary() {
|
||||
return this.groups.getPrimary();
|
||||
@@ -68,13 +80,14 @@ class AvailabilityProbesHealthEndpointGroups implements HealthEndpointGroups {
|
||||
public HealthEndpointGroup get(String name) {
|
||||
HealthEndpointGroup group = this.groups.get(name);
|
||||
if (group == null) {
|
||||
group = GROUPS.get(name);
|
||||
group = this.probeGroups.get(name);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
static boolean containsAllProbeGroups(HealthEndpointGroups groups) {
|
||||
return groups.getNames().containsAll(GROUPS.keySet());
|
||||
Set<String> names = groups.getNames();
|
||||
return names.contains("liveness") && names.contains("readiness");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,22 +20,31 @@ import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroupsPostProcessor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* {@link HealthEndpointGroupsPostProcessor} to add
|
||||
* {@link AvailabilityProbesHealthEndpointGroups}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
class AvailabilityProbesHealthEndpointGroupsPostProcessor implements HealthEndpointGroupsPostProcessor {
|
||||
|
||||
private final boolean addAdditionalPaths;
|
||||
|
||||
AvailabilityProbesHealthEndpointGroupsPostProcessor(Environment environment) {
|
||||
this.addAdditionalPaths = "true"
|
||||
.equalsIgnoreCase(environment.getProperty("management.endpoint.health.probes.add-additional-paths"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HealthEndpointGroups postProcessHealthEndpointGroups(HealthEndpointGroups groups) {
|
||||
if (AvailabilityProbesHealthEndpointGroups.containsAllProbeGroups(groups)) {
|
||||
return groups;
|
||||
}
|
||||
return new AvailabilityProbesHealthEndpointGroups(groups);
|
||||
return new AvailabilityProbesHealthEndpointGroups(groups, this.addAdditionalPaths);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,13 +48,13 @@ public class CloudFoundryReactiveHealthEndpointWebExtension {
|
||||
|
||||
@ReadOperation
|
||||
public Mono<WebEndpointResponse<? extends HealthComponent>> health(ApiVersion apiVersion) {
|
||||
return this.delegate.health(apiVersion, SecurityContext.NONE, true);
|
||||
return this.delegate.health(apiVersion, null, SecurityContext.NONE, true);
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public Mono<WebEndpointResponse<? extends HealthComponent>> health(ApiVersion apiVersion,
|
||||
@Selector(match = Match.ALL_REMAINING) String... path) {
|
||||
return this.delegate.health(apiVersion, SecurityContext.NONE, true, path);
|
||||
return this.delegate.health(apiVersion, null, SecurityContext.NONE, true, path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,13 +46,13 @@ public class CloudFoundryHealthEndpointWebExtension {
|
||||
|
||||
@ReadOperation
|
||||
public WebEndpointResponse<HealthComponent> health(ApiVersion apiVersion) {
|
||||
return this.delegate.health(apiVersion, SecurityContext.NONE, true);
|
||||
return this.delegate.health(apiVersion, null, SecurityContext.NONE, true);
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public WebEndpointResponse<HealthComponent> health(ApiVersion apiVersion,
|
||||
@Selector(match = Match.ALL_REMAINING) String... path) {
|
||||
return this.delegate.health(apiVersion, SecurityContext.NONE, true, path);
|
||||
return this.delegate.health(apiVersion, null, SecurityContext.NONE, true, path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,11 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.web.jersey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
import org.glassfish.jersey.server.model.Resource;
|
||||
@@ -27,7 +30,9 @@ import org.glassfish.jersey.server.model.Resource;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.jersey.ManagementContextResourceConfigCustomizer;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
|
||||
import org.springframework.boot.actuate.endpoint.EndpointId;
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
|
||||
@@ -36,8 +41,12 @@ import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.jersey.JerseyEndpointResourceFactory;
|
||||
import org.springframework.boot.actuate.endpoint.web.jersey.JerseyHealthEndpointAdditionalPathResourceFactory;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -64,6 +73,8 @@ import org.springframework.util.StringUtils;
|
||||
@ConditionalOnMissingBean(type = "org.springframework.web.servlet.DispatcherServlet")
|
||||
class JerseyWebEndpointManagementContextConfiguration {
|
||||
|
||||
private static final EndpointId HEALTH_ENDPOINT_ID = EndpointId.of("health");
|
||||
|
||||
@Bean
|
||||
JerseyWebEndpointsResourcesRegistrar jerseyWebEndpointsResourcesRegistrar(Environment environment,
|
||||
WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier,
|
||||
@@ -74,6 +85,17 @@ class JerseyWebEndpointManagementContextConfiguration {
|
||||
endpointMediaTypes, basePath, shouldRegisterLinks);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(HealthEndpoint.class)
|
||||
@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)
|
||||
JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar jerseyDifferentPortAdditionalHealthEndpointPathsResourcesRegistrar(
|
||||
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups healthEndpointGroups) {
|
||||
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
|
||||
ExposableWebEndpoint health = webEndpoints.stream()
|
||||
.filter((endpoint) -> endpoint.getEndpointId().equals(HEALTH_ENDPOINT_ID)).findFirst().get();
|
||||
return new JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(health, healthEndpointGroups);
|
||||
}
|
||||
|
||||
private boolean shouldRegisterLinksMapping(WebEndpointProperties properties, Environment environment,
|
||||
String basePath) {
|
||||
return properties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)
|
||||
@@ -134,4 +156,38 @@ class JerseyWebEndpointManagementContextConfiguration {
|
||||
|
||||
}
|
||||
|
||||
class JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar
|
||||
implements ManagementContextResourceConfigCustomizer {
|
||||
|
||||
private final ExposableWebEndpoint endpoint;
|
||||
|
||||
private final HealthEndpointGroups groups;
|
||||
|
||||
JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(ExposableWebEndpoint endpoint,
|
||||
HealthEndpointGroups groups) {
|
||||
this.endpoint = endpoint;
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(ResourceConfig config) {
|
||||
register(config);
|
||||
}
|
||||
|
||||
private void register(ResourceConfig config) {
|
||||
EndpointMapping mapping = new EndpointMapping("");
|
||||
JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(
|
||||
WebServerNamespace.MANAGEMENT, this.groups);
|
||||
Collection<Resource> endpointResources = resourceFactory
|
||||
.createEndpointResources(mapping, Collections.singletonList(this.endpoint), null, null, false)
|
||||
.stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
register(endpointResources, config);
|
||||
}
|
||||
|
||||
private void register(Collection<Resource> resources, ResourceConfig config) {
|
||||
config.registerResources(new HashSet<>(resources));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
@@ -31,9 +32,13 @@ import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.reactive.AdditionalHealthEndpointPathsWebFluxHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.reactive.ControllerEndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -84,6 +89,18 @@ public class WebFluxEndpointManagementContextConfiguration {
|
||||
|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)
|
||||
@ConditionalOnBean(HealthEndpoint.class)
|
||||
public AdditionalHealthEndpointPathsWebFluxHandlerMapping managementHealthEndpointWebFluxHandlerMapping(
|
||||
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
|
||||
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
|
||||
ExposableWebEndpoint health = webEndpoints.stream()
|
||||
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID)).findFirst().get();
|
||||
return new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(""), health,
|
||||
groups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ControllerEndpointHandlerMapping controllerEndpointHandlerMapping(
|
||||
|
||||
@@ -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.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
@@ -31,10 +32,14 @@ import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.servlet.AdditionalHealthEndpointPathsWebMvcHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.servlet.ControllerEndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -86,6 +91,18 @@ public class WebMvcEndpointManagementContextConfiguration {
|
||||
|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)
|
||||
@ConditionalOnBean(HealthEndpoint.class)
|
||||
public AdditionalHealthEndpointPathsWebMvcHandlerMapping managementHealthEndpointWebMvcHandlerMapping(
|
||||
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
|
||||
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
|
||||
ExposableWebEndpoint health = webEndpoints.stream()
|
||||
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID)).findFirst().get();
|
||||
return new AdditionalHealthEndpointPathsWebMvcHandlerMapping(health,
|
||||
groups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ControllerEndpointHandlerMapping controllerEndpointHandlerMapping(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthProperties.Show;
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroup;
|
||||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
@@ -35,6 +36,7 @@ import org.springframework.util.CollectionUtils;
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class AutoConfiguredHealthEndpointGroup implements HealthEndpointGroup {
|
||||
|
||||
@@ -50,6 +52,8 @@ class AutoConfiguredHealthEndpointGroup implements HealthEndpointGroup {
|
||||
|
||||
private final Collection<String> roles;
|
||||
|
||||
private final AdditionalHealthEndpointPath additionalPath;
|
||||
|
||||
/**
|
||||
* Create a new {@link AutoConfiguredHealthEndpointGroup} instance.
|
||||
* @param members a predicate used to test for group membership
|
||||
@@ -58,16 +62,18 @@ class AutoConfiguredHealthEndpointGroup implements HealthEndpointGroup {
|
||||
* @param showComponents the show components setting
|
||||
* @param showDetails the show details setting
|
||||
* @param roles the roles to match
|
||||
* @param additionalPath the additional path to use for this group
|
||||
*/
|
||||
AutoConfiguredHealthEndpointGroup(Predicate<String> members, StatusAggregator statusAggregator,
|
||||
HttpCodeStatusMapper httpCodeStatusMapper, Show showComponents, Show showDetails,
|
||||
Collection<String> roles) {
|
||||
HttpCodeStatusMapper httpCodeStatusMapper, Show showComponents, Show showDetails, Collection<String> roles,
|
||||
AdditionalHealthEndpointPath additionalPath) {
|
||||
this.members = members;
|
||||
this.statusAggregator = statusAggregator;
|
||||
this.httpCodeStatusMapper = httpCodeStatusMapper;
|
||||
this.showComponents = showComponents;
|
||||
this.showDetails = showDetails;
|
||||
this.roles = roles;
|
||||
this.additionalPath = additionalPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,4 +147,9 @@ class AutoConfiguredHealthEndpointGroup implements HealthEndpointGroup {
|
||||
return this.httpCodeStatusMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdditionalHealthEndpointPath getAdditionalPath() {
|
||||
return this.additionalPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,6 +33,7 @@ import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointProperties.Group;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthProperties.Show;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthProperties.Status;
|
||||
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroup;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
@@ -48,6 +49,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* Auto-configured {@link HealthEndpointGroups}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class AutoConfiguredHealthEndpointGroups implements HealthEndpointGroups {
|
||||
|
||||
@@ -77,7 +79,7 @@ class AutoConfiguredHealthEndpointGroups implements HealthEndpointGroups {
|
||||
httpCodeStatusMapper = new SimpleHttpCodeStatusMapper(properties.getStatus().getHttpMapping());
|
||||
}
|
||||
this.primaryGroup = new AutoConfiguredHealthEndpointGroup(ALL, statusAggregator, httpCodeStatusMapper,
|
||||
showComponents, showDetails, roles);
|
||||
showComponents, showDetails, roles, null);
|
||||
this.groups = createGroups(properties.getGroup(), beanFactory, statusAggregator, httpCodeStatusMapper,
|
||||
showComponents, showDetails, roles);
|
||||
}
|
||||
@@ -106,8 +108,10 @@ class AutoConfiguredHealthEndpointGroups implements HealthEndpointGroups {
|
||||
return defaultHttpCodeStatusMapper;
|
||||
});
|
||||
Predicate<String> members = new IncludeExcludeGroupMemberPredicate(group.getInclude(), group.getExclude());
|
||||
AdditionalHealthEndpointPath additionalPath = (group.getAdditionalPath() != null)
|
||||
? AdditionalHealthEndpointPath.from(group.getAdditionalPath()) : null;
|
||||
groups.put(groupName, new AutoConfiguredHealthEndpointGroup(members, statusAggregator, httpCodeStatusMapper,
|
||||
showComponents, showDetails, roles));
|
||||
showComponents, showDetails, roles, additionalPath));
|
||||
});
|
||||
return Collections.unmodifiableMap(groups);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -61,6 +61,10 @@ public class HealthEndpointProperties extends HealthProperties {
|
||||
*/
|
||||
public static class Group extends HealthProperties {
|
||||
|
||||
public static final String SERVER_PREFIX = "server:";
|
||||
|
||||
public static final String MANAGEMENT_PREFIX = "management:";
|
||||
|
||||
/**
|
||||
* Health indicator IDs that should be included or '*' for all.
|
||||
*/
|
||||
@@ -77,6 +81,14 @@ public class HealthEndpointProperties extends HealthProperties {
|
||||
*/
|
||||
private Show showDetails;
|
||||
|
||||
/**
|
||||
* Additional path that this group can be made available on. The additional path
|
||||
* must start with a valid prefix, either `server` or `management` to indicate if
|
||||
* it will be available on the main port or the management port. For instance,
|
||||
* `server:/healthz` will configure the group on the main port at `/healthz`.
|
||||
*/
|
||||
private String additionalPath;
|
||||
|
||||
public Set<String> getInclude() {
|
||||
return this.include;
|
||||
}
|
||||
@@ -102,6 +114,14 @@ public class HealthEndpointProperties extends HealthProperties {
|
||||
this.showDetails = showDetails;
|
||||
}
|
||||
|
||||
public String getAdditionalPath() {
|
||||
return this.additionalPath;
|
||||
}
|
||||
|
||||
public void setAdditionalPath(String additionalPath) {
|
||||
this.additionalPath = additionalPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,13 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.health;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.endpoint.web.reactive.AdditionalHealthEndpointPathsWebFluxHandlerMapping;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry;
|
||||
@@ -31,6 +38,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
* Configuration for {@link HealthEndpoint} reactive web extensions.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
* @see HealthEndpointAutoConfiguration
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -46,4 +54,19 @@ class HealthEndpointReactiveWebExtensionConfiguration {
|
||||
return new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry, groups);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class WebFluxAdditionalHealthEndpointPathsConfiguration {
|
||||
|
||||
@Bean
|
||||
AdditionalHealthEndpointPathsWebFluxHandlerMapping healthEndpointWebFluxHandlerMapping(
|
||||
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
|
||||
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
|
||||
ExposableWebEndpoint health = webEndpoints.stream()
|
||||
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID)).findFirst().get();
|
||||
return new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(""), health,
|
||||
groups.getAllWithAdditionalPath(WebServerNamespace.SERVER));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,21 +16,48 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.health;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
import org.glassfish.jersey.server.model.Resource;
|
||||
import org.glassfish.jersey.servlet.ServletContainer;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.endpoint.web.jersey.JerseyHealthEndpointAdditionalPathResourceFactory;
|
||||
import org.springframework.boot.actuate.endpoint.web.servlet.AdditionalHealthEndpointPathsWebMvcHandlerMapping;
|
||||
import org.springframework.boot.actuate.health.HealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.autoconfigure.jersey.JerseyProperties;
|
||||
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DefaultJerseyApplicationPath;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.JerseyApplicationPath;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* Configuration for {@link HealthEndpoint} web extensions.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
* @see HealthEndpointAutoConfiguration
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -46,4 +73,98 @@ class HealthEndpointWebExtensionConfiguration {
|
||||
return new HealthEndpointWebExtension(healthContributorRegistry, groups);
|
||||
}
|
||||
|
||||
private static ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {
|
||||
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
|
||||
return webEndpoints.stream().filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
|
||||
.findFirst().get();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(DispatcherServlet.class)
|
||||
static class MvcAdditionalHealthEndpointPathsConfiguration {
|
||||
|
||||
@Bean
|
||||
AdditionalHealthEndpointPathsWebMvcHandlerMapping healthEndpointWebMvcHandlerMapping(
|
||||
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
|
||||
ExposableWebEndpoint health = getHealthEndpoint(webEndpointsSupplier);
|
||||
return new AdditionalHealthEndpointPathsWebMvcHandlerMapping(health,
|
||||
groups.getAllWithAdditionalPath(WebServerNamespace.SERVER));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(ResourceConfig.class)
|
||||
@ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet")
|
||||
static class JerseyAdditionalHealthEndpointPathsConfiguration {
|
||||
|
||||
@Bean
|
||||
JerseyAdditionalHealthEndpointPathsResourcesRegistrar jerseyAdditionalHealthEndpointPathsResourcesRegistrar(
|
||||
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups healthEndpointGroups) {
|
||||
ExposableWebEndpoint health = getHealthEndpoint(webEndpointsSupplier);
|
||||
return new JerseyAdditionalHealthEndpointPathsResourcesRegistrar(health, healthEndpointGroups);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(ResourceConfig.class)
|
||||
@EnableConfigurationProperties(JerseyProperties.class)
|
||||
static class JerseyInfrastructureConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(JerseyApplicationPath.class)
|
||||
JerseyApplicationPath jerseyApplicationPath(JerseyProperties properties, ResourceConfig config) {
|
||||
return new DefaultJerseyApplicationPath(properties.getApplicationPath(), config);
|
||||
}
|
||||
|
||||
@Bean
|
||||
ResourceConfig resourceConfig(ObjectProvider<ResourceConfigCustomizer> resourceConfigCustomizers) {
|
||||
ResourceConfig resourceConfig = new ResourceConfig();
|
||||
resourceConfigCustomizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig));
|
||||
return resourceConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ServletRegistrationBean<ServletContainer> jerseyServletRegistration(
|
||||
JerseyApplicationPath jerseyApplicationPath, ResourceConfig resourceConfig) {
|
||||
return new ServletRegistrationBean<>(new ServletContainer(resourceConfig),
|
||||
jerseyApplicationPath.getUrlMapping());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class JerseyAdditionalHealthEndpointPathsResourcesRegistrar implements ResourceConfigCustomizer {
|
||||
|
||||
private final ExposableWebEndpoint endpoint;
|
||||
|
||||
private final HealthEndpointGroups groups;
|
||||
|
||||
JerseyAdditionalHealthEndpointPathsResourcesRegistrar(ExposableWebEndpoint endpoint,
|
||||
HealthEndpointGroups groups) {
|
||||
this.endpoint = endpoint;
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(ResourceConfig config) {
|
||||
register(config);
|
||||
}
|
||||
|
||||
private void register(ResourceConfig config) {
|
||||
EndpointMapping mapping = new EndpointMapping("");
|
||||
JerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(
|
||||
WebServerNamespace.SERVER, this.groups);
|
||||
Collection<Resource> endpointResources = resourceFactory
|
||||
.createEndpointResources(mapping, Collections.singletonList(this.endpoint), null, null, false)
|
||||
.stream().filter(Objects::nonNull).collect(Collectors.toList());
|
||||
register(endpointResources, config);
|
||||
}
|
||||
|
||||
private void register(Collection<Resource> resources, ResourceConfig config) {
|
||||
config.registerResources(new HashSet<>(resources));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,7 +32,7 @@ import static org.mockito.Mockito.mock;
|
||||
*/
|
||||
class AvailabilityProbesHealthEndpointGroupTests {
|
||||
|
||||
private AvailabilityProbesHealthEndpointGroup group = new AvailabilityProbesHealthEndpointGroup("a", "b");
|
||||
private AvailabilityProbesHealthEndpointGroup group = new AvailabilityProbesHealthEndpointGroup(null, "a", "b");
|
||||
|
||||
@Test
|
||||
void isMemberWhenMemberReturnsTrue() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,9 @@ import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroup;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -31,10 +33,12 @@ import static org.mockito.Mockito.mock;
|
||||
* Tests for {@link AvailabilityProbesHealthEndpointGroupsPostProcessor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class AvailabilityProbesHealthEndpointGroupsPostProcessorTests {
|
||||
|
||||
private AvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor();
|
||||
private AvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor(
|
||||
new MockEnvironment());
|
||||
|
||||
@Test
|
||||
void postProcessHealthEndpointGroupsWhenGroupsAlreadyContainedReturnsOriginal() {
|
||||
@@ -68,7 +72,43 @@ class AvailabilityProbesHealthEndpointGroupsPostProcessorTests {
|
||||
given(groups.getNames()).willReturn(names);
|
||||
assertThat(this.postProcessor.postProcessHealthEndpointGroups(groups))
|
||||
.isInstanceOf(AvailabilityProbesHealthEndpointGroups.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void postProcessHealthEndpointGroupsWhenAdditionalPathPropertyIsTrue() {
|
||||
HealthEndpointGroups postProcessed = getPostProcessed("true");
|
||||
HealthEndpointGroup liveness = postProcessed.get("liveness");
|
||||
HealthEndpointGroup readiness = postProcessed.get("readiness");
|
||||
assertThat(liveness.getAdditionalPath().toString()).isEqualTo("server:/livez");
|
||||
assertThat(readiness.getAdditionalPath().toString()).isEqualTo("server:/readyz");
|
||||
}
|
||||
|
||||
private HealthEndpointGroups getPostProcessed(String value) {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("management.endpoint.health.probes.add-additional-paths", value);
|
||||
AvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor(
|
||||
environment);
|
||||
HealthEndpointGroups groups = mock(HealthEndpointGroups.class);
|
||||
return postProcessor.postProcessHealthEndpointGroups(groups);
|
||||
}
|
||||
|
||||
@Test
|
||||
void postProcessHealthEndpointGroupsWhenAdditionalPathPropertyIsFalse() {
|
||||
HealthEndpointGroups postProcessed = getPostProcessed("false");
|
||||
HealthEndpointGroup liveness = postProcessed.get("liveness");
|
||||
HealthEndpointGroup readiness = postProcessed.get("readiness");
|
||||
assertThat(liveness.getAdditionalPath()).isNull();
|
||||
assertThat(readiness.getAdditionalPath()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void postProcessHealthEndpointGroupsWhenAdditionalPathPropertyIsNull() {
|
||||
HealthEndpointGroups groups = mock(HealthEndpointGroups.class);
|
||||
HealthEndpointGroups postProcessed = this.postProcessor.postProcessHealthEndpointGroups(groups);
|
||||
HealthEndpointGroup liveness = postProcessed.get("liveness");
|
||||
HealthEndpointGroup readiness = postProcessed.get("readiness");
|
||||
assertThat(liveness.getAdditionalPath()).isNull();
|
||||
assertThat(readiness.getAdditionalPath()).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,46 +50,46 @@ class AvailabilityProbesHealthEndpointGroupsTests {
|
||||
|
||||
@Test
|
||||
void createWhenGroupsIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new AvailabilityProbesHealthEndpointGroups(null))
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new AvailabilityProbesHealthEndpointGroups(null, false))
|
||||
.withMessage("Groups must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPrimaryDelegatesToGroups() {
|
||||
given(this.delegate.getPrimary()).willReturn(this.group);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);
|
||||
assertThat(availabilityProbes.getPrimary()).isEqualTo(this.group);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getNamesIncludesAvailabilityProbeGroups() {
|
||||
given(this.delegate.getNames()).willReturn(Collections.singleton("test"));
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);
|
||||
assertThat(availabilityProbes.getNames()).containsExactly("test", "liveness", "readiness");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWhenProbeInDelegateReturnsGroupFromDelegate() {
|
||||
given(this.delegate.get("liveness")).willReturn(this.group);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);
|
||||
assertThat(availabilityProbes.get("liveness")).isEqualTo(this.group);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWhenProbeNotInDelegateReturnsProbeGroup() {
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);
|
||||
assertThat(availabilityProbes.get("liveness")).isInstanceOf(AvailabilityProbesHealthEndpointGroup.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWhenNotProbeAndNotInDelegateReturnsNull() {
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);
|
||||
assertThat(availabilityProbes.get("mygroup")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLivenessProbeHasOnlyLivenessStateAsMember() {
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);
|
||||
HealthEndpointGroup probeGroup = availabilityProbes.get("liveness");
|
||||
assertThat(probeGroup.isMember("livenessState")).isTrue();
|
||||
assertThat(probeGroup.isMember("readinessState")).isFalse();
|
||||
@@ -97,7 +97,7 @@ class AvailabilityProbesHealthEndpointGroupsTests {
|
||||
|
||||
@Test
|
||||
void getReadinessProbeHasOnlyReadinessStateAsMember() {
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate);
|
||||
HealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);
|
||||
HealthEndpointGroup probeGroup = availabilityProbes.get("readiness");
|
||||
assertThat(probeGroup.isMember("livenessState")).isFalse();
|
||||
assertThat(probeGroup.isMember("readinessState")).isTrue();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,7 @@ import javax.sql.DataSource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthContributor;
|
||||
import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
@@ -164,6 +165,11 @@ class HealthEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
|
||||
return this.httpCodeStatusMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdditionalHealthEndpointPath getAdditionalPath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -59,7 +59,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
@Test
|
||||
void isMemberWhenMemberPredicateMatchesAcceptsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> name.startsWith("a"),
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);
|
||||
assertThat(group.isMember("albert")).isTrue();
|
||||
assertThat(group.isMember("arnold")).isTrue();
|
||||
}
|
||||
@@ -67,7 +67,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
@Test
|
||||
void isMemberWhenMemberPredicateRejectsReturnsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> name.startsWith("a"),
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);
|
||||
assertThat(group.isMember("bert")).isFalse();
|
||||
assertThat(group.isMember("ernie")).isFalse();
|
||||
}
|
||||
@@ -75,21 +75,22 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
@Test
|
||||
void showDetailsWhenShowDetailsIsNeverReturnsFalse() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.NEVER, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.NEVER, Collections.emptySet(), null);
|
||||
assertThat(group.showDetails(SecurityContext.NONE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void showDetailsWhenShowDetailsIsAlwaysReturnsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);
|
||||
assertThat(group.showDetails(SecurityContext.NONE)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void showDetailsWhenShowDetailsIsWhenAuthorizedAndPrincipalIsNullReturnsFalse() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED, Collections.emptySet(),
|
||||
null);
|
||||
given(this.securityContext.getPrincipal()).willReturn(null);
|
||||
assertThat(group.showDetails(this.securityContext)).isFalse();
|
||||
}
|
||||
@@ -97,7 +98,8 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
@Test
|
||||
void showDetailsWhenShowDetailsIsWhenAuthorizedAndRolesAreEmptyReturnsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED, Collections.emptySet(),
|
||||
null);
|
||||
given(this.securityContext.getPrincipal()).willReturn(this.principal);
|
||||
assertThat(group.showDetails(this.securityContext)).isTrue();
|
||||
}
|
||||
@@ -106,7 +108,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showDetailsWhenShowDetailsIsWhenAuthorizedAndUseIsInRoleReturnsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED,
|
||||
Arrays.asList("admin", "root", "bossmode"));
|
||||
Arrays.asList("admin", "root", "bossmode"), null);
|
||||
given(this.securityContext.getPrincipal()).willReturn(this.principal);
|
||||
given(this.securityContext.isUserInRole("admin")).willReturn(false);
|
||||
given(this.securityContext.isUserInRole("root")).willReturn(true);
|
||||
@@ -117,7 +119,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showDetailsWhenShowDetailsIsWhenAuthorizedAndUserIsNotInRoleReturnsFalse() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED,
|
||||
Arrays.asList("admin", "root", "bossmode"));
|
||||
Arrays.asList("admin", "root", "bossmode"), null);
|
||||
given(this.securityContext.getPrincipal()).willReturn(this.principal);
|
||||
assertThat(group.showDetails(this.securityContext)).isFalse();
|
||||
}
|
||||
@@ -126,7 +128,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showDetailsWhenShowDetailsIsWhenAuthorizedAndUserHasRightAuthorityReturnsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED,
|
||||
Arrays.asList("admin", "root", "bossmode"));
|
||||
Arrays.asList("admin", "root", "bossmode"), null);
|
||||
Authentication principal = mock(Authentication.class);
|
||||
given(principal.getAuthorities())
|
||||
.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority("admin")));
|
||||
@@ -138,7 +140,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showDetailsWhenShowDetailsIsWhenAuthorizedAndUserDoesNotHaveRightAuthoritiesReturnsFalse() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED,
|
||||
Arrays.asList("admin", "rot", "bossmode"));
|
||||
Arrays.asList("admin", "rot", "bossmode"), null);
|
||||
Authentication principal = mock(Authentication.class);
|
||||
given(principal.getAuthorities())
|
||||
.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority("other")));
|
||||
@@ -149,24 +151,26 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
@Test
|
||||
void showComponentsWhenShowComponentsIsNullDelegatesToShowDetails() {
|
||||
AutoConfiguredHealthEndpointGroup alwaysGroup = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);
|
||||
assertThat(alwaysGroup.showComponents(SecurityContext.NONE)).isTrue();
|
||||
AutoConfiguredHealthEndpointGroup neverGroup = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.NEVER, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.NEVER, Collections.emptySet(), null);
|
||||
assertThat(neverGroup.showComponents(SecurityContext.NONE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void showComponentsWhenShowComponentsIsNeverReturnsFalse() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.NEVER, Show.ALWAYS, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.NEVER, Show.ALWAYS, Collections.emptySet(),
|
||||
null);
|
||||
assertThat(group.showComponents(SecurityContext.NONE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void showComponentsWhenShowComponentsIsAlwaysReturnsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.ALWAYS, Show.NEVER, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.ALWAYS, Show.NEVER, Collections.emptySet(),
|
||||
null);
|
||||
assertThat(group.showComponents(SecurityContext.NONE)).isTrue();
|
||||
}
|
||||
|
||||
@@ -174,7 +178,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showComponentsWhenShowComponentsIsWhenAuthorizedAndPrincipalIsNullReturnsFalse() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,
|
||||
Collections.emptySet());
|
||||
Collections.emptySet(), null);
|
||||
given(this.securityContext.getPrincipal()).willReturn(null);
|
||||
assertThat(group.showComponents(this.securityContext)).isFalse();
|
||||
}
|
||||
@@ -183,7 +187,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showComponentsWhenShowComponentsIsWhenAuthorizedAndRolesAreEmptyReturnsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,
|
||||
Collections.emptySet());
|
||||
Collections.emptySet(), null);
|
||||
given(this.securityContext.getPrincipal()).willReturn(this.principal);
|
||||
assertThat(group.showComponents(this.securityContext)).isTrue();
|
||||
}
|
||||
@@ -192,7 +196,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showComponentsWhenShowComponentsIsWhenAuthorizedAndUseIsInRoleReturnsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,
|
||||
Arrays.asList("admin", "root", "bossmode"));
|
||||
Arrays.asList("admin", "root", "bossmode"), null);
|
||||
given(this.securityContext.getPrincipal()).willReturn(this.principal);
|
||||
given(this.securityContext.isUserInRole("admin")).willReturn(false);
|
||||
given(this.securityContext.isUserInRole("root")).willReturn(true);
|
||||
@@ -203,7 +207,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showComponentsWhenShowComponentsIsWhenAuthorizedAndUserIsNotInRoleReturnsFalse() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,
|
||||
Arrays.asList("admin", "rot", "bossmode"));
|
||||
Arrays.asList("admin", "rot", "bossmode"), null);
|
||||
given(this.securityContext.getPrincipal()).willReturn(this.principal);
|
||||
assertThat(group.showComponents(this.securityContext)).isFalse();
|
||||
}
|
||||
@@ -212,7 +216,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showComponentsWhenShowComponentsIsWhenAuthorizedAndUserHasRightAuthoritiesReturnsTrue() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,
|
||||
Arrays.asList("admin", "root", "bossmode"));
|
||||
Arrays.asList("admin", "root", "bossmode"), null);
|
||||
Authentication principal = mock(Authentication.class);
|
||||
given(principal.getAuthorities())
|
||||
.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority("admin")));
|
||||
@@ -224,7 +228,7 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
void showComponentsWhenShowComponentsIsWhenAuthorizedAndUserDoesNotHaveRightAuthoritiesReturnsFalse() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,
|
||||
Arrays.asList("admin", "rot", "bossmode"));
|
||||
Arrays.asList("admin", "rot", "bossmode"), null);
|
||||
Authentication principal = mock(Authentication.class);
|
||||
given(principal.getAuthorities())
|
||||
.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority("other")));
|
||||
@@ -235,14 +239,14 @@ class AutoConfiguredHealthEndpointGroupTests {
|
||||
@Test
|
||||
void getStatusAggregatorReturnsStatusAggregator() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);
|
||||
assertThat(group.getStatusAggregator()).isSameAs(this.statusAggregator);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHttpCodeStatusMapperReturnsHttpCodeStatusMapper() {
|
||||
AutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet());
|
||||
this.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);
|
||||
assertThat(group.getHttpCodeStatusMapper()).isSameAs(this.httpCodeStatusMapper);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,12 @@ import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.DefaultReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
@@ -69,8 +72,10 @@ class HealthEndpointAutoConfigurationTests {
|
||||
.of(HealthContributorAutoConfiguration.class, HealthEndpointAutoConfiguration.class));
|
||||
|
||||
private final ReactiveWebApplicationContextRunner reactiveContextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withUserConfiguration(HealthIndicatorsConfiguration.class).withConfiguration(AutoConfigurations
|
||||
.of(HealthContributorAutoConfiguration.class, HealthEndpointAutoConfiguration.class));
|
||||
.withUserConfiguration(HealthIndicatorsConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,
|
||||
HealthEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void runWhenHealthEndpointIsDisabledDoesNotCreateBeans() {
|
||||
@@ -208,8 +213,8 @@ class HealthEndpointAutoConfigurationTests {
|
||||
void runCreatesHealthEndpointWebExtension() {
|
||||
this.contextRunner.run((context) -> {
|
||||
HealthEndpointWebExtension webExtension = context.getBean(HealthEndpointWebExtension.class);
|
||||
WebEndpointResponse<HealthComponent> response = webExtension.health(ApiVersion.V3, SecurityContext.NONE,
|
||||
true, "simple");
|
||||
WebEndpointResponse<HealthComponent> response = webExtension.health(ApiVersion.V3,
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, true, "simple");
|
||||
Health health = (Health) response.getBody();
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
assertThat(health.getDetails()).containsEntry("counter", 42);
|
||||
@@ -220,8 +225,8 @@ class HealthEndpointAutoConfigurationTests {
|
||||
void runWhenHasHealthEndpointWebExtensionBeanDoesNotCreateExtraHealthEndpointWebExtension() {
|
||||
this.contextRunner.withUserConfiguration(HealthEndpointWebExtensionConfiguration.class).run((context) -> {
|
||||
HealthEndpointWebExtension webExtension = context.getBean(HealthEndpointWebExtension.class);
|
||||
WebEndpointResponse<HealthComponent> response = webExtension.health(ApiVersion.V3, SecurityContext.NONE,
|
||||
true, "simple");
|
||||
WebEndpointResponse<HealthComponent> response = webExtension.health(ApiVersion.V3,
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, true, "simple");
|
||||
assertThat(response).isNull();
|
||||
});
|
||||
}
|
||||
@@ -231,7 +236,7 @@ class HealthEndpointAutoConfigurationTests {
|
||||
this.reactiveContextRunner.run((context) -> {
|
||||
ReactiveHealthEndpointWebExtension webExtension = context.getBean(ReactiveHealthEndpointWebExtension.class);
|
||||
Mono<WebEndpointResponse<? extends HealthComponent>> response = webExtension.health(ApiVersion.V3,
|
||||
SecurityContext.NONE, true, "simple");
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, true, "simple");
|
||||
Health health = (Health) (response.block().getBody());
|
||||
assertThat(health.getDetails()).containsEntry("counter", 42);
|
||||
});
|
||||
@@ -244,7 +249,7 @@ class HealthEndpointAutoConfigurationTests {
|
||||
ReactiveHealthEndpointWebExtension webExtension = context
|
||||
.getBean(ReactiveHealthEndpointWebExtension.class);
|
||||
Mono<WebEndpointResponse<? extends HealthComponent>> response = webExtension.health(ApiVersion.V3,
|
||||
SecurityContext.NONE, true, "simple");
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, true, "simple");
|
||||
assertThat(response).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.integrationtest;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;
|
||||
import org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;
|
||||
import org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
/**
|
||||
* Abstract base class for health groups with an additional path.
|
||||
*
|
||||
* @param <T> the runner
|
||||
* @param <C> the application context type
|
||||
* @param <A> the assertions
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
abstract class AbstractHealthEndpointAdditionalPathIntegrationTests<T extends AbstractApplicationContextRunner<T, C, A>, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider<C>> {
|
||||
|
||||
private final T runner;
|
||||
|
||||
AbstractHealthEndpointAdditionalPathIntegrationTests(T runner) {
|
||||
this.runner = runner;
|
||||
}
|
||||
|
||||
@Test
|
||||
void groupIsAvailableAtAdditionalPath() {
|
||||
this.runner
|
||||
.withPropertyValues("management.endpoint.health.group.live.include=diskSpace",
|
||||
"management.endpoint.health.group.live.additional-path=server:/healthz",
|
||||
"management.endpoint.health.group.live.show-components=always")
|
||||
.run(withWebTestClient(this::testResponse, "local.server.port"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void groupIsAvailableAtAdditionalPathWithoutSlash() {
|
||||
this.runner
|
||||
.withPropertyValues("management.endpoint.health.group.live.include=diskSpace",
|
||||
"management.endpoint.health.group.live.additional-path=server:healthz",
|
||||
"management.endpoint.health.group.live.show-components=always")
|
||||
.run(withWebTestClient(this::testResponse, "local.server.port"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void groupIsAvailableAtAdditionalPathOnManagementPort() {
|
||||
this.runner.withPropertyValues("management.endpoint.health.group.live.include=diskSpace",
|
||||
"management.server.port=0", "management.endpoint.health.group.live.additional-path=management:healthz",
|
||||
"management.endpoint.health.group.live.show-components=always")
|
||||
.run(withWebTestClient(this::testResponse, "local.management.port"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void groupIsAvailableAtAdditionalPathOnServerPortWithDifferentManagementPort() {
|
||||
this.runner.withPropertyValues("management.endpoint.health.group.live.include=diskSpace",
|
||||
"management.server.port=0", "management.endpoint.health.group.live.additional-path=server:healthz",
|
||||
"management.endpoint.health.group.live.show-components=always")
|
||||
.withInitializer(new ConditionEvaluationReportLoggingListener())
|
||||
.run(withWebTestClient(this::testResponse, "local.server.port"));
|
||||
}
|
||||
|
||||
private void testResponse(WebTestClient client) {
|
||||
client.get().uri("/healthz").accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk().expectBody()
|
||||
.jsonPath("status").isEqualTo("UP").jsonPath("components.diskSpace").exists();
|
||||
}
|
||||
|
||||
private ContextConsumer<A> withWebTestClient(Consumer<WebTestClient> consumer, String property) {
|
||||
return (context) -> {
|
||||
String port = context.getEnvironment().getProperty(property);
|
||||
WebTestClient client = WebTestClient.bindToServer().baseUrl("http://localhost:" + port).build();
|
||||
consumer.accept(client);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.integrationtest;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer;
|
||||
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* Integration tests for health groups on an additional path on Jersey.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class JerseyHealthEndpointAdditionalPathIntegrationTests extends
|
||||
AbstractHealthEndpointAdditionalPathIntegrationTests<WebApplicationContextRunner, ConfigurableWebApplicationContext, AssertableWebApplicationContext> {
|
||||
|
||||
JerseyHealthEndpointAdditionalPathIntegrationTests() {
|
||||
super(new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, JerseyAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, ServletWebServerFactoryAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, JerseyAutoConfiguration.class,
|
||||
ManagementContextAutoConfiguration.class, ServletManagementContextAutoConfiguration.class,
|
||||
HealthEndpointAutoConfiguration.class, DiskSpaceHealthContributorAutoConfiguration.class))
|
||||
.withInitializer(new ServerPortInfoApplicationContextInitializer())
|
||||
.withClassLoader(new FilteredClassLoader(DispatcherServlet.class)).withPropertyValues("server.port=0"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.integrationtest;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer;
|
||||
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
|
||||
/**
|
||||
* Integration tests for MVC health groups on an additional path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class WebMvcHealthEndpointAdditionalPathIntegrationTests extends
|
||||
AbstractHealthEndpointAdditionalPathIntegrationTests<WebApplicationContextRunner, ConfigurableWebApplicationContext, AssertableWebApplicationContext> {
|
||||
|
||||
WebMvcHealthEndpointAdditionalPathIntegrationTests() {
|
||||
super(new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, ManagementContextAutoConfiguration.class,
|
||||
ServletWebServerFactoryAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
ServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
|
||||
HealthEndpointAutoConfiguration.class, DiskSpaceHealthContributorAutoConfiguration.class))
|
||||
.withInitializer(new ServerPortInfoApplicationContextInitializer())
|
||||
.withPropertyValues("server.port=0"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.integrationtest;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
|
||||
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer;
|
||||
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
|
||||
import org.springframework.boot.web.reactive.context.ConfigurableReactiveWebApplicationContext;
|
||||
|
||||
/**
|
||||
* Integration tests for Webflux health groups on an additional path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class WebfluxHealthEndpointAdditionalPathIntegrationTests extends
|
||||
AbstractHealthEndpointAdditionalPathIntegrationTests<ReactiveWebApplicationContextRunner, ConfigurableReactiveWebApplicationContext, AssertableReactiveWebApplicationContext> {
|
||||
|
||||
WebfluxHealthEndpointAdditionalPathIntegrationTests() {
|
||||
super(new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)
|
||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, CodecsAutoConfiguration.class,
|
||||
WebFluxAutoConfiguration.class, HttpHandlerAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, HealthEndpointAutoConfiguration.class,
|
||||
DiskSpaceHealthContributorAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
ManagementContextAutoConfiguration.class, ReactiveWebServerFactoryAutoConfiguration.class,
|
||||
ReactiveManagementContextAutoConfiguration.class, BeansEndpointAutoConfiguration.class))
|
||||
.withInitializer(new ServerPortInfoApplicationContextInitializer())
|
||||
.withPropertyValues("server.port=0"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user