From bf5de108e26fcdcb5348ec98248cf10422ea27f8 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 10 May 2018 10:02:30 +0200 Subject: [PATCH] Stop exposing a duplicate web extension for the env endpoint An actuator endpoint is designed around a single class flagged with `@Endpoint`. Such endpoint can have some of its operations refined with a given tech (for instance via a `EndpointWebExtension` for web specific concerns). This design mandates that an endpoint (and its tech specific refinements are managed centrally to form a unified contract). As Spring Cloud is extending the standard Spring Boot's `env` endpoint, this commit introduces a WritableEnvironmentEndpoint with a web extension. Closes gh-367 Closes gh-354 --- ...LifecycleMvcEndpointAutoConfiguration.java | 34 +++------- .../RefreshEndpointAutoConfiguration.java | 3 +- ...eEnvironmentEndpointAutoConfiguration.java | 62 +++++++++++++++++++ .../WritableEnvironmentEndpoint.java | 19 ++++++ ...tableEnvironmentEndpointWebExtension.java} | 16 ++--- .../main/resources/META-INF/spring.factories | 3 +- .../EnvironmentManagerIntegrationTests.java | 10 ++- 7 files changed, 110 insertions(+), 37 deletions(-) create mode 100644 spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/WritableEnvironmentEndpointAutoConfiguration.java create mode 100644 spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/WritableEnvironmentEndpoint.java rename spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/{EnvironmentWebEndpointExtension.java => WritableEnvironmentEndpointWebExtension.java} (75%) diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/LifecycleMvcEndpointAutoConfiguration.java b/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/LifecycleMvcEndpointAutoConfiguration.java index 72be149e..0db22a8a 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/LifecycleMvcEndpointAutoConfiguration.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/LifecycleMvcEndpointAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2018 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. @@ -15,16 +15,10 @@ */ package org.springframework.cloud.autoconfigure; -import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; -import org.springframework.boot.actuate.env.EnvironmentEndpoint; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -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.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.cloud.context.environment.EnvironmentManager; -import org.springframework.cloud.context.environment.EnvironmentWebEndpointExtension; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.ConfigurableEnvironment; @@ -38,27 +32,13 @@ import org.springframework.core.env.ConfigurableEnvironment; * */ @Configuration -@AutoConfigureAfter({ WebMvcAutoConfiguration.class, - RefreshEndpointAutoConfiguration.class }) +@AutoConfigureAfter(WebMvcAutoConfiguration.class) public class LifecycleMvcEndpointAutoConfiguration { - @Bean - @ConditionalOnMissingBean - public EnvironmentManager environmentManager(ConfigurableEnvironment environment) { - return new EnvironmentManager(environment); - } - - @Configuration - @ConditionalOnClass(EnvironmentEndpoint.class) - @ConditionalOnWebApplication - protected static class EndpointConfiguration { - @Bean - @ConditionalOnBean(EnvironmentEndpoint.class) - @ConditionalOnEnabledEndpoint - public EnvironmentWebEndpointExtension environmentWebEndpointExtension( - EnvironmentManager environment) { - return new EnvironmentWebEndpointExtension(environment); - } - } + @Bean + @ConditionalOnMissingBean + public EnvironmentManager environmentManager(ConfigurableEnvironment environment) { + return new EnvironmentManager(environment); + } } diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/RefreshEndpointAutoConfiguration.java b/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/RefreshEndpointAutoConfiguration.java index eda8a027..4f440f91 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/RefreshEndpointAutoConfiguration.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/RefreshEndpointAutoConfiguration.java @@ -46,7 +46,8 @@ import org.springframework.integration.monitor.IntegrationMBeanExporter; */ @Configuration @ConditionalOnClass({EndpointAutoConfiguration.class, Health.class}) -@AutoConfigureAfter({EndpointAutoConfiguration.class, RefreshAutoConfiguration.class}) +@AutoConfigureAfter({ LifecycleMvcEndpointAutoConfiguration.class, + RefreshAutoConfiguration.class}) @Import({ RestartEndpointWithIntegrationConfiguration.class, RestartEndpointWithoutIntegrationConfiguration.class, PauseResumeEndpointsConfiguration.class }) diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/WritableEnvironmentEndpointAutoConfiguration.java b/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/WritableEnvironmentEndpointAutoConfiguration.java new file mode 100644 index 00000000..f3c7a5d2 --- /dev/null +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/autoconfigure/WritableEnvironmentEndpointAutoConfiguration.java @@ -0,0 +1,62 @@ +package org.springframework.cloud.autoconfigure; + +import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; +import org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointProperties; +import org.springframework.boot.actuate.env.EnvironmentEndpoint; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +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.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.context.environment.EnvironmentManager; +import org.springframework.cloud.context.environment.WritableEnvironmentEndpoint; +import org.springframework.cloud.context.environment.WritableEnvironmentEndpointWebExtension; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for the + * {@link WritableEnvironmentEndpoint}. + * + * @author Stephane Nicoll + * @since 2.0.0 + */ +@Configuration +@ConditionalOnClass({ EnvironmentEndpoint.class, EnvironmentEndpointProperties.class }) +@ConditionalOnBean(EnvironmentManager.class) +@AutoConfigureBefore(EnvironmentEndpointAutoConfiguration.class) +@AutoConfigureAfter(LifecycleMvcEndpointAutoConfiguration.class) +@EnableConfigurationProperties({ EnvironmentEndpointProperties.class }) +public class WritableEnvironmentEndpointAutoConfiguration { + + private final EnvironmentEndpointProperties properties; + + public WritableEnvironmentEndpointAutoConfiguration( + EnvironmentEndpointProperties properties) { + this.properties = properties; + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint + public WritableEnvironmentEndpoint environmentEndpoint(Environment environment) { + WritableEnvironmentEndpoint endpoint = new WritableEnvironmentEndpoint(environment); + String[] keysToSanitize = this.properties.getKeysToSanitize(); + if (keysToSanitize != null) { + endpoint.setKeysToSanitize(keysToSanitize); + } + return endpoint; + } + + @Bean + @ConditionalOnEnabledEndpoint + public WritableEnvironmentEndpointWebExtension environmentWebEndpointExtension( + WritableEnvironmentEndpoint endpoint, EnvironmentManager environment) { + return new WritableEnvironmentEndpointWebExtension(endpoint, environment); + } + +} diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/WritableEnvironmentEndpoint.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/WritableEnvironmentEndpoint.java new file mode 100644 index 00000000..86c98849 --- /dev/null +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/WritableEnvironmentEndpoint.java @@ -0,0 +1,19 @@ +package org.springframework.cloud.context.environment; + +import org.springframework.boot.actuate.env.EnvironmentEndpoint; +import org.springframework.core.env.Environment; + +/** + * An extension of the standard {@link EnvironmentEndpoint} that allows to modify the + * environment at runtime. + * + * @author Stephane Nicoll + * @since 2.0.0 + */ +public class WritableEnvironmentEndpoint extends EnvironmentEndpoint { + + public WritableEnvironmentEndpoint(Environment environment) { + super(environment); + } + +} diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/EnvironmentWebEndpointExtension.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/WritableEnvironmentEndpointWebExtension.java similarity index 75% rename from spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/EnvironmentWebEndpointExtension.java rename to spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/WritableEnvironmentEndpointWebExtension.java index 68096811..9a99193f 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/EnvironmentWebEndpointExtension.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/environment/WritableEnvironmentEndpointWebExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2018 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,8 +21,7 @@ import java.util.Map; import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation; import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension; -import org.springframework.boot.actuate.env.EnvironmentEndpoint; - +import org.springframework.boot.actuate.env.EnvironmentEndpointWebExtension; /** * MVC endpoint for the {@link EnvironmentManager} providing a POST to /env as a simple @@ -31,13 +30,16 @@ import org.springframework.boot.actuate.env.EnvironmentEndpoint; * @author Dave Syer * */ -@EndpointWebExtension(endpoint = EnvironmentEndpoint.class) -public class EnvironmentWebEndpointExtension { +@EndpointWebExtension(endpoint = WritableEnvironmentEndpoint.class) +public class WritableEnvironmentEndpointWebExtension + extends EnvironmentEndpointWebExtension { private EnvironmentManager environment; - public EnvironmentWebEndpointExtension(EnvironmentManager enviroment) { - environment = enviroment; + public WritableEnvironmentEndpointWebExtension(WritableEnvironmentEndpoint endpoint, + EnvironmentManager environment) { + super(endpoint); + this.environment = environment; } @WriteOperation diff --git a/spring-cloud-context/src/main/resources/META-INF/spring.factories b/spring-cloud-context/src/main/resources/META-INF/spring.factories index ddbc6cde..be5c5d76 100644 --- a/spring-cloud-context/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-context/src/main/resources/META-INF/spring.factories @@ -1,9 +1,10 @@ # AutoConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\ +org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration,\ org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\ org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\ -org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration +org.springframework.cloud.autoconfigure.WritableEnvironmentEndpointAutoConfiguration # Application Listeners org.springframework.context.ApplicationListener=\ diff --git a/spring-cloud-context/src/test/java/org/springframework/cloud/context/environment/EnvironmentManagerIntegrationTests.java b/spring-cloud-context/src/test/java/org/springframework/cloud/context/environment/EnvironmentManagerIntegrationTests.java index bf6a4030..60da5383 100644 --- a/spring-cloud-context/src/test/java/org/springframework/cloud/context/environment/EnvironmentManagerIntegrationTests.java +++ b/spring-cloud-context/src/test/java/org/springframework/cloud/context/environment/EnvironmentManagerIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2017 the original author or authors. + * Copyright 2006-2018 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. @@ -18,6 +18,7 @@ package org.springframework.cloud.context.environment; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import javax.servlet.ServletException; @@ -44,6 +45,7 @@ import org.springframework.web.context.WebApplicationContext; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -108,6 +110,12 @@ public class EnvironmentManagerIntegrationTests { assertEquals(0, properties.getDelay()); } + @Test + public void coreWebExtensionAvailable() throws Exception { + this.mvc.perform(get(BASE_PATH + "/env/" + UUID.randomUUID().toString())) + .andExpect(status().isNotFound()); + } + @Configuration @EnableAutoConfiguration protected static class TestConfiguration {