diff --git a/README.adoc b/README.adoc index b2301858..f402a34d 100644 --- a/README.adoc +++ b/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. \ No newline at end of file diff --git a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/ConfigMapPropertySource.java b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/ConfigMapPropertySource.java index 60fdb812..c0442e4a 100644 --- a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/ConfigMapPropertySource.java +++ b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/ConfigMapPropertySource.java @@ -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 processAllEntries(Map input, Environment environment) { diff --git a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsConfigProperties.java b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsConfigProperties.java index 4623f8c4..93edcebb 100644 --- a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsConfigProperties.java +++ b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsConfigProperties.java @@ -95,16 +95,16 @@ public class SecretsConfigProperties extends AbstractConfigProperties { return new ArrayList() { { 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 defaultLabels) { + String defaultNamespace, Map 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 normalizedLabels = this.labels.isEmpty() - ? defaultLabels : this.labels; + ? defaultLabels : this.labels; return new SecretsConfigProperties.NormalizedSource(normalizedName, - normalizedNamespace, normalizedLabels); + normalizedNamespace, normalizedLabels); } } diff --git a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsPropertySource.java b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsPropertySource.java index 0651ea65..5168ad4a 100644 --- a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsPropertySource.java +++ b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsPropertySource.java @@ -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 labels) { + String namespace, Map 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 getSourceData(KubernetesClient client, - Environment env, String name, String namespace, Map labels) { + Environment env, String name, String namespace, Map labels) { Map 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 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())); } } diff --git a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsPropertySourceLocator.java b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsPropertySourceLocator.java index 1d44c20c..8b00632e 100644 --- a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsPropertySourceLocator.java +++ b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/SecretsPropertySourceLocator.java @@ -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 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 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) { diff --git a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/reload/EventBasedConfigurationChangeDetector.java b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/reload/EventBasedConfigurationChangeDetector.java index 308f25f2..32a9d463 100644 --- a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/reload/EventBasedConfigurationChangeDetector.java +++ b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/reload/EventBasedConfigurationChangeDetector.java @@ -51,10 +51,10 @@ public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDe private Map 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() { - @Override - public void eventReceived(Action action, - ConfigMap configMap) { - onEvent(configMap); - } + .watch(new Watcher() { + @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() { - @Override - public void eventReceived(Action action, Secret secret) { - onEvent(secret); - } + this.kubernetesClient.secrets().watch(new Watcher() { + @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(); diff --git a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/reload/PollingConfigurationChangeDetector.java b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/reload/PollingConfigurationChangeDetector.java index 0a7da19e..d315ef4c 100644 --- a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/reload/PollingConfigurationChangeDetector.java +++ b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/reload/PollingConfigurationChangeDetector.java @@ -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 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 currentSecretSources = locateMapPropertySources( - this.secretsPropertySourceLocator, this.environment); + this.secretsPropertySourceLocator, this.environment); if (currentSecretSources != null && !currentSecretSources.isEmpty()) { List propertySources = findPropertySources( - SecretsPropertySource.class); + SecretsPropertySource.class); changedSecrets = changed(currentSecretSources, propertySources); } } diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsFromFilePathsTests.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsFromFilePathsTests.java index c987fe19..d6f1d45d 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsFromFilePathsTests.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsFromFilePathsTests.java @@ -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 { diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsMixedTests.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsMixedTests.java index 1e458e54..829fbe61 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsMixedTests.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsMixedTests.java @@ -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 }) diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithActiveProfilesNameTests.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithActiveProfilesNameTests.java index 2496cf63..a6ed2fe5 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithActiveProfilesNameTests.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithActiveProfilesNameTests.java @@ -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 { diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/MultipleSecretsTests.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/MultipleSecretsTests.java index 90cf6a80..fc9deceb 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/MultipleSecretsTests.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/MultipleSecretsTests.java @@ -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 { diff --git a/spring-cloud-kubernetes-core/src/main/java/org/springframework/cloud/kubernetes/profile/KubernetesProfileEnvironmentPostProcessor.java b/spring-cloud-kubernetes-core/src/main/java/org/springframework/cloud/kubernetes/profile/KubernetesProfileEnvironmentPostProcessor.java index ccb7840c..5d0826e7 100644 --- a/spring-cloud-kubernetes-core/src/main/java/org/springframework/cloud/kubernetes/profile/KubernetesProfileEnvironmentPostProcessor.java +++ b/spring-cloud-kubernetes-core/src/main/java/org/springframework/cloud/kubernetes/profile/KubernetesProfileEnvironmentPostProcessor.java @@ -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; } diff --git a/spring-cloud-kubernetes-leader/src/test/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfigurationTests.java b/spring-cloud-kubernetes-leader/src/test/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfigurationTests.java index 08cdd31f..0072a811 100644 --- a/spring-cloud-kubernetes-leader/src/test/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfigurationTests.java +++ b/spring-cloud-kubernetes-leader/src/test/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfigurationTests.java @@ -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}") diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesEndpointsServerList.java b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesEndpointsServerList.java index 7166564c..59257e45 100644 --- a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesEndpointsServerList.java +++ b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesEndpointsServerList.java @@ -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 getUpdatedListOfServers() { List 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; } + } diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesRibbonClientConfiguration.java b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesRibbonClientConfiguration.java index aa1018ad..904e9c46 100644 --- a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesRibbonClientConfiguration.java +++ b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesRibbonClientConfiguration.java @@ -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); diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesServerList.java b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesServerList.java index 7c6abc2a..7c3232f0 100644 --- a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesServerList.java +++ b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesServerList.java @@ -32,7 +32,7 @@ import io.fabric8.kubernetes.client.KubernetesClient; * @author wuzishu */ public abstract class KubernetesServerList extends AbstractServerList - implements ServerList { + implements ServerList { private static final int FIRST = 0; @@ -48,12 +48,11 @@ public abstract class KubernetesServerList extends AbstractServerList /** * 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 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 getInitialListOfServers() { return Collections.emptyList(); } - /** * Gets first. - * * @return the first */ static int getFIRST() { @@ -82,7 +79,6 @@ public abstract class KubernetesServerList extends AbstractServerList /** * Gets client. - * * @return the client */ KubernetesClient getClient() { @@ -91,7 +87,6 @@ public abstract class KubernetesServerList extends AbstractServerList /** * Gets service id. - * * @return the service id */ String getServiceId() { @@ -100,7 +95,6 @@ public abstract class KubernetesServerList extends AbstractServerList /** * Gets namespace. - * * @return the namespace */ String getNamespace() { @@ -109,7 +103,6 @@ public abstract class KubernetesServerList extends AbstractServerList /** * Gets port name. - * * @return the port name */ String getPortName() { @@ -118,10 +111,10 @@ public abstract class KubernetesServerList extends AbstractServerList /** * Gets properties. - * * @return the properties */ KubernetesRibbonProperties getProperties() { return properties; } + } diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesServicesServerList.java b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesServicesServerList.java index 2c445126..5d0d6a69 100644 --- a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesServicesServerList.java +++ b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/KubernetesServicesServerList.java @@ -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 getUpdatedListOfServers() { List 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; } + } diff --git a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonWithServiceModeTest.java b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonWithServiceModeTest.java index 8d75bcc2..cfb7ba1b 100644 --- a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonWithServiceModeTest.java +++ b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonWithServiceModeTest.java @@ -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 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()); } + }