Bumping versions

This commit is contained in:
buildmaster
2019-07-23 10:51:15 +00:00
parent abbe91a91f
commit 42acea1c49
18 changed files with 282 additions and 181 deletions

View File

@@ -124,6 +124,10 @@ spring.cloud.kubernetes.discovery.enabled=false
Some Spring Cloud components use the `DiscoveryClient` in order to obtain information about the local service instance. For
this to work, you need to align the Kubernetes service name with the `spring.application.name` property.
Spring Cloud Kubernetes can also watch the Kubernetes service catalog for changes and update the
`DiscoveryClient` implementation accordingly. In order to enable this functionality you need to add
`@EnableScheduling` on a configuration class in your application.
== Kubernetes native service discovery
Kubernetes itself is capable of (server side) service discovery (see: https://kubernetes.io/docs/concepts/services-networking/service/#discovering-services).
@@ -138,7 +142,7 @@ Additionally, you can use Hystrix for:
== Kubernetes PropertySource implementations
The most common approach to configuring your Spring Boot application is to create an `application.properties` or `applicaiton.yaml` or
The most common approach to configuring your Spring Boot application is to create an `application.properties` or `application.yaml` or
an `application-profile.properties` or `application-profile.yaml` file that contains key-value pairs that provide customization values to your
application or Spring Boot starters. You can override these properties by specifying system properties or environment
variables.
@@ -320,26 +324,89 @@ However, if the `production` profile is active, the configuration becomes:
If both profiles are active, the property that appears last within the `ConfigMap` overwrites any preceding values.
To tell Spring Boot which `profile` should be enabled at bootstrap, you can pass a system property to the Java
command. To do so, you can launch your Spring Boot application with an environment variable that you can define with the OpenShift
`DeploymentConfig` or Kubernetes `ReplicationConfig` resource file, as follows:
Another option is to create a different config map per profile and spring boot will automatically fetch it based
on active profiles
====
[source,yaml]
----
kind: ConfigMap
apiVersion: v1
kind: DeploymentConfig
metadata:
name: demo
data:
application.yml: |-
greeting:
message: Say Hello to the World
farewell:
message: Say Goodbye
----
====
====
[source,yaml]
----
kind: ConfigMap
apiVersion: v1
metadata:
name: demo-development
data:
application.yml: |-
spring:
profiles: development
greeting:
message: Say Hello to the Developers
farewell:
message: Say Goodbye to the Developers
----
====
====
[source,yaml]
----
kind: ConfigMap
apiVersion: v1
metadata:
name: demo-production
data:
application.yml: |-
spring:
profiles: production
greeting:
message: Say Hello to the Ops
farewell:
message: Say Goodbye
----
====
To tell Spring Boot which `profile` should be enabled at bootstrap, you can pass `SPRING_PROFILES_ACTIVE` environment variable.
To do so, you can launch your Spring Boot application with an environment variable that you can define it in the PodSpec at the container specification.
Deployment resource file, as follows:
====
[source,yaml]
----
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-name
labels:
app: deployment-name
spec:
replicas: 1
...
spec:
containers:
- env:
- name: JAVA_APP_DIR
value: /deployments
- name: JAVA_OPTIONS
value: -Dspring.profiles.active=developer
selector:
matchLabels:
app: deployment-name
template:
metadata:
labels:
app: deployment-name
spec:
containers:
- name: container-name
image: your-image
env:
- name: SPRING_PROFILES_ACTIVE
value: "development"
----
====
@@ -483,6 +550,36 @@ If you have all the secrets mapped to a common root, you can set them like:
----
====
As the case with `ConfigMap`, more advanced configuration is also possible where you can use multiple `Secret`
instances. The `spring.cloud.kubernetes.secrets.sources` list makes this possible.
For example, you could define the following `Secret` instances:
====
[source,yaml]
----
spring:
application:
name: cloud-k8s-app
cloud:
kubernetes:
secrets:
name: default-name
namespace: default-namespace
sources:
# Spring Cloud Kubernetes looks up a Secret named s1 in namespace default-namespace
- name: s1
# Spring Cloud Kubernetes looks up a Secret named default-name in whatever namespace n2
- namespace: n2
# Spring Cloud Kubernetes looks up a Secret named s3 in namespace n3
- namespace: n3
name: s3
----
====
In the preceding example, if `spring.cloud.kubernetes.secrets.namespace` had not been set,
the `Secret` named `s1` would be looked up in the namespace that the application runs.
.Properties:
[options="header,footer"]
|===
@@ -584,7 +681,7 @@ The reload feature supports two operating modes:
Any event produces a re-check on the configuration and, in case of changes, a reload.
The `view` role on the service account is required in order to listen for config map changes. A higher level role (such as `edit`) is required for secrets
(by default, secrets are not monitored).
* Polling: Oeriodically re-creates the configuration from config maps and secrets to see if it has changed.
* Polling: Periodically re-creates the configuration from config maps and secrets to see if it has changed.
You can configure the polling period by using the `spring.cloud.kubernetes.reload.period` property and defaults to 15 seconds.
It requires the same role as the monitored property source.
This means, for example, that using polling on file-mounted secret sources does not require particular privileges.
@@ -596,7 +693,7 @@ This means, for example, that using polling on file-mounted secret sources does
| `spring.cloud.kubernetes.reload.enabled` | `Boolean` | `false` | Enables monitoring of property sources and configuration reload
| `spring.cloud.kubernetes.reload.monitoring-config-maps` | `Boolean` | `true` | Allow monitoring changes in config maps
| `spring.cloud.kubernetes.reload.monitoring-secrets` | `Boolean` | `false` | Allow monitoring changes in secrets
| `spring.cloud.kubernetes.reload.strategy ` | `Enum` | `refresh` | The strategy to use when firing a reload (`refresh`, `restart_context`, or `shutdown`)
| `spring.cloud.kubernetes.reload.strategy` | `Enum` | `refresh` | The strategy to use when firing a reload (`refresh`, `restart_context`, or `shutdown`)
| `spring.cloud.kubernetes.reload.mode` | `Enum` | `event` | Specifies how to listen for changes in property sources (`event` or `polling`)
| `spring.cloud.kubernetes.reload.period` | `Duration`| `15s` | The period for verifying changes when using the `polling` strategy
|===
@@ -652,7 +749,6 @@ the `PortName` key. If you want to specify in which Kubernetes namespace the tar
the `KubernetesNamespace` key, remembering in both instances to prefix these keys with your service name and
`ribbon` prefix, as specified earlier.
.Spring Cloud Kubernetes Ribbon Configuration
|===
|Property Key |Type |Default Value
@@ -679,7 +775,6 @@ the `SERVICE` mode uses load balancing of the Kubernetes service to support Isti
* `spring.cloud.kubernetes.ribbon.cluster-domain` Set the custom Kubernetes cluster domain suffix. The default value is: 'cluster.local'
The following examples use this module for ribbon discovery:
* link:./spring-cloud-kubernetes-examples/kubernetes-circuitbreaker-ribbon-example[Spring Cloud Circuitbreaker and Ribbon]
@@ -1011,6 +1106,7 @@ $ touch .springformat
==== Intellij IDEA
In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin.
The following files can be found in the https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools[Spring Cloud Build] project.
.spring-cloud-build-tools/
----
@@ -1055,4 +1151,4 @@ Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on t
- `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL.
- `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`.
IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.
IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.

View File

@@ -99,16 +99,18 @@ public class ConfigMapPropertySource extends MapPropertySource {
}
if (environment != null) {
for (String activeProfile:environment.getActiveProfiles()) {
for (String activeProfile : environment.getActiveProfiles()) {
String mapNameWithProfile = name + "-" + activeProfile;
ConfigMap mapWithProfile = StringUtils.isEmpty(namespace)
? client.configMaps().withName(mapNameWithProfile).get()
: client.configMaps().inNamespace(namespace).withName(mapNameWithProfile).get();
? client.configMaps().withName(mapNameWithProfile).get()
: client.configMaps().inNamespace(namespace)
.withName(mapNameWithProfile).get();
if (mapWithProfile != null) {
result.putAll(processAllEntries(mapWithProfile.getData(), environment));
result.putAll(
processAllEntries(mapWithProfile.getData(), environment));
}
}
@@ -125,7 +127,6 @@ public class ConfigMapPropertySource extends MapPropertySource {
return new HashMap<>();
}
private static Map<String, String> processAllEntries(Map<String, String> input,
Environment environment) {

View File

@@ -95,16 +95,16 @@ public class SecretsConfigProperties extends AbstractConfigProperties {
return new ArrayList<SecretsConfigProperties.NormalizedSource>() {
{
add(new SecretsConfigProperties.NormalizedSource(
SecretsConfigProperties.this.name,
SecretsConfigProperties.this.namespace,
SecretsConfigProperties.this.labels));
SecretsConfigProperties.this.name,
SecretsConfigProperties.this.namespace,
SecretsConfigProperties.this.labels));
}
};
}
return this.sources.stream()
.map(s -> s.normalize(this.name, this.namespace, this.labels))
.collect(Collectors.toList());
.map(s -> s.normalize(this.name, this.namespace, this.labels))
.collect(Collectors.toList());
}
public static class Source {
@@ -162,16 +162,16 @@ public class SecretsConfigProperties extends AbstractConfigProperties {
}
public SecretsConfigProperties.NormalizedSource normalize(String defaultName,
String defaultNamespace, Map<String, String> defaultLabels) {
String defaultNamespace, Map<String, String> defaultLabels) {
final String normalizedName = StringUtils.isEmpty(this.name) ? defaultName
: this.name;
: this.name;
final String normalizedNamespace = StringUtils.isEmpty(this.namespace)
? defaultNamespace : this.namespace;
? defaultNamespace : this.namespace;
final Map<String, String> normalizedLabels = this.labels.isEmpty()
? defaultLabels : this.labels;
? defaultLabels : this.labels;
return new SecretsConfigProperties.NormalizedSource(normalizedName,
normalizedNamespace, normalizedLabels);
normalizedNamespace, normalizedLabels);
}
}

View File

@@ -42,21 +42,21 @@ public class SecretsPropertySource extends MapPropertySource {
private static final String PREFIX = "secrets";
public SecretsPropertySource(KubernetesClient client, Environment env, String name,
String namespace, Map<String, String> labels) {
String namespace, Map<String, String> labels) {
super(getSourceName(client, env, name, namespace),
getSourceData(client, env, name, namespace, labels));
getSourceData(client, env, name, namespace, labels));
}
private static String getSourceName(KubernetesClient client, Environment env,
String name, String namespace) {
String name, String namespace) {
return new StringBuilder().append(PREFIX)
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(name)
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(namespace)
.toString();
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(name)
.append(Constants.PROPERTY_SOURCE_NAME_SEPARATOR).append(namespace)
.toString();
}
private static Map<String, Object> getSourceData(KubernetesClient client,
Environment env, String name, String namespace, Map<String, String> labels) {
Environment env, String name, String namespace, Map<String, String> labels) {
Map<String, Object> result = new HashMap<>();
try {
@@ -74,18 +74,18 @@ public class SecretsPropertySource extends MapPropertySource {
if (!labels.isEmpty()) {
if (StringUtils.isEmpty(namespace)) {
client.secrets().withLabels(labels).list().getItems()
.forEach(s -> putAll(s, result));
.forEach(s -> putAll(s, result));
}
else {
client.secrets().inNamespace(namespace).withLabels(labels).list()
.getItems().forEach(s -> putAll(s, result));
.getItems().forEach(s -> putAll(s, result));
}
}
}
catch (Exception e) {
LOG.warn("Can't read secret with name: [" + name + "] or labels [" + labels
+ "] in namespace:[" + namespace + "] (cause: " + e.getMessage()
+ "). Ignoring");
+ "] in namespace:[" + namespace + "] (cause: " + e.getMessage()
+ "). Ignoring");
}
return result;
@@ -97,7 +97,7 @@ public class SecretsPropertySource extends MapPropertySource {
private static void putAll(Secret secret, Map<String, Object> result) {
if (secret != null && secret.getData() != null) {
secret.getData().forEach((k, v) -> result.put(k,
new String(Base64.getDecoder().decode(v)).trim()));
new String(Base64.getDecoder().decode(v)).trim()));
}
}

View File

@@ -55,7 +55,7 @@ public class SecretsPropertySourceLocator implements PropertySourceLocator {
private final SecretsConfigProperties properties;
public SecretsPropertySourceLocator(KubernetesClient client,
SecretsConfigProperties properties) {
SecretsConfigProperties properties) {
this.client = client;
this.properties = properties;
}
@@ -66,12 +66,12 @@ public class SecretsPropertySourceLocator implements PropertySourceLocator {
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
List<SecretsConfigProperties.NormalizedSource> sources = this.properties
.determineSources();
.determineSources();
CompositePropertySource composite = new CompositePropertySource(
"composite-secrets");
"composite-secrets");
if (this.properties.isEnableApi()) {
sources.forEach(s -> composite.addFirstPropertySource(
getKubernetesPropertySourceForSingleSecret(env, s)));
getKubernetesPropertySourceForSingleSecret(env, s)));
}
// read for secrets mount
@@ -83,28 +83,28 @@ public class SecretsPropertySourceLocator implements PropertySourceLocator {
}
private MapPropertySource getKubernetesPropertySourceForSingleSecret(
ConfigurableEnvironment environment,
SecretsConfigProperties.NormalizedSource normalizedSource) {
ConfigurableEnvironment environment,
SecretsConfigProperties.NormalizedSource normalizedSource) {
String configurationTarget = this.properties.getConfigurationTarget();
return new SecretsPropertySource(this.client, environment,
getApplicationName(environment, normalizedSource.getName(),
configurationTarget),
getApplicationNamespace(this.client, normalizedSource.getNamespace(),
configurationTarget),
normalizedSource.getLabels());
getApplicationName(environment, normalizedSource.getName(),
configurationTarget),
getApplicationNamespace(this.client, normalizedSource.getNamespace(),
configurationTarget),
normalizedSource.getLabels());
}
private void putPathConfig(CompositePropertySource composite) {
this.properties.getPaths().stream().map(Paths::get).filter(Files::exists)
.forEach(p -> putAll(p, composite));
.forEach(p -> putAll(p, composite));
}
private void putAll(Path path, CompositePropertySource composite) {
try {
Files.walk(path).filter(Files::isRegularFile)
.forEach(p -> readFile(p, composite));
.forEach(p -> readFile(p, composite));
}
catch (IOException e) {
LOG.warn("Error walking properties files", e);
@@ -115,10 +115,10 @@ public class SecretsPropertySourceLocator implements PropertySourceLocator {
try {
Map<String, Object> result = new HashMap<>();
result.put(path.getFileName().toString(),
new String(Files.readAllBytes(path)).trim());
new String(Files.readAllBytes(path)).trim());
if (!result.isEmpty()) {
composite.addFirstPropertySource(new MapPropertySource(
path.getFileName().toString().toLowerCase(), result));
path.getFileName().toString().toLowerCase(), result));
}
}
catch (IOException e) {

View File

@@ -51,10 +51,10 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
private Map<String, Watch> watches;
public EventBasedConfigurationChangeDetector(AbstractEnvironment environment,
ConfigReloadProperties properties, KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
ConfigReloadProperties properties, KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
super(environment, properties, kubernetesClient, strategy);
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
@@ -70,24 +70,24 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
try {
String name = "config-maps-watch";
this.watches.put(name, this.kubernetesClient.configMaps()
.watch(new Watcher<ConfigMap>() {
@Override
public void eventReceived(Action action,
ConfigMap configMap) {
onEvent(configMap);
}
.watch(new Watcher<ConfigMap>() {
@Override
public void eventReceived(Action action,
ConfigMap configMap) {
onEvent(configMap);
}
@Override
public void onClose(KubernetesClientException e) {
}
}));
@Override
public void onClose(KubernetesClientException e) {
}
}));
activated = true;
this.log.info("Added new Kubernetes watch: " + name);
}
catch (Exception e) {
this.log.error(
"Error while establishing a connection to watch config maps: configuration may remain stale",
e);
"Error while establishing a connection to watch config maps: configuration may remain stale",
e);
}
}
@@ -96,29 +96,29 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
activated = false;
String name = "secrets-watch";
this.watches.put(name,
this.kubernetesClient.secrets().watch(new Watcher<Secret>() {
@Override
public void eventReceived(Action action, Secret secret) {
onEvent(secret);
}
this.kubernetesClient.secrets().watch(new Watcher<Secret>() {
@Override
public void eventReceived(Action action, Secret secret) {
onEvent(secret);
}
@Override
public void onClose(KubernetesClientException e) {
}
}));
@Override
public void onClose(KubernetesClientException e) {
}
}));
activated = true;
this.log.info("Added new Kubernetes watch: " + name);
}
catch (Exception e) {
this.log.error(
"Error while establishing a connection to watch secrets: configuration may remain stale",
e);
"Error while establishing a connection to watch secrets: configuration may remain stale",
e);
}
}
if (activated) {
this.log.info(
"Kubernetes event-based configuration change detector activated");
"Kubernetes event-based configuration change detector activated");
}
}
@@ -140,9 +140,9 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
private void onEvent(ConfigMap configMap) {
boolean changed = changed(
locateMapPropertySources(this.configMapPropertySourceLocator,
this.environment),
findPropertySources(ConfigMapPropertySource.class));
locateMapPropertySources(this.configMapPropertySourceLocator,
this.environment),
findPropertySources(ConfigMapPropertySource.class));
if (changed) {
this.log.info("Detected change in config maps");
reloadProperties();
@@ -151,9 +151,9 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe
private void onEvent(Secret secret) {
boolean changed = changed(
locateMapPropertySources(this.secretsPropertySourceLocator,
this.environment),
findPropertySources(SecretsPropertySource.class));
locateMapPropertySources(this.secretsPropertySourceLocator,
this.environment),
findPropertySources(SecretsPropertySource.class));
if (changed) {
this.log.info("Detected change in secrets");
reloadProperties();

View File

@@ -48,10 +48,10 @@ public class PollingConfigurationChangeDetector extends ConfigurationChangeDetec
private SecretsPropertySourceLocator secretsPropertySourceLocator;
public PollingConfigurationChangeDetector(AbstractEnvironment environment,
ConfigReloadProperties properties, KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
ConfigReloadProperties properties, KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
super(environment, properties, kubernetesClient, strategy);
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
@@ -64,29 +64,29 @@ public class PollingConfigurationChangeDetector extends ConfigurationChangeDetec
}
@Scheduled(initialDelayString = "${spring.cloud.kubernetes.reload.period:15000}",
fixedDelayString = "${spring.cloud.kubernetes.reload.period:15000}")
fixedDelayString = "${spring.cloud.kubernetes.reload.period:15000}")
public void executeCycle() {
boolean changedConfigMap = false;
if (this.properties.isMonitoringConfigMaps()) {
List<? extends MapPropertySource> currentConfigMapSources = findPropertySources(
ConfigMapPropertySource.class);
ConfigMapPropertySource.class);
if (!currentConfigMapSources.isEmpty()) {
changedConfigMap = changed(
locateMapPropertySources(this.configMapPropertySourceLocator,
this.environment),
currentConfigMapSources);
locateMapPropertySources(this.configMapPropertySourceLocator,
this.environment),
currentConfigMapSources);
}
}
boolean changedSecrets = false;
if (this.properties.isMonitoringSecrets()) {
List<MapPropertySource> currentSecretSources = locateMapPropertySources(
this.secretsPropertySourceLocator, this.environment);
this.secretsPropertySourceLocator, this.environment);
if (currentSecretSources != null && !currentSecretSources.isEmpty()) {
List<SecretsPropertySource> propertySources = findPropertySources(
SecretsPropertySource.class);
SecretsPropertySource.class);
changedSecrets = changed(currentSecretSources, propertySources);
}
}

View File

@@ -44,8 +44,7 @@ import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.crea
properties = { "spring.application.name=configmap-path-example",
"spring.cloud.kubernetes.config.enableApi=false",
"spring.cloud.kubernetes.config.paths="
+ ConfigMapsFromFilePathsTests.FIRST_FILE_NAME_FULL_PATH
+ ","
+ ConfigMapsFromFilePathsTests.FIRST_FILE_NAME_FULL_PATH + ","
+ ConfigMapsFromFilePathsTests.SECOND_FILE_NAME_FULL_PATH })
public class ConfigMapsFromFilePathsTests {

View File

@@ -43,9 +43,7 @@ import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.read
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = App.class,
properties = {
"spring.application.name="
+ ConfigMapsMixedTests.APPLICATION_NAME,
properties = { "spring.application.name=" + ConfigMapsMixedTests.APPLICATION_NAME,
"spring.cloud.kubernetes.config.enableApi=true",
"spring.cloud.kubernetes.config.paths="
+ ConfigMapsMixedTests.FILE_NAME_FULL_PATH })

View File

@@ -42,9 +42,10 @@ import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.read
* @author Ali Shahbour
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = App.class, properties = {
"spring.application.name=configmap-with-active-profile-name-example",
"spring.cloud.kubernetes.reload.enabled=false" })
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = App.class,
properties = {
"spring.application.name=configmap-with-active-profile-name-example",
"spring.cloud.kubernetes.reload.enabled=false" })
@ActiveProfiles("development")
@AutoConfigureWebTestClient
public class ConfigMapsWithActiveProfilesNameTests {

View File

@@ -41,8 +41,9 @@ import org.springframework.test.web.reactive.server.WebTestClient;
* @author Haytham Mohamed
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = MultiSecretsApp.class, properties = {
"spring.cloud.bootstrap.name=multiple-secrets" })
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = MultiSecretsApp.class,
properties = { "spring.cloud.bootstrap.name=multiple-secrets" })
@AutoConfigureWebTestClient
public class MultipleSecretsTests {

View File

@@ -43,7 +43,8 @@ public class KubernetesProfileEnvironmentPostProcessor
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
final String enabledStr = environment.getProperty("spring.cloud.kubernetes.enabled", "true");
final String enabledStr = environment
.getProperty("spring.cloud.kubernetes.enabled", "true");
if ("false".equals(enabledStr.toLowerCase())) {
return;
}

View File

@@ -33,8 +33,7 @@ import static org.hamcrest.Matchers.containsString;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {
// Make sure test passes without Kubernetes cluster
"spring.cloud.kubernetes.leader.autoStartup=false"
})
"spring.cloud.kubernetes.leader.autoStartup=false" })
public class LeaderAutoConfigurationTests {
@Value("${local.server.port}")

View File

@@ -32,6 +32,7 @@ import org.apache.commons.logging.LogFactory;
/**
* the KubernetesEndpointsServerList description.
*
* @author wuzishu
*/
public class KubernetesEndpointsServerList extends KubernetesServerList {
@@ -40,11 +41,11 @@ public class KubernetesEndpointsServerList extends KubernetesServerList {
/**
* Instantiates a new Kubernetes endpoints server list.
*
* @param client the client
* @param properties the properties
*/
KubernetesEndpointsServerList(KubernetesClient client, KubernetesRibbonProperties properties) {
KubernetesEndpointsServerList(KubernetesClient client,
KubernetesRibbonProperties properties) {
super(client, properties);
}
@@ -52,16 +53,16 @@ public class KubernetesEndpointsServerList extends KubernetesServerList {
public List<Server> getUpdatedListOfServers() {
List<Server> result = new ArrayList<>();
Endpoints endpoints = StringUtils.isNotBlank(this.getNamespace())
? this.getClient().endpoints().inNamespace(this.getNamespace())
.withName(this.getServiceId()).get()
: this.getClient().endpoints().withName(this.getServiceId()).get();
? this.getClient().endpoints().inNamespace(this.getNamespace())
.withName(this.getServiceId()).get()
: this.getClient().endpoints().withName(this.getServiceId()).get();
if (endpoints != null) {
if (LOG.isDebugEnabled()) {
LOG.debug(String.format(
"Found [%d] endpoints in l [%s] for name [%s] and portName [%s]",
endpoints.getSubsets().size(),
endpoints.getMetadata().getNamespace(), this.getServiceId(),
this.getPortName()));
"Found [%d] endpoints in l [%s] for name [%s] and portName [%s]",
endpoints.getSubsets().size(),
endpoints.getMetadata().getNamespace(), this.getServiceId(),
this.getPortName()));
}
for (EndpointSubset subset : endpoints.getSubsets()) {
@@ -74,10 +75,9 @@ public class KubernetesEndpointsServerList extends KubernetesServerList {
else {
for (EndpointPort port : subset.getPorts()) {
if (Utils.isNullOrEmpty(this.getPortName())
|| this.getPortName().endsWith(port.getName())) {
|| this.getPortName().endsWith(port.getName())) {
for (EndpointAddress address : subset.getAddresses()) {
result.add(
new Server(address.getIp(), port.getPort()));
result.add(new Server(address.getIp(), port.getPort()));
}
}
}
@@ -86,10 +86,11 @@ public class KubernetesEndpointsServerList extends KubernetesServerList {
}
if (result.isEmpty()) {
LOG.warn(String.format(
"Did not find any endpoints in ribbon in namespace [%s] for name [%s] and portName [%s]",
this.getNamespace(), this.getServiceId(), this.getPortName()));
"Did not find any endpoints in ribbon in namespace [%s] for name [%s] and portName [%s]",
this.getNamespace(), this.getServiceId(), this.getPortName()));
}
return result;
}
}

View File

@@ -40,7 +40,7 @@ public class KubernetesRibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(KubernetesClient client, IClientConfig config,
KubernetesRibbonProperties properties) {
KubernetesRibbonProperties properties) {
KubernetesServerList serverList;
if (properties.getMode() == KubernetesRibbonMode.SERVICE) {
serverList = new KubernetesServicesServerList(client, properties);

View File

@@ -32,7 +32,7 @@ import io.fabric8.kubernetes.client.KubernetesClient;
* @author wuzishu
*/
public abstract class KubernetesServerList extends AbstractServerList<Server>
implements ServerList<Server> {
implements ServerList<Server> {
private static final int FIRST = 0;
@@ -48,12 +48,11 @@ public abstract class KubernetesServerList extends AbstractServerList<Server>
/**
* Instantiates a new Kubernetes server list.
*
* @param client the client
* @param properties the properties
*/
public KubernetesServerList(KubernetesClient client,
KubernetesRibbonProperties properties) {
KubernetesRibbonProperties properties) {
this.client = client;
this.properties = properties;
}
@@ -61,19 +60,17 @@ public abstract class KubernetesServerList extends AbstractServerList<Server>
public void initWithNiwsConfig(IClientConfig clientConfig) {
this.serviceId = clientConfig.getClientName();
this.namespace = clientConfig.getPropertyAsString(KubernetesConfigKey.Namespace,
this.client.getNamespace());
this.client.getNamespace());
this.portName = clientConfig.getPropertyAsString(KubernetesConfigKey.PortName,
null);
null);
}
public List<Server> getInitialListOfServers() {
return Collections.emptyList();
}
/**
* Gets first.
*
* @return the first
*/
static int getFIRST() {
@@ -82,7 +79,6 @@ public abstract class KubernetesServerList extends AbstractServerList<Server>
/**
* Gets client.
*
* @return the client
*/
KubernetesClient getClient() {
@@ -91,7 +87,6 @@ public abstract class KubernetesServerList extends AbstractServerList<Server>
/**
* Gets service id.
*
* @return the service id
*/
String getServiceId() {
@@ -100,7 +95,6 @@ public abstract class KubernetesServerList extends AbstractServerList<Server>
/**
* Gets namespace.
*
* @return the namespace
*/
String getNamespace() {
@@ -109,7 +103,6 @@ public abstract class KubernetesServerList extends AbstractServerList<Server>
/**
* Gets port name.
*
* @return the port name
*/
String getPortName() {
@@ -118,10 +111,10 @@ public abstract class KubernetesServerList extends AbstractServerList<Server>
/**
* Gets properties.
*
* @return the properties
*/
KubernetesRibbonProperties getProperties() {
return properties;
}
}

View File

@@ -30,18 +30,20 @@ import org.apache.commons.logging.LogFactory;
/**
* the KubernetesServicesServerList description.
*
* @author wuzishu
*/
public class KubernetesServicesServerList extends KubernetesServerList {
private static final Log LOG = LogFactory.getLog(KubernetesServicesServerList.class);
/**
* Instantiates a new Kubernetes services server list.
*
* @param client the client
* @param properties the properties
*/
KubernetesServicesServerList(KubernetesClient client, KubernetesRibbonProperties properties) {
KubernetesServicesServerList(KubernetesClient client,
KubernetesRibbonProperties properties) {
super(client, properties);
}
@@ -52,31 +54,32 @@ public class KubernetesServicesServerList extends KubernetesServerList {
*/
private String concatServiceFQDN(Service service) {
return String.format("%s.%s.svc.%s", service.getMetadata().getName(),
StringUtils.isNotBlank(service.getMetadata().getNamespace()) ? service.getMetadata()
.getNamespace() : "default", this.getProperties().getClusterDomain());
StringUtils.isNotBlank(service.getMetadata().getNamespace())
? service.getMetadata().getNamespace() : "default",
this.getProperties().getClusterDomain());
}
@Override
public List<Server> getUpdatedListOfServers() {
List<Server> result = new ArrayList<>();
Service service = StringUtils.isNotBlank(this.getNamespace())
? this.getClient().services().inNamespace(this.getNamespace())
.withName(this.getServiceId()).get()
: this.getClient().services().withName(this.getServiceId()).get();
? this.getClient().services().inNamespace(this.getNamespace())
.withName(this.getServiceId()).get()
: this.getClient().services().withName(this.getServiceId()).get();
if (service != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Found Service[" + service.getMetadata().getName() + "]");
}
if (service.getSpec().getPorts().size() == 1) {
result.add(new Server(this.concatServiceFQDN(service),
service.getSpec().getPorts().get(0).getPort()));
service.getSpec().getPorts().get(0).getPort()));
}
else {
for (ServicePort servicePort : service.getSpec().getPorts()) {
if (Utils.isNotNullOrEmpty(this.getPortName())
|| this.getPortName().endsWith(servicePort.getName())) {
|| this.getPortName().endsWith(servicePort.getName())) {
result.add(new Server(concatServiceFQDN(service),
servicePort.getPort()));
servicePort.getPort()));
}
}
@@ -84,9 +87,10 @@ public class KubernetesServicesServerList extends KubernetesServerList {
}
if (result.isEmpty()) {
LOG.warn(String.format(
"Did not find any service in ribbon in namespace [%s] for name [%s] and portName [%s]",
this.getNamespace(), this.getServiceId(), this.getPortName()));
"Did not find any service in ribbon in namespace [%s] for name [%s] and portName [%s]",
this.getNamespace(), this.getServiceId(), this.getPortName()));
}
return result;
}
}

View File

@@ -43,22 +43,24 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* the RibbonWithServiceModeTest description.
*
* @author wuzishu
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class, properties = {
"spring.application.name=testapp",
"spring.cloud.kubernetes.client.namespace=testns",
"spring.cloud.kubernetes.client.trustCerts=true",
"spring.cloud.kubernetes.config.namespace=testns",
"spring.cloud.kubernetes.enabled=true",
"spring.cloud.kubernetes.discovery.enabled=true",
"spring.cloud.kubernetes.ribbon.enabled=true",
"spring.cloud.kubernetes.ribbon.mode=SERVICE",
"spring.cloud.kubernetes.ribbon.clusterDomain=test.com"})
@SpringBootTest(classes = TestApplication.class,
properties = { "spring.application.name=testapp",
"spring.cloud.kubernetes.client.namespace=testns",
"spring.cloud.kubernetes.client.trustCerts=true",
"spring.cloud.kubernetes.config.namespace=testns",
"spring.cloud.kubernetes.enabled=true",
"spring.cloud.kubernetes.discovery.enabled=true",
"spring.cloud.kubernetes.ribbon.enabled=true",
"spring.cloud.kubernetes.ribbon.mode=SERVICE",
"spring.cloud.kubernetes.ribbon.clusterDomain=test.com" })
@EnableAutoConfiguration
@EnableDiscoveryClient
public class RibbonWithServiceModeTest {
@ClassRule
public static KubernetesServer server = new KubernetesServer();
@@ -76,21 +78,22 @@ public class RibbonWithServiceModeTest {
// Configure the kubernetes master url to point to the mock server
System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY,
mockClient.getConfiguration().getMasterUrl());
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");
"false");
// Configured
server.expect().get().withPath("/api/v1/namespaces/testns/services/testapp").andReturn(200,
new ServiceBuilder().withNewMetadata().withName("testapp").withNamespace("testns")
.endMetadata().withNewSpec().addToSelector("app", "testapp-a")
.addNewPort().withName("http")
.withPort(mockEndpointA.getMockServer().getPort())
.withTargetPort(new IntOrString(mockEndpointA.getMockServer().getPort()))
.withProtocol("TCP").endPort().endSpec().build())
.always();
server.expect().get().withPath("/api/v1/namespaces/testns/services/testapp")
.andReturn(200, new ServiceBuilder().withNewMetadata().withName("testapp")
.withNamespace("testns").endMetadata().withNewSpec()
.addToSelector("app", "testapp-a").addNewPort().withName("http")
.withPort(mockEndpointA.getMockServer().getPort())
.withTargetPort(
new IntOrString(mockEndpointA.getMockServer().getPort()))
.withProtocol("TCP").endPort().endSpec().build())
.always();
}
@@ -99,10 +102,14 @@ public class RibbonWithServiceModeTest {
@Test
public void testGreetingWithServiceMode() {
SpringClientFactory springClientFactory = context.getBean(SpringClientFactory.class);
SpringClientFactory springClientFactory = context
.getBean(SpringClientFactory.class);
ILoadBalancer testapp = springClientFactory.getLoadBalancer("testapp");
List<Server> allServers = testapp.getAllServers();
assertThat(allServers.stream().map(c -> String.format("%s:%s", c.getHost(), c.getPort())))
.containsOnly("testapp.testns.svc.test.com:" + mockEndpointA.getMockServer().getPort());
assertThat(allServers.stream()
.map(c -> String.format("%s:%s", c.getHost(), c.getPort())))
.containsOnly("testapp.testns.svc.test.com:"
+ mockEndpointA.getMockServer().getPort());
}
}