Bumping versions
This commit is contained in:
134
README.adoc
134
README.adoc
@@ -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.
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 })
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user