diff --git a/spring/microservices-externalized-config/greeting-service/pom.xml b/spring/microservices-externalized-config/greeting-service/pom.xml deleted file mode 100644 index 26137b3..0000000 --- a/spring/microservices-externalized-config/greeting-service/pom.xml +++ /dev/null @@ -1,159 +0,0 @@ - - - - 4.0.0 - spring-boot-configmap-greeting - io.openshift.booster - 1.0.0-SNAPSHOT - - Spring Boot - ConfigMap Booster - Greeting Service - Spring Boot - ConfigMap Booster - Greeting Service - - - 1.8 - 1.8 - UTF-8 - UTF-8 - - 3.3.9 - 9.4.1212 - 1.3 - - 2.1.6.RELEASE - 2.1.6.Final-redhat-00004 - 2.20 - 3.5.40 - true - true - - registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift:${openjdk18-openshift.version} - - 3.1.0 - 1.4.0.Final - 3.1.0 - - - - - - me.snowdrop - spring-boot-bom - ${spring-boot-bom.version} - pom - import - - - org.jboss.arquillian - arquillian-bom - ${arquillian.version} - pom - import - - - io.rest-assured - rest-assured - ${rest-assured.version} - - - org.awaitility - awaitility - ${awaitility.version} - - - - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - - org.springframework.boot - spring-boot-starter-test - test - - - io.rest-assured - rest-assured - test - - - org.jboss.arquillian.junit - arquillian-junit-standalone - test - - - org.awaitility - awaitility - test - - - org.assertj - assertj-core - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - - local - - exec - - - - - - - - openshift - - - org.springframework.cloud - spring-cloud-starter-kubernetes-config - - - - - - - io.fabric8 - fabric8-maven-plugin - ${fabric8-maven-plugin.version} - - - fmp - - resource - build - - - - - - - - - diff --git a/spring/microservices-externalized-config/greeting-service/src/main/etc/application.properties b/spring/microservices-externalized-config/greeting-service/src/main/etc/application.properties deleted file mode 100644 index 43665ec..0000000 --- a/spring/microservices-externalized-config/greeting-service/src/main/etc/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.application.name=spring-boot-configmap-greeting -greeting.message=Greetings, you picked %s as your favorite fruit! \ No newline at end of file diff --git a/spring/microservices-externalized-config/greeting-service/src/main/fabric8/configmap.yml b/spring/microservices-externalized-config/greeting-service/src/main/fabric8/configmap.yml deleted file mode 100644 index 66df3e9..0000000 --- a/spring/microservices-externalized-config/greeting-service/src/main/fabric8/configmap.yml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: app-config - labels: - app: spring-boot-configmap-greeting -data: - application.properties: |- - greeting.message=Hola, you picked %s as your favorite fruit! \ No newline at end of file diff --git a/spring/microservices-externalized-config/greeting-service/src/main/resources/bootstrap.properties b/spring/microservices-externalized-config/greeting-service/src/main/resources/bootstrap.properties deleted file mode 100644 index 9a7013a..0000000 --- a/spring/microservices-externalized-config/greeting-service/src/main/resources/bootstrap.properties +++ /dev/null @@ -1,5 +0,0 @@ -# bootstrap -spring.application.name=spring-boot-configmap-greeting -# Look for a Kube ConfigMap named app-config, and reload config when it changes -spring.cloud.kubernetes.config.name=app-config -spring.cloud.kubernetes.reload.enabled=true \ No newline at end of file diff --git a/spring/microservices-externalized-config/greeting-service/src/test/java/io/openshift/booster/BoosterApplicationTest.java b/spring/microservices-externalized-config/greeting-service/src/test/java/io/openshift/booster/BoosterApplicationTest.java deleted file mode 100644 index 2417502..0000000 --- a/spring/microservices-externalized-config/greeting-service/src/test/java/io/openshift/booster/BoosterApplicationTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 - *

