fix 640 (#1032)
This commit is contained in:
@@ -65,8 +65,38 @@ of the application is resolved.
|
||||
Any matching `ConfigMap` that is found is processed as follows:
|
||||
|
||||
* Apply individual configuration properties.
|
||||
* Apply as `yaml` the content of any property named `application.yaml`.
|
||||
* Apply as a properties file the content of any property named `application.properties`.
|
||||
* Apply as `yaml` (or `properties`) the content of any property that is named by the value of `spring.application.name`
|
||||
(if it's not present, by `application.yaml/properties`)
|
||||
* Apply as a properties file the content of the above name + each active profile.
|
||||
|
||||
An example should make a lot more sense. Let's suppose that `spring.application.name=my-app` and that
|
||||
we have a single active profile called `k8s`. For a configuration as below:
|
||||
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-app
|
||||
data:
|
||||
my-app.yaml: |-
|
||||
...
|
||||
my-app-k8s.yaml: |-
|
||||
..
|
||||
my-app-dev.yaml: |-
|
||||
..
|
||||
someProp: someValue
|
||||
----
|
||||
====
|
||||
|
||||
These is what we will end-up loading:
|
||||
|
||||
- `my-app.yaml` treated as a file
|
||||
- `my-app-k8s.yaml` treated as a file
|
||||
- `my-app-dev.yaml` _ignored_, since `dev` is _not_ an active profile
|
||||
- `someProp: someValue` plain property
|
||||
|
||||
The single exception to the aforementioned flow is when the `ConfigMap` contains a *single* key that indicates
|
||||
the file is a YAML or properties file. In that case, the name of the key does NOT have to be `application.yaml` or
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.client.config.applications.single_source_multiple_files;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Color;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Name;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Shape;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Type;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties({ Name.class, Shape.class, Color.class, Type.class })
|
||||
public class SingleSourceMultipleFilesApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SingleSourceMultipleFilesApp.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.client.config.applications.single_source_multiple_files;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@ActiveProfiles("color")
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = SingleSourceMultipleFilesApp.class,
|
||||
properties = { "spring.cloud.bootstrap.name=single-source-multiple-files",
|
||||
"spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true",
|
||||
"spring.cloud.kubernetes.client.namespace=spring-k8s", "single.source.multiple.files.stub=true" })
|
||||
class SingleSourceMultipleFilesBootstrapTests extends SingleSourceMultipleFilesTests {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.client.config.applications.single_source_multiple_files;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.kubernetes.client.KubernetesClientUtils;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SingleSourceMultipleFilesConfigurationStub.stubData;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@ActiveProfiles("color")
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = SingleSourceMultipleFilesApp.class,
|
||||
properties = { "spring.main.cloud-platform=KUBERNETES",
|
||||
"spring.config.import=kubernetes:,classpath:./single-source-multiple-files.yaml",
|
||||
"spring.cloud.kubernetes.client.namespace=spring-k8s" })
|
||||
class SingleSourceMultipleFilesConfigDataTests extends SingleSourceMultipleFilesTests {
|
||||
|
||||
private static MockedStatic<KubernetesClientUtils> clientUtilsMock;
|
||||
|
||||
@BeforeAll
|
||||
static void wireMock() {
|
||||
WireMockServer server = new WireMockServer(options().dynamicPort());
|
||||
server.start();
|
||||
WireMock.configureFor("localhost", server.port());
|
||||
clientUtilsMock = mockStatic(KubernetesClientUtils.class);
|
||||
clientUtilsMock.when(KubernetesClientUtils::kubernetesApiClient)
|
||||
.thenReturn(new ClientBuilder().setBasePath(server.baseUrl()).build());
|
||||
stubData();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void teardown() {
|
||||
clientUtilsMock.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.client.config.applications.single_source_multiple_files;
|
||||
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*
|
||||
* Stub for this test is here :
|
||||
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SingleSourceMultipleFilesConfigurationStub}
|
||||
*
|
||||
* issue: https://github.com/spring-cloud/spring-cloud-kubernetes/issues/640
|
||||
*
|
||||
*/
|
||||
abstract class SingleSourceMultipleFilesTests {
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() {
|
||||
WireMock.shutdownServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* "fruit-color.properties" is taken since "spring.application.name=fruit" and
|
||||
* "color" is an active profile
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void color() {
|
||||
this.webClient.get().uri("/single_source-multiple-files/color").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("raw:green###ripe:yellow"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* "fruit.properties" is read, since it matches "spring.application.name"
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void name() {
|
||||
this.webClient.get().uri("/single_source-multiple-files/name").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("banana"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* shape profile is not active, thus property "fruit-shape.properties" is skipped
|
||||
* and as such, a null comes here.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void shape() {
|
||||
this.webClient.get().uri("/single_source-multiple-files/shape").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* this is a non-file property in the configmap
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void type() {
|
||||
this.webClient.get().uri("/single_source-multiple-files/type").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("yummy"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013-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.cloud.kubernetes.client.config.applications.single_source_multiple_files.controller;
|
||||
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Color;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Name;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Shape;
|
||||
import org.springframework.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties.Type;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class SingleSourceMultipleFilesController {
|
||||
|
||||
private final Name name;
|
||||
|
||||
private final Shape shape;
|
||||
|
||||
private final Color color;
|
||||
|
||||
private final Type type;
|
||||
|
||||
public SingleSourceMultipleFilesController(Name name, Shape shape, Color color, Type type) {
|
||||
this.name = name;
|
||||
this.shape = shape;
|
||||
this.color = color;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@GetMapping("/single_source-multiple-files/type")
|
||||
public String type() {
|
||||
return type.getType();
|
||||
}
|
||||
|
||||
@GetMapping("/single_source-multiple-files/shape")
|
||||
public String shape() {
|
||||
return shape.getRaw();
|
||||
}
|
||||
|
||||
@GetMapping("/single_source-multiple-files/color")
|
||||
public String color() {
|
||||
return "raw:" + color.getRaw() + "###" + "ripe:" + color.getRipe();
|
||||
}
|
||||
|
||||
@GetMapping("/single_source-multiple-files/name")
|
||||
public String name() {
|
||||
return name.getName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-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.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "color.when")
|
||||
public class Color {
|
||||
|
||||
private String raw;
|
||||
|
||||
private String ripe;
|
||||
|
||||
public String getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
public void setRaw(String raw) {
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
public String getRipe() {
|
||||
return ripe;
|
||||
}
|
||||
|
||||
public void setRipe(String ripe) {
|
||||
this.ripe = ripe;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("cool")
|
||||
public class Name {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("shape.when")
|
||||
public class Shape {
|
||||
|
||||
private String raw;
|
||||
|
||||
private String ripe;
|
||||
|
||||
public String getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
public void setRaw(String raw) {
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
public String getRipe() {
|
||||
return ripe;
|
||||
}
|
||||
|
||||
public void setRipe(String ripe) {
|
||||
this.ripe = ripe;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.client.config.applications.single_source_multiple_files.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("fruit")
|
||||
public class Type {
|
||||
|
||||
private String type;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.client.config.boostrap.stubs;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.JSON;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMap;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMapBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMapList;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
|
||||
/**
|
||||
* A test bootstrap that takes care to initialize ApiClient _before_ our main bootstrap
|
||||
* context; with some stub data already present.
|
||||
*
|
||||
* @author wind57
|
||||
*/
|
||||
@Order(0)
|
||||
@Configuration
|
||||
@ConditionalOnProperty("single.source.multiple.files.stub")
|
||||
public class SingleSourceMultipleFilesConfigurationStub {
|
||||
|
||||
@Bean
|
||||
public WireMockServer wireMock() {
|
||||
WireMockServer server = new WireMockServer(options().dynamicPort());
|
||||
server.start();
|
||||
WireMock.configureFor("localhost", server.port());
|
||||
return server;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApiClient apiClient(WireMockServer wireMockServer) {
|
||||
ApiClient apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
|
||||
io.kubernetes.client.openapi.Configuration.setDefaultApiClient(apiClient);
|
||||
stubData();
|
||||
return apiClient;
|
||||
}
|
||||
|
||||
public static void stubData() {
|
||||
|
||||
Map<String, String> one = new HashMap<>();
|
||||
one.put("fruit.type", "yummy");
|
||||
one.put("fruit.properties", "cool.name=banana");
|
||||
one.put("fruit-color.properties", "color.when.raw=green\ncolor.when.ripe=yellow");
|
||||
|
||||
// this is not taken, since "shape" is not an active profile
|
||||
one.put("fruit-shape.properties", "shape.when.raw=small-sphere\nshape.when.ripe=bigger-sphere");
|
||||
|
||||
V1ConfigMap configMap = new V1ConfigMapBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("my-configmap").withNamespace("spring-k8s").build())
|
||||
.addToData(one).build();
|
||||
|
||||
V1ConfigMapList allConfigMaps = new V1ConfigMapList();
|
||||
allConfigMaps.addItemsItem(configMap);
|
||||
|
||||
// the actual stub for CoreV1Api calls
|
||||
WireMock.stubFor(WireMock.get("/api/v1/namespaces/spring-k8s/configmaps")
|
||||
.willReturn(WireMock.aResponse().withStatus(200).withBody(new JSON().serialize(allConfigMaps))));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithProfileConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithPrefixConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithPrefixConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithPrefixConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithProfileConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithPrefixConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithProfileConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithPrefixConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithProfileConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SingleSourceMultipleFilesConfigurationStub, \
|
||||
org.springframework.cloud.kubernetes.client.config.EnableRetryBootstrapConfiguration
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
spring:
|
||||
application:
|
||||
name: fruit
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
namespace: spring-k8s
|
||||
sources:
|
||||
- name: my-configmap
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.commons.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -28,9 +30,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.commons.config.Constants.APPLICATION_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.Constants.APPLICATION_YAML;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.Constants.APPLICATION_YML;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.KEY_VALUE_TO_PROPERTIES;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.PROPERTIES_TO_MAP;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.PropertySourceUtils.throwingMerger;
|
||||
@@ -76,21 +75,45 @@ public class SourceDataEntriesProcessor extends MapPropertySource {
|
||||
|
||||
private static Map<String, Object> defaultProcessAllEntries(Map<String, String> input, Environment environment) {
|
||||
|
||||
return input.entrySet().stream().map(e -> extractProperties(e.getKey(), e.getValue(), environment))
|
||||
// we pass empty Strings on purpose, the logic here is either the value of
|
||||
// "spring.application.name"
|
||||
// or literal "application".
|
||||
String applicationName = ConfigUtils.getApplicationName(environment, "", "");
|
||||
String[] activeProfiles = environment.getActiveProfiles();
|
||||
|
||||
Set<String> fileNames = Stream
|
||||
.concat(Stream.of(applicationName),
|
||||
Arrays.stream(activeProfiles).map(profile -> applicationName + "-" + profile))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return input.entrySet().stream().map(e -> extractProperties(e.getKey(), e.getValue(), fileNames, environment))
|
||||
.flatMap(m -> m.entrySet().stream())
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, throwingMerger(), HashMap::new));
|
||||
}
|
||||
|
||||
private static Map<String, Object> extractProperties(String resourceName, String content, Environment environment) {
|
||||
private static Map<String, Object> extractProperties(String resourceName, String content, Set<String> fileNames,
|
||||
Environment environment) {
|
||||
|
||||
if (resourceName.equals(APPLICATION_YAML) || resourceName.equals(APPLICATION_YML)) {
|
||||
return yamlParserGenerator(environment).andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
}
|
||||
else if (resourceName.equals(APPLICATION_PROPERTIES)) {
|
||||
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
if (resourceName.endsWith(".yml") || resourceName.endsWith(".yaml") || resourceName.endsWith(".properties")) {
|
||||
|
||||
if (fileNames.contains(resourceName.split("\\.", 2)[0])) {
|
||||
if (resourceName.endsWith(".properties")) {
|
||||
LOG.debug("entry : " + resourceName + " will be treated as a single properties file");
|
||||
return KEY_VALUE_TO_PROPERTIES.andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
}
|
||||
else {
|
||||
LOG.debug("entry : " + resourceName + " will be treated as a single yml/yaml file");
|
||||
return yamlParserGenerator(environment).andThen(PROPERTIES_TO_MAP).apply(content);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG.warn("entry : " + resourceName + " will be skipped");
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.singletonMap(resourceName, content);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.commons.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
class SourceDataEntriesProcessorTests {
|
||||
|
||||
@Test
|
||||
void testSingleYml() {
|
||||
|
||||
Map<String, Object> result = SourceDataEntriesProcessor.processAllEntries(Map.of("one.yml", "key: \n value"),
|
||||
new MockEnvironment());
|
||||
|
||||
Assertions.assertEquals(1, result.size());
|
||||
Assertions.assertEquals("value", result.get("key"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSingleYaml() {
|
||||
|
||||
Map<String, Object> result = SourceDataEntriesProcessor.processAllEntries(Map.of("one.yaml", "key: \n value"),
|
||||
new MockEnvironment());
|
||||
|
||||
Assertions.assertEquals(1, result.size());
|
||||
Assertions.assertEquals("value", result.get("key"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSingleProperties() {
|
||||
|
||||
Map<String, Object> result = SourceDataEntriesProcessor.processAllEntries(Map.of("one.properties", "key=value"),
|
||||
new MockEnvironment());
|
||||
|
||||
Assertions.assertEquals(1, result.size());
|
||||
Assertions.assertEquals("value", result.get("key"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* two properties present, none are file treated
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void twoEntriesNoneFileTreated() {
|
||||
|
||||
Map.Entry<String, String> one = Map.entry("one", "1");
|
||||
Map.Entry<String, String> two = Map.entry("two", "2");
|
||||
Map<String, String> map = Map.ofEntries(one, two);
|
||||
|
||||
Map<String, Object> result = SourceDataEntriesProcessor.processAllEntries(map, new MockEnvironment());
|
||||
|
||||
Assertions.assertEquals(2, result.size());
|
||||
Assertions.assertEquals("1", result.get("one"));
|
||||
Assertions.assertEquals("2", result.get("two"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - two properties present, none are file treated.
|
||||
* - even if there is a application.yaml, it is not taken since it is != spring.application.name
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void twoEntriesOneIsYamlButNotTaken() {
|
||||
|
||||
Map.Entry<String, String> one = Map.entry("one", "1");
|
||||
Map.Entry<String, String> myName = Map.entry("my-name.yaml", "color: \n blue");
|
||||
Map<String, String> map = Map.ofEntries(one, myName);
|
||||
|
||||
Map<String, Object> result = SourceDataEntriesProcessor.processAllEntries(map, new MockEnvironment());
|
||||
|
||||
Assertions.assertEquals(1, result.size());
|
||||
Assertions.assertEquals("1", result.get("one"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - two properties present, both taken.
|
||||
* - second one is treated as a file, since it's name matches "spring.application.name"
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void twoEntriesBothTaken() {
|
||||
|
||||
Map.Entry<String, String> one = Map.entry("one", "1");
|
||||
Map.Entry<String, String> application = Map.entry("application.yaml", "color: \n blue");
|
||||
Map<String, String> map = Map.ofEntries(one, application);
|
||||
|
||||
Map<String, Object> result = SourceDataEntriesProcessor.processAllEntries(map, new MockEnvironment());
|
||||
|
||||
Assertions.assertEquals(2, result.size());
|
||||
Assertions.assertEquals("1", result.get("one"));
|
||||
Assertions.assertEquals("blue", result.get("color"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - three properties present, all taken.
|
||||
* - second one is treated as a file, since it's name matches "spring.application.name"
|
||||
* - third one is taken since it matches one active profile
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void threeEntriesAllTaken() {
|
||||
|
||||
Map.Entry<String, String> one = Map.entry("one", "1");
|
||||
Map.Entry<String, String> application = Map.entry("application.properties", "color=blue");
|
||||
Map.Entry<String, String> applicationDev = Map.entry("application-dev.properties", "fit=sport");
|
||||
Map<String, String> map = Map.ofEntries(one, application, applicationDev);
|
||||
|
||||
MockEnvironment env = new MockEnvironment();
|
||||
env.setActiveProfiles("dev");
|
||||
Map<String, Object> result = SourceDataEntriesProcessor.processAllEntries(map, env);
|
||||
|
||||
Assertions.assertEquals(3, result.size());
|
||||
Assertions.assertEquals("1", result.get("one"));
|
||||
Assertions.assertEquals("blue", result.get("color"));
|
||||
Assertions.assertEquals("sport", result.get("fit"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* - five properties present, four are taken
|
||||
* - second one is treated as a file, since it's name matches "spring.application.name"
|
||||
* - third one is taken since it matches one active profile
|
||||
* - fourth one is taken since it matches one active profile
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void fiveEntriesFourTaken() {
|
||||
|
||||
Map.Entry<String, String> one = Map.entry("one", "1");
|
||||
Map.Entry<String, String> jacket = Map.entry("jacket.properties", "name=jacket");
|
||||
Map.Entry<String, String> jacketFit = Map.entry("jacket-fit.properties", "fit=sport");
|
||||
Map.Entry<String, String> jacketColor = Map.entry("jacket-color.properties", "color=black");
|
||||
Map.Entry<String, String> jacketSeason = Map.entry("jacket-season.properties", "season=summer");
|
||||
Map<String, String> map = Map.ofEntries(one, jacket, jacketFit, jacketColor, jacketSeason);
|
||||
|
||||
MockEnvironment env = new MockEnvironment();
|
||||
env.setProperty("spring.application.name", "jacket");
|
||||
env.setActiveProfiles("fit", "color");
|
||||
Map<String, Object> result = SourceDataEntriesProcessor.processAllEntries(map, env);
|
||||
|
||||
Assertions.assertEquals(4, result.size());
|
||||
Assertions.assertEquals("1", result.get("one"));
|
||||
Assertions.assertEquals("jacket", result.get("name"));
|
||||
Assertions.assertEquals("sport", result.get("fit"));
|
||||
Assertions.assertEquals("black", result.get("color"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.fabric8.config.single_source_multiple_files;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties.Color;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties.Name;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties.Shape;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties.Type;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties({ Name.class, Shape.class, Color.class, Type.class })
|
||||
public class SingleSourceMultipleFilesApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SingleSourceMultipleFilesApp.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.fabric8.config.single_source_multiple_files;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@ActiveProfiles("color")
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = SingleSourceMultipleFilesApp.class,
|
||||
properties = { "spring.cloud.bootstrap.name=single-source-multiple-files",
|
||||
"spring.main.cloud-platform=KUBERNETES", "spring.cloud.bootstrap.enabled=true" })
|
||||
@EnableKubernetesMockClient(crud = true, https = false)
|
||||
class SingleSourceMultipleFilesBootstrapTests extends SingleSourceMultipleFilesTests {
|
||||
|
||||
private static KubernetesClient mockClient;
|
||||
|
||||
@BeforeAll
|
||||
static void setUpBeforeClass() {
|
||||
setUpBeforeClass(mockClient);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.fabric8.config.single_source_multiple_files;
|
||||
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@ActiveProfiles("color")
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = SingleSourceMultipleFilesApp.class,
|
||||
properties = { "spring.main.cloud-platform=KUBERNETES",
|
||||
"spring.config.import=kubernetes:,classpath:./single-source-multiple-files.yaml" })
|
||||
@EnableKubernetesMockClient(crud = true, https = false)
|
||||
class SingleSourceMultipleFilesConfigDataTests extends SingleSourceMultipleFilesTests {
|
||||
|
||||
private static KubernetesClient mockClient;
|
||||
|
||||
@BeforeAll
|
||||
static void setUpBeforeClass() {
|
||||
setUpBeforeClass(mockClient);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.fabric8.config.single_source_multiple_files;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*
|
||||
* issue: https://github.com/spring-cloud/spring-cloud-kubernetes/issues/640
|
||||
*/
|
||||
abstract class SingleSourceMultipleFilesTests {
|
||||
|
||||
private static KubernetesClient mockClient;
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webClient;
|
||||
|
||||
static void setUpBeforeClass(KubernetesClient mockClient) {
|
||||
SingleSourceMultipleFilesTests.mockClient = mockClient;
|
||||
// Configure the kubernetes master url to point to the mock server
|
||||
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl());
|
||||
System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
|
||||
System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false");
|
||||
System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false");
|
||||
System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
|
||||
System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
|
||||
|
||||
Map<String, String> one = new HashMap<>();
|
||||
one.put("fruit.type", "yummy");
|
||||
one.put("fruit.properties", "cool.name=banana");
|
||||
one.put("fruit-color.properties", "color.when.raw=green\ncolor.when.ripe=yellow");
|
||||
|
||||
// this is not taken, since "shape" is not an active profile
|
||||
one.put("fruit-shape.properties", "shape.when.raw=small-sphere\nshape.when.ripe=bigger-sphere");
|
||||
createConfigmap(one);
|
||||
|
||||
}
|
||||
|
||||
static void createConfigmap(Map<String, String> data) {
|
||||
mockClient.configMaps().inNamespace("spring-k8s").create(new ConfigMapBuilder().withNewMetadata()
|
||||
.withName("my-configmap").endMetadata().addToData(data).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* "fruit-color.properties" is taken since "spring.application.name=fruit" and
|
||||
* "color" is an active profile
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void color() {
|
||||
this.webClient.get().uri("/single_source-multiple-files/color").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("raw:green###ripe:yellow"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* "fruit.properties" is read, since it matches "spring.application.name"
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void name() {
|
||||
this.webClient.get().uri("/single_source-multiple-files/name").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("banana"));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* shape profile is not active, thus property "fruit-shape.properties" is skipped
|
||||
* and as such, a null comes here.
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void shape() {
|
||||
this.webClient.get().uri("/single_source-multiple-files/shape").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* this is a non-file property in the configmap
|
||||
* </pre>
|
||||
*/
|
||||
@Test
|
||||
void type() {
|
||||
this.webClient.get().uri("/single_source-multiple-files/type").exchange().expectStatus().isOk()
|
||||
.expectBody(String.class).value(Matchers.equalTo("yummy"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013-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.cloud.kubernetes.fabric8.config.single_source_multiple_files.controller;
|
||||
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties.Color;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties.Name;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties.Shape;
|
||||
import org.springframework.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties.Type;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class SingleSourceMultipleFilesController {
|
||||
|
||||
private final Name name;
|
||||
|
||||
private final Shape shape;
|
||||
|
||||
private final Color color;
|
||||
|
||||
private final Type type;
|
||||
|
||||
public SingleSourceMultipleFilesController(Name name, Shape shape, Color color, Type type) {
|
||||
this.name = name;
|
||||
this.shape = shape;
|
||||
this.color = color;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@GetMapping("/single_source-multiple-files/type")
|
||||
public String type() {
|
||||
return type.getType();
|
||||
}
|
||||
|
||||
@GetMapping("/single_source-multiple-files/shape")
|
||||
public String shape() {
|
||||
return shape.getRaw();
|
||||
}
|
||||
|
||||
@GetMapping("/single_source-multiple-files/color")
|
||||
public String color() {
|
||||
return "raw:" + color.getRaw() + "###" + "ripe:" + color.getRipe();
|
||||
}
|
||||
|
||||
@GetMapping("/single_source-multiple-files/name")
|
||||
public String name() {
|
||||
return name.getName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-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.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "color.when")
|
||||
public class Color {
|
||||
|
||||
private String raw;
|
||||
|
||||
private String ripe;
|
||||
|
||||
public String getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
public void setRaw(String raw) {
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
public String getRipe() {
|
||||
return ripe;
|
||||
}
|
||||
|
||||
public void setRipe(String ripe) {
|
||||
this.ripe = ripe;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("cool")
|
||||
public class Name {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("shape.when")
|
||||
public class Shape {
|
||||
|
||||
private String raw;
|
||||
|
||||
private String ripe;
|
||||
|
||||
public String getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
public void setRaw(String raw) {
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
public String getRipe() {
|
||||
return ripe;
|
||||
}
|
||||
|
||||
public void setRipe(String ripe) {
|
||||
this.ripe = ripe;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-2022 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.cloud.kubernetes.fabric8.config.single_source_multiple_files.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("fruit")
|
||||
public class Type {
|
||||
|
||||
private String type;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
spring:
|
||||
application:
|
||||
name: fruit
|
||||
cloud:
|
||||
kubernetes:
|
||||
config:
|
||||
namespace: spring-k8s
|
||||
sources:
|
||||
- name: my-configmap
|
||||
@@ -83,7 +83,9 @@ public class LeaderInitiatorTest {
|
||||
assertThat(this.leaderInitiator.isRunning()).isTrue();
|
||||
verify(this.mockFabric8LeaderRecordWatcher).start();
|
||||
verify(this.mockFabric8PodReadinessWatcher).start();
|
||||
Thread.sleep(10);
|
||||
|
||||
// TODO this tests needs to be reviewed not to use sleep
|
||||
Thread.sleep(1000);
|
||||
verify(this.mockFabric8LeadershipController, atLeastOnce()).update();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user