Skip to content

Commit 9e95483

Browse files
committed
Add cloudfoundry health extensions
Fixes gh-11192
1 parent 1bdd42e commit 9e95483

File tree

15 files changed

+577
-13
lines changed

15 files changed

+577
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.cloudfoundry;
18+
19+
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
20+
import org.springframework.boot.actuate.endpoint.EndpointFilter;
21+
import org.springframework.boot.actuate.endpoint.EndpointInfo;
22+
import org.springframework.boot.actuate.endpoint.web.WebOperation;
23+
24+
/**
25+
* {@link EndpointFilter} for endpoints discovered by
26+
* {@link CloudFoundryWebAnnotationEndpointDiscoverer}.
27+
*
28+
* @author Madhura Bhave
29+
*/
30+
public class CloudFoundryEndpointFilter implements EndpointFilter<WebOperation> {
31+
32+
@Override
33+
public boolean match(EndpointInfo<WebOperation> info, EndpointDiscoverer<WebOperation> discoverer) {
34+
return (discoverer instanceof CloudFoundryWebAnnotationEndpointDiscoverer);
35+
}
36+
37+
}
38+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.cloudfoundry;
18+
19+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.CloudFoundryReactiveHealthEndpointWebExtension;
20+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.ReactiveCloudFoundryActuatorAutoConfiguration;
21+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration;
22+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryHealthEndpointWebExtension;
23+
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
24+
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
25+
import org.springframework.boot.actuate.health.HealthEndpoint;
26+
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
27+
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
28+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
29+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
31+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
32+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
33+
import org.springframework.context.annotation.Bean;
34+
import org.springframework.context.annotation.Configuration;
35+
36+
/**
37+
* Configuration for Cloud Foundry Health endpoint extensions.
38+
*
39+
* @author Madhura Bhave
40+
*/
41+
@Configuration
42+
@AutoConfigureBefore({ ReactiveCloudFoundryActuatorAutoConfiguration.class, CloudFoundryActuatorAutoConfiguration.class })
43+
@AutoConfigureAfter(HealthEndpointAutoConfiguration.class)
44+
public class CloudFoundryHealthWebEndpointManagementContextConfiguration {
45+
46+
@Configuration
47+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
48+
static class ServletWebHealthConfiguration {
49+
50+
@Bean
51+
@ConditionalOnMissingBean
52+
@ConditionalOnEnabledEndpoint
53+
@ConditionalOnBean(HealthEndpoint.class)
54+
public CloudFoundryHealthEndpointWebExtension cloudFoundryHealthEndpointWebExtension(
55+
HealthEndpoint healthEndpoint, HealthStatusHttpMapper healthStatusHttpMapper) {
56+
HealthEndpoint delegate = new HealthEndpoint(healthEndpoint.getHealthIndicator(), true);
57+
return new CloudFoundryHealthEndpointWebExtension(delegate, healthStatusHttpMapper);
58+
}
59+
60+
}
61+
62+
@Configuration
63+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
64+
static class ReactiveWebHealthConfiguration {
65+
66+
@Bean
67+
@ConditionalOnMissingBean
68+
@ConditionalOnEnabledEndpoint
69+
@ConditionalOnBean(HealthEndpoint.class)
70+
public CloudFoundryReactiveHealthEndpointWebExtension cloudFoundryReactiveHealthEndpointWebExtension(
71+
ReactiveHealthIndicator reactiveHealthIndicator,
72+
HealthStatusHttpMapper healthStatusHttpMapper) {
73+
return new CloudFoundryReactiveHealthEndpointWebExtension(reactiveHealthIndicator,
74+
healthStatusHttpMapper);
75+
}
76+
77+
}
78+
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.cloudfoundry;
18+
19+
import java.util.Collection;
20+
import java.util.Map;
21+
22+
import org.springframework.boot.actuate.endpoint.EndpointFilter;
23+
import org.springframework.boot.actuate.endpoint.reflect.OperationMethodInvokerAdvisor;
24+
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
25+
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
26+
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
27+
import org.springframework.boot.actuate.endpoint.web.WebOperation;
28+
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
29+
import org.springframework.boot.actuate.health.HealthEndpoint;
30+
import org.springframework.context.ApplicationContext;
31+
32+
/**
33+
* {@link WebAnnotationEndpointDiscoverer} for Cloud Foundry that uses Cloud Foundry specific
34+
* extensions for the {@link HealthEndpoint}.
35+
*
36+
* @author Madhura Bhave
37+
*/
38+
public class CloudFoundryWebAnnotationEndpointDiscoverer extends WebAnnotationEndpointDiscoverer {
39+
40+
private final ApplicationContext applicationContext;
41+
42+
private final Class<?> requiredExtensionType;
43+
44+
public CloudFoundryWebAnnotationEndpointDiscoverer(ApplicationContext applicationContext, ParameterMapper parameterMapper,
45+
EndpointMediaTypes endpointMediaTypes, EndpointPathResolver endpointPathResolver,
46+
Collection<? extends OperationMethodInvokerAdvisor> invokerAdvisors, Collection<? extends EndpointFilter<WebOperation>> filters, Class<?> requiredExtensionType) {
47+
super(applicationContext, parameterMapper, endpointMediaTypes, endpointPathResolver, invokerAdvisors, filters);
48+
this.applicationContext = applicationContext;
49+
this.requiredExtensionType = requiredExtensionType;
50+
}
51+
52+
@Override
53+
protected void addExtension(Map<Class<?>, DiscoveredEndpoint> endpoints, Map<Class<?>, DiscoveredExtension> extensions, String beanName) {
54+
Class<?> extensionType = this.applicationContext.getType(beanName);
55+
Class<?> endpointType = getEndpointType(extensionType);
56+
if (HealthEndpoint.class.equals(endpointType) && !this.requiredExtensionType.equals(extensionType)) {
57+
return;
58+
}
59+
super.addExtension(endpoints, extensions, beanName);
60+
}
61+
62+
}
63+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive;
18+
19+
import reactor.core.publisher.Mono;
20+
21+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryEndpointFilter;
22+
import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;
23+
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
24+
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
25+
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
26+
import org.springframework.boot.actuate.health.Health;
27+
import org.springframework.boot.actuate.health.HealthEndpoint;
28+
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
29+
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
30+
31+
/**
32+
* Reactive {@link EndpointWebExtension} for the {@link HealthEndpoint}
33+
* that always exposes full health details.
34+
*
35+
* @author Madhura Bhave
36+
*/
37+
@EndpointExtension(filter = CloudFoundryEndpointFilter.class, endpoint = HealthEndpoint.class)
38+
public class CloudFoundryReactiveHealthEndpointWebExtension {
39+
40+
private final ReactiveHealthIndicator delegate;
41+
42+
private final HealthStatusHttpMapper statusHttpMapper;
43+
44+
public CloudFoundryReactiveHealthEndpointWebExtension(ReactiveHealthIndicator delegate,
45+
HealthStatusHttpMapper statusHttpMapper) {
46+
this.delegate = delegate;
47+
this.statusHttpMapper = statusHttpMapper;
48+
}
49+
50+
@ReadOperation
51+
public Mono<WebEndpointResponse<Health>> health() {
52+
return this.delegate.health().map((health) -> {
53+
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
54+
return new WebEndpointResponse<>(health, status);
55+
});
56+
}
57+
58+
}
59+
60+

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfiguration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121

2222
import org.springframework.beans.BeansException;
2323
import org.springframework.beans.factory.config.BeanPostProcessor;
24+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryWebAnnotationEndpointDiscoverer;
2425
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
2526
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
2627
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
27-
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
2828
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2929
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3030
import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
@@ -68,9 +68,9 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
6868
public CloudFoundryWebFluxEndpointHandlerMapping cloudFoundryWebFluxEndpointHandlerMapping(
6969
ParameterMapper parameterMapper, EndpointMediaTypes endpointMediaTypes,
7070
WebClient.Builder webClientBuilder) {
71-
WebAnnotationEndpointDiscoverer endpointDiscoverer = new WebAnnotationEndpointDiscoverer(
71+
CloudFoundryWebAnnotationEndpointDiscoverer endpointDiscoverer = new CloudFoundryWebAnnotationEndpointDiscoverer(
7272
this.applicationContext, parameterMapper, endpointMediaTypes,
73-
EndpointPathResolver.useEndpointId(), null, null);
73+
EndpointPathResolver.useEndpointId(), null, null, CloudFoundryReactiveHealthEndpointWebExtension.class);
7474
ReactiveCloudFoundrySecurityInterceptor securityInterceptor = getSecurityInterceptor(
7575
webClientBuilder, this.applicationContext.getEnvironment());
7676
return new CloudFoundryWebFluxEndpointHandlerMapping(

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818

1919
import java.util.Arrays;
2020

21+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryWebAnnotationEndpointDiscoverer;
2122
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
2223
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
2324
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
2425
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
25-
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
2626
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2727
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2828
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -72,9 +72,9 @@ public class CloudFoundryActuatorAutoConfiguration {
7272
public CloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(
7373
ParameterMapper parameterMapper, EndpointMediaTypes endpointMediaTypes,
7474
RestTemplateBuilder restTemplateBuilder) {
75-
WebAnnotationEndpointDiscoverer endpointDiscoverer = new WebAnnotationEndpointDiscoverer(
75+
CloudFoundryWebAnnotationEndpointDiscoverer endpointDiscoverer = new CloudFoundryWebAnnotationEndpointDiscoverer(
7676
this.applicationContext, parameterMapper, endpointMediaTypes,
77-
EndpointPathResolver.useEndpointId(), null, null);
77+
EndpointPathResolver.useEndpointId(), null, null, CloudFoundryHealthEndpointWebExtension.class);
7878
CloudFoundrySecurityInterceptor securityInterceptor = getSecurityInterceptor(
7979
restTemplateBuilder, this.applicationContext.getEnvironment());
8080
return new CloudFoundryWebEndpointServletHandlerMapping(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet;
18+
19+
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryEndpointFilter;
20+
import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;
21+
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
22+
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
23+
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
24+
import org.springframework.boot.actuate.health.Health;
25+
import org.springframework.boot.actuate.health.HealthEndpoint;
26+
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
27+
28+
/**
29+
* {@link EndpointWebExtension} for the {@link HealthEndpoint}
30+
* that always exposes full health details.
31+
*
32+
* @author Madhura Bhave
33+
*/
34+
@EndpointExtension(filter = CloudFoundryEndpointFilter.class, endpoint = HealthEndpoint.class)
35+
public class CloudFoundryHealthEndpointWebExtension {
36+
37+
private final HealthEndpoint delegate;
38+
39+
private final HealthStatusHttpMapper statusHttpMapper;
40+
41+
public CloudFoundryHealthEndpointWebExtension(HealthEndpoint delegate,
42+
HealthStatusHttpMapper statusHttpMapper) {
43+
this.delegate = delegate;
44+
this.statusHttpMapper = statusHttpMapper;
45+
}
46+
47+
@ReadOperation
48+
public WebEndpointResponse<Health> getHealth() {
49+
Health health = this.delegate.health();
50+
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
51+
return new WebEndpointResponse<>(health, status);
52+
}
53+
54+
}
55+

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointManagementContextConfiguration.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,11 @@ public HealthStatusHttpMapper createHealthStatusHttpMapper(
6464
@ConditionalOnWebApplication(type = Type.REACTIVE)
6565
static class ReactiveWebHealthConfiguration {
6666

67-
private final ReactiveHealthIndicator reactiveHealthIndicator;
68-
69-
ReactiveWebHealthConfiguration(ObjectProvider<HealthAggregator> healthAggregator,
67+
@Bean
68+
public ReactiveHealthIndicator reactiveHealthIndicator(ObjectProvider<HealthAggregator> healthAggregator,
7069
ObjectProvider<Map<String, ReactiveHealthIndicator>> reactiveHealthIndicators,
7170
ObjectProvider<Map<String, HealthIndicator>> healthIndicators) {
72-
this.reactiveHealthIndicator = new CompositeReactiveHealthIndicatorFactory()
71+
return new CompositeReactiveHealthIndicatorFactory()
7372
.createReactiveHealthIndicator(
7473
healthAggregator.getIfAvailable(OrderedHealthAggregator::new),
7574
reactiveHealthIndicators
@@ -82,9 +81,10 @@ static class ReactiveWebHealthConfiguration {
8281
@ConditionalOnEnabledEndpoint
8382
@ConditionalOnBean(HealthEndpoint.class)
8483
public ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension(
84+
ReactiveHealthIndicator reactiveHealthIndicator,
8585
HealthStatusHttpMapper healthStatusHttpMapper,
8686
HealthEndpointProperties properties) {
87-
return new ReactiveHealthEndpointWebExtension(this.reactiveHealthIndicator,
87+
return new ReactiveHealthEndpointWebExtension(reactiveHealthIndicator,
8888
healthStatusHttpMapper, properties.isShowDetails());
8989
}
9090

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfigurat
66
org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthIndicatorAutoConfiguration,\
77
org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration,\
88
org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.ReactiveCloudFoundryActuatorAutoConfiguration,\
9+
org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryHealthWebEndpointManagementContextConfiguration,\
910
org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpointAutoConfiguration,\
1011
org.springframework.boot.actuate.autoconfigure.context.properties.ConfigurationPropertiesReportEndpointAutoConfiguration,\
1112
org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration,\

0 commit comments

Comments
 (0)