- * http://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 io.openshift.booster; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.core.Is.is; - -import io.openshift.booster.service.MessageProperties; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class BoosterApplicationTest { - - protected static final String GREETING_PATH = "api/greeting"; - @Value("${local.server.port}") - private int port; - - @Autowired - private MessageProperties properties; - - @Test - public void testGreetingEndpoint() { - given() - .baseUri(String.format("http://localhost:%d", port)) - .get(GREETING_PATH) - .then() - .statusCode(200) - .body("content", is(String.format(properties.getMessage(), "Banana"))); - } - - @Test - public void testGreetingEndpointWithNameParameter() { - given() - .baseUri(String.format("http://localhost:%d", port)) - .param("name", "John") - .get(GREETING_PATH) - .then() - .statusCode(200) - .body("content", is(String.format(properties.getMessage(), "John"))); - } - -} \ No newline at end of file diff --git a/spring/microservices-externalized-config/greeting-service/src/test/resources/application.properties b/spring/microservices-externalized-config/greeting-service/src/test/resources/application.properties deleted file mode 100644 index e8d5bf4..0000000 --- a/spring/microservices-externalized-config/greeting-service/src/test/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -# Unit tests does not need config map -# spring.application.name=${project.artifactId} -greeting.message=Hello, %s! diff --git a/spring/microservices-externalized-config/greeting-service/src/test/resources/logback-test.xml b/spring/microservices-externalized-config/greeting-service/src/test/resources/logback-test.xml deleted file mode 100644 index 9f754ed..0000000 --- a/spring/microservices-externalized-config/greeting-service/src/test/resources/logback-test.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/spring/microservices-externalized-config/pom.xml b/spring/microservices-externalized-config/pom.xml index c6b926c..80fda11 100644 --- a/spring/microservices-externalized-config/pom.xml +++ b/spring/microservices-externalized-config/pom.xml @@ -1,31 +1,188 @@ - + + 4.0.0 + com.example + spring-boot-configmap-greeting + 1.0.0-SNAPSHOT + jar - 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 + spring-boot-configmap-greeting + Spring Boot Externalized Configuration - http://www.apache.org/licenses/LICENSE-2.0 + + 11 + 11 + UTF-8 + UTF-8 - 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. ---> - 4.0.0 + 3.3.9 - booster-configmap-spring-boot + 2.3.6.RELEASE + 2.3.6.Final-redhat-00001 - io.openshift.booster - 1.0.0-SNAPSHOT - pom + true + 1.3.0 + registry.redhat.io/ubi8/openjdk-11:latest + - Spring Boot - ConfigMap Booster - Spring Boot - ConfigMap Booster + + + + dev.snowdrop + snowdrop-dependencies + ${spring-boot-bom.version} + pom + import + + + - - greeting-service - + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.assertj + assertj-core + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + local + + exec + + + + + repackage + + + + + + + maven-surefire-plugin + 2.22.2 + + + + maven-failsafe-plugin + 2.22.2 + + + + maven-deploy-plugin + 2.8.2 + + + + + + + local + + true + + + + + openshift + + + org.springframework.cloud + spring-cloud-starter-kubernetes-config + + + + + + + org.eclipse.jkube + openshift-maven-plugin + ${jkube-maven-plugin.version} + + + jkmp + package + + resource + build + + + + + + + + + + + + jboss-ga-repository + https://maven.repository.redhat.com/ga + + true + daily + + + false + daily + + Red Hat GA + + + + + jboss-ga-repository + https://maven.repository.redhat.com/ga + + true + daily + + + false + daily + + Red Hat GA + + diff --git a/spring/microservices-externalized-config/greeting-service/src/main/resources/application.properties b/spring/microservices-externalized-config/src/main/etc/application.properties similarity index 53% rename from spring/microservices-externalized-config/greeting-service/src/main/resources/application.properties rename to spring/microservices-externalized-config/src/main/etc/application.properties index 43665ec..b4e6d5d 100644 --- a/spring/microservices-externalized-config/greeting-service/src/main/resources/application.properties +++ b/spring/microservices-externalized-config/src/main/etc/application.properties @@ -1,2 +1 @@ -spring.application.name=spring-boot-configmap-greeting -greeting.message=Greetings, you picked %s as your favorite fruit! \ No newline at end of file +greeting.message=Greetings, you picked %s as your favorite fruit! diff --git a/spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/BoosterApplication.java b/spring/microservices-externalized-config/src/main/java/com/example/ExternalizedConfigurationExample.java similarity index 75% rename from spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/BoosterApplication.java rename to spring/microservices-externalized-config/src/main/java/com/example/ExternalizedConfigurationExample.java index 598368e..c8012e9 100644 --- a/spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/BoosterApplication.java +++ b/spring/microservices-externalized-config/src/main/java/com/example/ExternalizedConfigurationExample.java @@ -14,15 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.openshift.booster; +package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +import com.example.service.MessageProperties; @SpringBootApplication -public class BoosterApplication { +@EnableConfigurationProperties(MessageProperties.class) +public class ExternalizedConfigurationExample { public static void main(String[] args) { - SpringApplication.run(BoosterApplication.class, args); + SpringApplication.run(ExternalizedConfigurationExample.class, args); } } diff --git a/spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/service/FruitController.java b/spring/microservices-externalized-config/src/main/java/com/example/service/FruitController.java similarity index 80% rename from spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/service/FruitController.java rename to spring/microservices-externalized-config/src/main/java/com/example/service/FruitController.java index e5add61..8ca80c9 100644 --- a/spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/service/FruitController.java +++ b/spring/microservices-externalized-config/src/main/java/com/example/service/FruitController.java @@ -14,26 +14,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.openshift.booster.service; - -import java.util.Objects; +package com.example.service; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController +@RequestMapping("/api") public class FruitController { - @Autowired private MessageProperties properties; - @RequestMapping("/api/greeting") + @GetMapping(path = "/greeting", produces = MediaType.APPLICATION_JSON_VALUE) public Message greeting(@RequestParam(value = "name", defaultValue = "Banana") String name) { - Objects.requireNonNull(properties.getMessage(), "Greeting message was not set in the properties"); - - String message = String.format(properties.getMessage(), name); + String message = String.format(this.properties.getMessage(), name); return new Message(message); } -} \ No newline at end of file +} diff --git a/spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/service/Message.java b/spring/microservices-externalized-config/src/main/java/com/example/service/Message.java similarity index 94% rename from spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/service/Message.java rename to spring/microservices-externalized-config/src/main/java/com/example/service/Message.java index 186a670..e829bd6 100644 --- a/spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/service/Message.java +++ b/spring/microservices-externalized-config/src/main/java/com/example/service/Message.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.openshift.booster.service; +package com.example.service; public class Message { @@ -29,6 +29,6 @@ public Message(String content) { } public String getContent() { - return content; + return this.content; } } diff --git a/spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/service/MessageProperties.java b/spring/microservices-externalized-config/src/main/java/com/example/service/MessageProperties.java similarity index 72% rename from spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/service/MessageProperties.java rename to spring/microservices-externalized-config/src/main/java/com/example/service/MessageProperties.java index c3cb229..2d4af52 100644 --- a/spring/microservices-externalized-config/greeting-service/src/main/java/io/openshift/booster/service/MessageProperties.java +++ b/spring/microservices-externalized-config/src/main/java/com/example/service/MessageProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 Red Hat, Inc, and individual contributors. + * Copyright 2021 Red Hat, Inc, and individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,24 +14,26 @@ * limitations under the License. */ -package io.openshift.booster.service; +package com.example.service; + +import javax.validation.constraints.NotBlank; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; -import org.springframework.stereotype.Component; +import org.springframework.validation.annotation.Validated; -@Component -@ConfigurationProperties(prefix = "greeting") +@ConfigurationProperties("greeting") +@Validated public class MessageProperties { /** * This message has to be set in the application.properties file. If application is executed locally, "local" profile is * expected. On OpenShift, this property is set by a ConfigMap. */ - private String message = null; + @NotBlank(message = "Greeting message was not set in the properties") + private String message; public String getMessage() { - return message; + return this.message; } public void setMessage(String message) { diff --git a/spring/microservices-externalized-config/greeting-service/src/main/fabric8/route.yml b/spring/microservices-externalized-config/src/main/jkube/route.yml similarity index 100% rename from spring/microservices-externalized-config/greeting-service/src/main/fabric8/route.yml rename to spring/microservices-externalized-config/src/main/jkube/route.yml diff --git a/spring/microservices-externalized-config/greeting-service/src/main/resources/application-local.properties b/spring/microservices-externalized-config/src/main/resources/application-local.properties similarity index 100% rename from spring/microservices-externalized-config/greeting-service/src/main/resources/application-local.properties rename to spring/microservices-externalized-config/src/main/resources/application-local.properties diff --git a/spring/microservices-externalized-config/src/main/resources/application.properties b/spring/microservices-externalized-config/src/main/resources/application.properties new file mode 100644 index 0000000..c71897a --- /dev/null +++ b/spring/microservices-externalized-config/src/main/resources/application.properties @@ -0,0 +1,9 @@ +# bootstrap +spring.application.name=spring-boot-configmap-greeting + +# Look for a Kube ConfigMap named spring-boot-configmap-greeting, and reload config when it changes +spring.cloud.kubernetes.config.enabled=true +spring.cloud.kubernetes.reload.enabled=true + +management.endpoints.web.exposure.include=* +management.endpoint.health.show-details:always diff --git a/spring/microservices-externalized-config/src/main/resources/bootstrap.properties b/spring/microservices-externalized-config/src/main/resources/bootstrap.properties new file mode 100644 index 0000000..08e668e --- /dev/null +++ b/spring/microservices-externalized-config/src/main/resources/bootstrap.properties @@ -0,0 +1,6 @@ +# bootstrap +spring.application.name=spring-boot-configmap-greeting + +# Look for a Kube ConfigMap named spring-boot-configmap-greeting, and reload config when it changes +spring.cloud.kubernetes.config.enabled=true +spring.cloud.kubernetes.reload.enabled=true diff --git a/spring/microservices-externalized-config/greeting-service/src/main/resources/static/index.html b/spring/microservices-externalized-config/src/main/resources/static/index.html similarity index 89% rename from spring/microservices-externalized-config/greeting-service/src/main/resources/static/index.html rename to spring/microservices-externalized-config/src/main/resources/static/index.html index dfc926d..39494e2 100644 --- a/spring/microservices-externalized-config/greeting-service/src/main/resources/static/index.html +++ b/spring/microservices-externalized-config/src/main/resources/static/index.html @@ -38,15 +38,14 @@

