diff --git a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/BootstrapConfiguration.java b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/BootstrapConfiguration.java index ac3cdc6f..e421e915 100644 --- a/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/BootstrapConfiguration.java +++ b/spring-cloud-kubernetes-config/src/main/java/org/springframework/cloud/kubernetes/config/BootstrapConfiguration.java @@ -49,14 +49,16 @@ public class BootstrapConfiguration { private KubernetesClient client; @Bean - @ConditionalOnProperty(name = "spring.cloud.kubernetes.config.enabled", matchIfMissing = true) + @ConditionalOnProperty(name = "spring.cloud.kubernetes.config.enabled", + matchIfMissing = true) public ConfigMapPropertySourceLocator configMapPropertySourceLocator( ConfigMapConfigProperties properties) { return new ConfigMapPropertySourceLocator(this.client, properties); } @Bean - @ConditionalOnProperty(name = "spring.cloud.kubernetes.secrets.enabled", matchIfMissing = true) + @ConditionalOnProperty(name = "spring.cloud.kubernetes.secrets.enabled", + matchIfMissing = true) public SecretsPropertySourceLocator secretsPropertySourceLocator( SecretsConfigProperties properties) { return new SecretsPropertySourceLocator(this.client, properties); 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 964d6488..4fd01381 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 @@ -62,7 +62,8 @@ public class PollingConfigurationChangeDetector extends ConfigurationChangeDetec this.log.info("Kubernetes polling configuration change detector activated"); } - @Scheduled(initialDelayString = "${spring.cloud.kubernetes.reload.period:15000}", fixedDelayString = "${spring.cloud.kubernetes.reload.period:15000}") + @Scheduled(initialDelayString = "${spring.cloud.kubernetes.reload.period:15000}", + fixedDelayString = "${spring.cloud.kubernetes.reload.period:15000}") public void executeCycle() { boolean changedConfigMap = false; diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsFromFilePathsSpringBootTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsFromFilePathsSpringBootTest.java index 771e4aa0..23190d53 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsFromFilePathsSpringBootTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsFromFilePathsSpringBootTest.java @@ -39,12 +39,14 @@ import static org.assertj.core.util.Lists.newArrayList; import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.createFileWithContent; @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = { - "spring.application.name=configmap-path-example", - "spring.cloud.kubernetes.config.enableApi=false", - "spring.cloud.kubernetes.config.paths=" - + ConfigMapsFromFilePathsSpringBootTest.FIRST_FILE_NAME_FULL_PATH + "," - + ConfigMapsFromFilePathsSpringBootTest.SECOND_FILE_NAME_FULL_PATH }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class, + properties = { "spring.application.name=configmap-path-example", + "spring.cloud.kubernetes.config.enableApi=false", + "spring.cloud.kubernetes.config.paths=" + + ConfigMapsFromFilePathsSpringBootTest.FIRST_FILE_NAME_FULL_PATH + + "," + + ConfigMapsFromFilePathsSpringBootTest.SECOND_FILE_NAME_FULL_PATH }) public class ConfigMapsFromFilePathsSpringBootTest { protected static final String FILES_ROOT_PATH = "/tmp/scktests"; diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsMixedSpringBootTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsMixedSpringBootTest.java index 7e260972..63d11c26 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsMixedSpringBootTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsMixedSpringBootTest.java @@ -41,11 +41,14 @@ import static org.assertj.core.util.Lists.newArrayList; import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile; @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = { - "spring.application.name=" + ConfigMapsMixedSpringBootTest.APPLICATION_NAME, - "spring.cloud.kubernetes.config.enableApi=true", - "spring.cloud.kubernetes.config.paths=" - + ConfigMapsMixedSpringBootTest.FILE_NAME_FULL_PATH }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class, + properties = { + "spring.application.name=" + + ConfigMapsMixedSpringBootTest.APPLICATION_NAME, + "spring.cloud.kubernetes.config.enableApi=true", + "spring.cloud.kubernetes.config.paths=" + + ConfigMapsMixedSpringBootTest.FILE_NAME_FULL_PATH }) public class ConfigMapsMixedSpringBootTest { protected static final String FILES_ROOT_PATH = "/tmp/scktests"; diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsSpringBootTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsSpringBootTest.java index bce19076..246395fe 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsSpringBootTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsSpringBootTest.java @@ -41,9 +41,9 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Charles Moulliard */ @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = { - "spring.application.name=configmap-example", - "spring.cloud.kubernetes.reload.enabled=false" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class, properties = { "spring.application.name=configmap-example", + "spring.cloud.kubernetes.reload.enabled=false" }) @AutoConfigureWebTestClient public class ConfigMapsSpringBootTest { diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfileExpressionSpringBootTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfileExpressionSpringBootTest.java index 532216c0..83ec370b 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfileExpressionSpringBootTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfileExpressionSpringBootTest.java @@ -41,9 +41,10 @@ import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.read * Tests reading property from YAML document specified by profile expression. */ @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = { - "spring.application.name=configmap-with-profile-example", - "spring.cloud.kubernetes.reload.enabled=false" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class, + properties = { "spring.application.name=configmap-with-profile-example", + "spring.cloud.kubernetes.reload.enabled=false" }) @ActiveProfiles({ "production", "us-east" }) @AutoConfigureWebTestClient public class ConfigMapsWithProfileExpressionSpringBootTest { diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfilesNoActiveProfileSpringBootTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfilesNoActiveProfileSpringBootTest.java index 18f24e52..c558dc83 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfilesNoActiveProfileSpringBootTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfilesNoActiveProfileSpringBootTest.java @@ -40,9 +40,11 @@ import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.read * @author Charles Moulliard */ @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = { - "spring.application.name=configmap-with-profile-no-active-profiles-example", - "spring.cloud.kubernetes.reload.enabled=false" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class, + properties = { + "spring.application.name=configmap-with-profile-no-active-profiles-example", + "spring.cloud.kubernetes.reload.enabled=false" }) @AutoConfigureWebTestClient public class ConfigMapsWithProfilesNoActiveProfileSpringBootTest { diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfilesSpringBootTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfilesSpringBootTest.java index 32cfe9c0..4af184bb 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfilesSpringBootTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithProfilesSpringBootTest.java @@ -41,9 +41,10 @@ import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.read * @author Charles Moulliard */ @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = { - "spring.application.name=configmap-with-profile-example", - "spring.cloud.kubernetes.reload.enabled=false" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class, + properties = { "spring.application.name=configmap-with-profile-example", + "spring.cloud.kubernetes.reload.enabled=false" }) @ActiveProfiles("development") @AutoConfigureWebTestClient public class ConfigMapsWithProfilesSpringBootTest { diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithoutProfilesSpringBootTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithoutProfilesSpringBootTest.java index 9e1165bb..657b5ff3 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithoutProfilesSpringBootTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/ConfigMapsWithoutProfilesSpringBootTest.java @@ -38,9 +38,10 @@ import org.springframework.test.web.reactive.server.WebTestClient; import static org.springframework.cloud.kubernetes.config.ConfigMapTestUtil.readResourceFile; @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = { - "spring.application.name=configmap-without-profile-example", - "spring.cloud.kubernetes.reload.enabled=false" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class, + properties = { "spring.application.name=configmap-without-profile-example", + "spring.cloud.kubernetes.reload.enabled=false" }) @ActiveProfiles("development") @AutoConfigureWebTestClient public class ConfigMapsWithoutProfilesSpringBootTest { diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/CoreTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/CoreTest.java index d64cde8a..a39069c0 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/CoreTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/CoreTest.java @@ -36,12 +36,12 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; @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.secrets.enableApi=true" }) +@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.secrets.enableApi=true" }) public class CoreTest { @ClassRule diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/HealthIndicatorTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/HealthIndicatorTest.java index 049b14ee..29340b33 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/HealthIndicatorTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/HealthIndicatorTest.java @@ -35,8 +35,9 @@ import org.springframework.test.web.reactive.server.WebTestClient; import static org.hamcrest.Matchers.containsString; @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = { - "management.endpoint.health.show-details=always" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class, + properties = { "management.endpoint.health.show-details=always" }) public class HealthIndicatorTest { @ClassRule diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/MultipleConfigMapsSpringBootTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/MultipleConfigMapsSpringBootTest.java index afc65ed7..28ec49d1 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/MultipleConfigMapsSpringBootTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/MultipleConfigMapsSpringBootTest.java @@ -39,8 +39,9 @@ import org.springframework.test.web.reactive.server.WebTestClient; * @author Charles Moulliard */ @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ExampleApp.class, properties = { - "spring.cloud.bootstrap.name=multiplecms" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = ExampleApp.class, + properties = { "spring.cloud.bootstrap.name=multiplecms" }) @AutoConfigureWebTestClient public class MultipleConfigMapsSpringBootTest { diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/SecretsPropertySourceTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/SecretsPropertySourceTest.java index a1657956..62d05689 100644 --- a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/SecretsPropertySourceTest.java +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/SecretsPropertySourceTest.java @@ -39,7 +39,8 @@ import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class) @TestPropertySource("classpath:/application-secrets.properties") public class SecretsPropertySourceTest { diff --git a/spring-cloud-kubernetes-core/src/test/java/org/springframework/cloud/kubernetes/HealthIndicatorTest.java b/spring-cloud-kubernetes-core/src/test/java/org/springframework/cloud/kubernetes/HealthIndicatorTest.java index ddd25ed5..8bcd3bc8 100644 --- a/spring-cloud-kubernetes-core/src/test/java/org/springframework/cloud/kubernetes/HealthIndicatorTest.java +++ b/spring-cloud-kubernetes-core/src/test/java/org/springframework/cloud/kubernetes/HealthIndicatorTest.java @@ -35,8 +35,9 @@ import org.springframework.test.web.reactive.server.WebTestClient; import static org.hamcrest.Matchers.containsString; @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = { - "management.endpoint.health.show-details=always" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class, + properties = { "management.endpoint.health.show-details=always" }) public class HealthIndicatorTest { @ClassRule diff --git a/spring-cloud-kubernetes-core/src/test/java/org/springframework/cloud/kubernetes/InfoContributorTest.java b/spring-cloud-kubernetes-core/src/test/java/org/springframework/cloud/kubernetes/InfoContributorTest.java index 7d4d2573..2de4986e 100644 --- a/spring-cloud-kubernetes-core/src/test/java/org/springframework/cloud/kubernetes/InfoContributorTest.java +++ b/spring-cloud-kubernetes-core/src/test/java/org/springframework/cloud/kubernetes/InfoContributorTest.java @@ -35,7 +35,8 @@ import org.springframework.test.web.reactive.server.WebTestClient; import static org.hamcrest.Matchers.containsString; @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = App.class) public class InfoContributorTest { @ClassRule diff --git a/spring-cloud-kubernetes-discovery/src/main/java/org/springframework/cloud/kubernetes/discovery/KubernetesCatalogWatch.java b/spring-cloud-kubernetes-discovery/src/main/java/org/springframework/cloud/kubernetes/discovery/KubernetesCatalogWatch.java index 231aaac0..03511b14 100644 --- a/spring-cloud-kubernetes-discovery/src/main/java/org/springframework/cloud/kubernetes/discovery/KubernetesCatalogWatch.java +++ b/spring-cloud-kubernetes-discovery/src/main/java/org/springframework/cloud/kubernetes/discovery/KubernetesCatalogWatch.java @@ -58,7 +58,8 @@ public class KubernetesCatalogWatch implements ApplicationEventPublisherAware { this.publisher = publisher; } - @Scheduled(fixedDelayString = "${spring.cloud.kubernetes.discovery.catalogServicesWatchDelay:30000}") + @Scheduled( + fixedDelayString = "${spring.cloud.kubernetes.discovery.catalogServicesWatchDelay:30000}") public void catalogServicesWatch() { try { List previousState = this.catalogEndpointsState.get(); diff --git a/spring-cloud-kubernetes-discovery/src/main/java/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientAutoConfiguration.java b/spring-cloud-kubernetes-discovery/src/main/java/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientAutoConfiguration.java index fc1b3b64..37413912 100644 --- a/spring-cloud-kubernetes-discovery/src/main/java/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientAutoConfiguration.java +++ b/spring-cloud-kubernetes-discovery/src/main/java/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientAutoConfiguration.java @@ -58,7 +58,8 @@ public class KubernetesDiscoveryClientAutoConfiguration { @Bean @ConditionalOnMissingBean - @ConditionalOnProperty(name = "spring.cloud.kubernetes.discovery.enabled", matchIfMissing = true) + @ConditionalOnProperty(name = "spring.cloud.kubernetes.discovery.enabled", + matchIfMissing = true) public KubernetesDiscoveryClient kubernetesDiscoveryClient(KubernetesClient client, KubernetesDiscoveryProperties properties, KubernetesClientServicesFunction kubernetesClientServicesFunction, @@ -85,7 +86,9 @@ public class KubernetesDiscoveryClientAutoConfiguration { @Bean @ConditionalOnMissingBean - @ConditionalOnProperty(name = "spring.cloud.kubernetes.discovery.catalog-services-watch.enabled", matchIfMissing = true) + @ConditionalOnProperty( + name = "spring.cloud.kubernetes.discovery.catalog-services-watch.enabled", + matchIfMissing = true) public KubernetesCatalogWatch kubernetesCatalogWatch(KubernetesClient client) { return new KubernetesCatalogWatch(client); } diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/README.md b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/README.md index 1858ee66..ad953e0b 100644 --- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/README.md +++ b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/README.md @@ -27,9 +27,17 @@ And finally, if the leadership is yielded or revoked for some reason, the old le ## Example application usage -To begin with, build and deploy the application: +Leader election mechanism uses Kubernetes ConfigMap feature to coordinate leadership information. +To access ConfigMap user needs correct role and role binding. +Create them using the following commands: ``` -mvn clean package fabric8:deploy -Pkubernetes +kubectl apply -f leader-role.yml +kubectl apply -f leader-rolebinding.yml +``` + +Now build and deploy the application: +``` +mvn clean fabric8:deploy -Pkubernetes ``` This will deploy a single application instance to the cluster and that instance will automatically become a leader. @@ -76,8 +84,4 @@ Thus, when trying to yield the leadership, request might go to a non-leader node > Note: instances periodically try to acquire leadership and Spring Cloud Kubernetes doesn't decide which one of them is more worth to become one. Thus, it is possible that the instance which just yielded the leadership, made another leadership take over request faster than another instances and became a leader again. - -## Access control notice - -Leader election mechanism uses Kubernetes ConfigMap feature to coordinate leadership information. -In order to access it, [Role](./src/main/fabric8/role.yaml) and [RoleBinding](./src/main/fabric8/rb.yaml) objects are defined. + diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-role.yml b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-role.yml new file mode 100644 index 00000000..968fe263 --- /dev/null +++ b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-role.yml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: leader + labels: + app: kubernetes-leader-election-example + group: org.springframework.cloud +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + verbs: + - '*' diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-rolebinding.yml b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-rolebinding.yml new file mode 100644 index 00000000..72e41216 --- /dev/null +++ b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-rolebinding.yml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app: kubernetes-leader-election-example + group: org.springframework.cloud + name: leader +roleRef: + apiGroup: "" + kind: Role + name: leader +subjects: +- kind: ServiceAccount + name: default + apiGroup: "" diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/pom.xml b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/pom.xml index f78f5a2f..96457680 100644 --- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/pom.xml +++ b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/pom.xml @@ -36,6 +36,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-actuator + org.springframework.cloud spring-cloud-kubernetes-leader diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/fabric8/rb.yaml b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/fabric8/rb.yaml deleted file mode 100644 index f3646344..00000000 --- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/fabric8/rb.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: RoleBinding -metadata: - name: leader - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: leader -subjects: - - kind: ServiceAccount - name: default - namespace: default diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/fabric8/role.yaml b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/fabric8/role.yaml deleted file mode 100644 index 3f15dd3b..00000000 --- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/fabric8/role.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: Role -metadata: - name: leader - namespace: default -rules: - - apiGroups: - resources: - - pods - - configmaps - verbs: - - "*" diff --git a/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfiguration.java b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfiguration.java index 902821cd..e4bb868b 100644 --- a/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfiguration.java +++ b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfiguration.java @@ -41,7 +41,8 @@ import org.springframework.integration.leader.event.LeaderEventPublisher; @Configuration @EnableConfigurationProperties(LeaderProperties.class) @ConditionalOnBean(KubernetesClient.class) -@ConditionalOnProperty(value = "spring.cloud.kubernetes.leader.enabled", matchIfMissing = true) +@ConditionalOnProperty(value = "spring.cloud.kubernetes.leader.enabled", + matchIfMissing = true) public class LeaderAutoConfiguration { @Bean diff --git a/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeadershipController.java b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeadershipController.java index 74490a9a..898aeb18 100644 --- a/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeadershipController.java +++ b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeadershipController.java @@ -149,24 +149,18 @@ public class LeadershipController { LOGGER.debug("Leader is still '{}'", this.localLeader); return; } - else if (this.localLeader != null - && this.localLeader.isCandidate(this.candidate)) { + + Leader oldLeader = this.localLeader; + this.localLeader = newLeader; + + if (oldLeader != null && oldLeader.isCandidate(this.candidate)) { notifyOnRevoked(); } else if (newLeader != null && newLeader.isCandidate(this.candidate)) { notifyOnGranted(); } - this.localLeader = newLeader; - if (this.leaderReadinessWatcher != null) { - this.leaderReadinessWatcher.stop(); - this.leaderReadinessWatcher = null; - } - if (this.localLeader != null && !this.localLeader.isCandidate(this.candidate)) { - this.leaderReadinessWatcher = new PodReadinessWatcher( - this.localLeader.getId(), this.kubernetesClient, this); - this.leaderReadinessWatcher.start(); - } + restartLeaderReadinessWatcher(); LOGGER.debug("New leader is '{}'", this.localLeader); } @@ -203,6 +197,19 @@ public class LeadershipController { } } + private void restartLeaderReadinessWatcher() { + if (this.leaderReadinessWatcher != null) { + this.leaderReadinessWatcher.stop(); + this.leaderReadinessWatcher = null; + } + + if (this.localLeader != null && !this.localLeader.isCandidate(this.candidate)) { + this.leaderReadinessWatcher = new PodReadinessWatcher( + this.localLeader.getId(), this.kubernetesClient, this); + this.leaderReadinessWatcher.start(); + } + } + private String getLeaderKey() { return this.leaderProperties.getLeaderIdPrefix() + this.candidate.getRole(); } 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 f16fdd35..15932f73 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 @@ -31,10 +31,13 @@ import org.springframework.test.web.reactive.server.WebTestClient; import static org.hamcrest.Matchers.containsString; @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { - "spring.cloud.kubernetes.leader.autoStartup=false" // Make sure test passes - // without Kubernetes cluster -}) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { "spring.cloud.kubernetes.leader.autoStartup=false" // Make sure + // test passes + // without + // Kubernetes + // cluster + }) public class LeaderAutoConfigurationTests { @Value("${local.server.port}") diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/RibbonKubernetesAutoConfiguration.java b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/RibbonKubernetesAutoConfiguration.java index d549540b..c56a7195 100644 --- a/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/RibbonKubernetesAutoConfiguration.java +++ b/spring-cloud-kubernetes-ribbon/src/main/java/org/springframework/cloud/kubernetes/ribbon/RibbonKubernetesAutoConfiguration.java @@ -33,7 +33,8 @@ import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties @ConditionalOnBean(SpringClientFactory.class) -@ConditionalOnProperty(value = "spring.cloud.kubernetes.ribbon.enabled", matchIfMissing = true) +@ConditionalOnProperty(value = "spring.cloud.kubernetes.ribbon.enabled", + matchIfMissing = true) @AutoConfigureAfter(RibbonAutoConfiguration.class) @RibbonClients(defaultConfiguration = KubernetesRibbonClientConfiguration.class) public class RibbonKubernetesAutoConfiguration { diff --git a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonFallbackTest.java b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonFallbackTest.java index 77bfd4be..45473f52 100644 --- a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonFallbackTest.java +++ b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonFallbackTest.java @@ -44,11 +44,11 @@ import static org.assertj.core.api.Assertions.fail; * @author Charles Moulliard */ @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" }) +@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" }) @EnableAutoConfiguration @EnableDiscoveryClient public class RibbonFallbackTest { diff --git a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java index b54dabf0..216c291d 100644 --- a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java +++ b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java @@ -41,11 +41,11 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Charles Moulliard */ @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" }) +@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" }) @EnableAutoConfiguration @EnableDiscoveryClient public class RibbonTest {