Result:

Reconfigure OpenShift ConfigMap

Open ConfigMap editor in your terminal:

-
oc edit configmap <CONFIGMAP_NAME>
+
oc edit configmap spring-boot-configmap-greeting

Replace the greeting.message

-
greeting.message: Bonjour %s from a ConfigMap!
+
greeting.message: Bonjour, you picked a %s from a ConfigMap!
-

And reload your application

-
oc rollout latest dc/<DEPLOYMENT_NAME>
+

And re-try the request. The new message should be automatically picked up

diff --git a/spring/microservices-externalized-config/src/test/java/com/example/service/FruitControllerTest.java b/spring/microservices-externalized-config/src/test/java/com/example/service/FruitControllerTest.java new file mode 100644 index 0000000..35ae8d1 --- /dev/null +++ b/spring/microservices-externalized-config/src/test/java/com/example/service/FruitControllerTest.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + *

+ * http://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 com.example.service; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +@SpringBootTest +@AutoConfigureMockMvc +public class FruitControllerTest { + protected static final String GREETING_PATH = "/api/greeting"; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private MessageProperties properties; + + @Test + public void testGreetingEndpoint() throws Exception { + this.mockMvc.perform(get(GREETING_PATH)) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("content").value((String.format(this.properties.getMessage(), "Banana")))); + } + + @Test + public void testGreetingEndpointWithNameParameter() throws Exception { + this.mockMvc.perform(get(GREETING_PATH).param("name", "John")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("content").value(String.format(this.properties.getMessage(), "John"))); + } +} diff --git a/spring/microservices-externalized-config/src/test/resources/application.properties b/spring/microservices-externalized-config/src/test/resources/application.properties new file mode 100644 index 0000000..3a96ea0 --- /dev/null +++ b/spring/microservices-externalized-config/src/test/resources/application.properties @@ -0,0 +1 @@ +greeting.message=Hello, %s!