From 123b2cce34ecb2c5c5a33ad8cbb77cdab0988afe Mon Sep 17 00:00:00 2001 From: wind57 Date: Fri, 19 Dec 2025 11:55:00 +0200 Subject: [PATCH 1/3] drop old leader election implementation Signed-off-by: wind57 --- docs/modules/ROOT/pages/examples.adoc | 1 - docs/modules/ROOT/pages/leader-election.adoc | 122 +++++---- pom.xml | 2 - .../kubernetes/commons/leader/Leader.java | 78 ------ .../commons/leader/LeaderContext.java | 51 ---- .../commons/leader/LeaderInfoContributor.java | 49 ---- .../commons/leader/LeaderInitiator.java | 101 -------- .../commons/leader/LeaderProperties.java | 156 ----------- .../commons/leader/LeaderRecordWatcher.java | 28 -- .../commons/leader/LeadershipController.java | 158 ------------ .../commons/leader/PodReadinessWatcher.java | 28 -- .../ConditionalOnLeaderElectionDisabled.java | 52 ---- .../ConditionalOnLeaderElectionEnabled.java | 4 +- .../election/LeaderElectionCallbacks.java | 1 - .../election/LeaderElectionProperties.java | 2 +- .../leader/{ => election}/LeaderUtils.java | 13 +- .../leader/LeaderInfoContributorTests.java | 94 ------- .../commons/leader/LeaderPropertiesTests.java | 50 ---- .../leader/LeadershipControllerStub.java | 61 ----- .../{ => election}/LeaderUtilsTests.java | 2 +- .../README.md | 162 ------------ .../leader-role.yml | 25 -- .../leader-rolebinding.yml | 15 -- .../pom.xml | 78 ------ .../cloud/kubernetes/examples/App.java | 29 --- .../kubernetes/examples/LeaderController.java | 99 ------- .../src/main/resources/application.properties | 6 - .../examples/LeaderControllerTest.java | 111 -------- spring-cloud-kubernetes-examples/pom.xml | 52 ---- .../Fabric8LeaderAutoConfiguration.java | 116 --------- .../leader/Fabric8LeaderRecordWatcher.java | 103 -------- .../leader/Fabric8LeadershipController.java | 196 -------------- .../leader/Fabric8PodReadinessWatcher.java | 114 -------- ...abric8LeaderElectionAutoConfiguration.java | 6 +- .../Fabric8LeaderAutoConfigurationTests.java | 62 ----- .../leader/Fabric8LeaderContextTest.java | 79 ------ ...ic8LeaderInfoContributorDisabledTests.java | 58 ----- .../leader/Fabric8LeaderInitiatorTest.java | 125 --------- .../Fabric8LeaderRecordWatcherTest.java | 125 --------- .../fabric8/leader/Fabric8LeaderTest.java | 65 ----- .../Fabric8LeadershipControllerTest.java | 108 -------- .../Fabric8PodReadinessWatcherTest.java | 124 --------- .../Fabric8LeaderAutoConfigurationTests.java | 79 +++--- ...erElectionInfoContributorIsLeaderTest.java | 2 +- ...lectionInfoContributorIsNotLeaderTest.java | 2 +- ...ic8LeaderOldAndNewImplementationTests.java | 244 ------------------ .../election/AbstractLeaderElection.java | 2 +- 47 files changed, 129 insertions(+), 3111 deletions(-) delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/Leader.java delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderContext.java delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInfoContributor.java delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInitiator.java delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderProperties.java delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderRecordWatcher.java delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeadershipController.java delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/PodReadinessWatcher.java delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/ConditionalOnLeaderElectionDisabled.java rename spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/{ => election}/LeaderUtils.java (92%) delete mode 100644 spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInfoContributorTests.java delete mode 100644 spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderPropertiesTests.java delete mode 100644 spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeadershipControllerStub.java rename spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/{ => election}/LeaderUtilsTests.java (97%) delete mode 100644 spring-cloud-kubernetes-examples/kubernetes-leader-election-example/README.md delete mode 100644 spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-role.yml delete mode 100644 spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-rolebinding.yml delete mode 100644 spring-cloud-kubernetes-examples/kubernetes-leader-election-example/pom.xml delete mode 100644 spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/java/org/springframework/cloud/kubernetes/examples/App.java delete mode 100644 spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/java/org/springframework/cloud/kubernetes/examples/LeaderController.java delete mode 100644 spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/resources/application.properties delete mode 100644 spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/test/java/org/springframework/cloud/kubernetes/examples/LeaderControllerTest.java delete mode 100644 spring-cloud-kubernetes-examples/pom.xml delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderAutoConfiguration.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderRecordWatcher.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeadershipController.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8PodReadinessWatcher.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderAutoConfigurationTests.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderContextTest.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderInfoContributorDisabledTests.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderInitiatorTest.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderRecordWatcherTest.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderTest.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeadershipControllerTest.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8PodReadinessWatcherTest.java delete mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderOldAndNewImplementationTests.java diff --git a/docs/modules/ROOT/pages/examples.adoc b/docs/modules/ROOT/pages/examples.adoc index d78f857dec..81fb4db9cf 100644 --- a/docs/modules/ROOT/pages/examples.adoc +++ b/docs/modules/ROOT/pages/examples.adoc @@ -10,7 +10,6 @@ The same applies for `PropertySourceLocator`, where you need to add to the class The following projects highlight the usage of these dependencies and demonstrate how you can use these libraries from any Spring Boot application: -* https://github.com/spring-cloud/spring-cloud-kubernetes/tree/main/spring-cloud-kubernetes-examples[Spring Cloud Kubernetes Examples]: the ones located inside this repository. * Spring Cloud Kubernetes Full Example: Minions and Boss ** https://github.com/salaboy/spring-cloud-k8s-minion[Minion] ** https://github.com/salaboy/spring-cloud-k8s-boss[Boss] diff --git a/docs/modules/ROOT/pages/leader-election.adoc b/docs/modules/ROOT/pages/leader-election.adoc index 58f3bf3b47..04bf334736 100644 --- a/docs/modules/ROOT/pages/leader-election.adoc +++ b/docs/modules/ROOT/pages/leader-election.adoc @@ -1,35 +1,19 @@ [[leader-election]] = Leader Election -The Spring Cloud Kubernetes leader election mechanism implements the leader election API of Spring Integration using a Kubernetes ConfigMap. - -Multiple application instances compete for leadership, but leadership will only be granted to one. -When granted leadership, a leader application receives an `OnGrantedEvent` application event with leadership `Context`. -Applications periodically attempt to gain leadership, with leadership granted to the first caller. -A leader will remain a leader until either it is removed from the cluster, or it yields its leadership. -When leadership removal occurs, the previous leader receives `OnRevokedEvent` application event. -After removal, any instances in the cluster may become the new leader, including the old leader. - -To include it in your project, add the following dependency. -Fabric8 Leader Implementation +To include leader election in your project, add the following dependency. [source,xml] ---- org.springframework.cloud - spring-cloud-kubernetes-fabric8-leader + spring-cloud-kubernetes-fabric8-leader-election ---- -To specify the name of the configmap used for leader election use the following property. -[source,properties] ----- -spring.cloud.kubernetes.leader.config-map-name=leader ----- - == Leader Election Info Contributor -Spring Cloud Kubernetes Leader includes an `InfoContributor` which adds leader election information to -Spring Boot's `/actuator/info` endpoint. This contributor provides information about the current leader, +Spring Cloud Kubernetes Leader Election includes an `InfoContributor` that adds leader election information to +Spring Boot’s `/actuator/info` endpoint. This contributor provides information about the current leader, including the leader ID, role, and whether the current application instance is the leader. Example output: @@ -44,90 +28,138 @@ Example output: } ---- -You can disable this `InfoContributor` by setting `management.info.leader.enabled` +You can disable this `InfoContributor` by setting `management.info.leader.election.enabled` to `false` in `application.[properties | yaml]`: [source,properties] ---- -management.info.leader.enabled=false - -''' - -There is another way you can configure leader election, and it comes with native support in the fabric8 library (k8s native client support is not yet implemented). In the long run, this will be the default way to configure leader election, while the previous one will be dropped. You can treat this one much like the JDK's "preview" features. +management.info.leader.election.enabled=false +---- -To be able to use it, you need to set the property: +To enable or disable leader election globally, you can use the following property: [source] ---- spring.cloud.kubernetes.leader.election.enabled=true ---- -Unlike the old implementation, this one will use either the `Lease` _or_ `ConfigMap` as the lock, depending on your cluster version. You can force using configMap still, even if leases are supported, via : +The Spring Cloud Kubernetes leader election mechanism uses a Kubernetes `Lease` when the cluster supports it, +and falls back to a `ConfigMap` otherwise. Even when `Lease` is supported, you can explicitly force the use of +a `ConfigMap` via configuration: [source] ---- spring.cloud.kubernetes.leader.election.use-config-map-as-lock=true ---- -The name of that `Lease` or `ConfigMap` can be defined using the property (default value is `spring-k8s-leader-election-lock`): +The name of the `Lease` or `ConfigMap` can be configured using the following property +(the default value is `spring-k8s-leader-election-lock`): [source] ---- spring.cloud.kubernetes.leader.election.lockName=other-name ---- -The namespace where the lock is created (`default` being set if no explicit one exists) can be set also: +The namespace where the lock is created (`default` is used if none is explicitly set) +can also be configured: [source] ---- spring.cloud.kubernetes.leader.election.lockNamespace=other-namespace ---- -Before the leader election process kicks in, you can wait until the pod is ready (via the readiness check). This is enabled by default, but you can disable it if needed: +Before the leader election process starts, the application can wait until the pod is ready +(via the readiness check). This behavior is enabled by default, but can be disabled if needed: [source] ---- spring.cloud.kubernetes.leader.election.waitForPodReady=false ---- -Like with the old implementation, we will publish events by default, but this can be disabled: +As with the previous implementation, leader election events are published by default, +but this behavior can be disabled: [source] ---- spring.cloud.kubernetes.leader.election.publishEvents=false ---- -There are a few parameters that control how the leader election process will happen. To explain them, we need to look at the high-level implementation of this process. All the candidate pods try to become the leader, or they try to _acquire_ the lock. If the lock is already taken, they will continue to retry to acquire it every `spring.cloud.kubernetes.leader.election.retryPeriod` (value is specified as `java.time.Duration`, and by default it is 2 seconds). +Several parameters control how the leader election process operates. At a high level, +all candidate pods attempt to become the leader by trying to _acquire_ the lock. If the lock +is already held, they will retry acquisition every +`spring.cloud.kubernetes.leader.election.retryPeriod` +(specified as a `java.time.Duration`, with a default of 2 seconds). -If the lock is not taken, current pod becomes the leader. It does so by inserting a so-called "record" into the lock (`Lease` or `ConfigMap`). Among the things that the "record" contains, is the `leaseDuration` (that you can specify via `spring.cloud.kubernetes.leader.election.leaseDuration`; by default it is 15 seconds and is of type `java.time.Duration`). This acts like a TTL on the lock: no other candidate can acquire the lock, unless this period has expired (from the last renewal time). +If the lock is not held, the current pod becomes the leader by writing a "record" into the lock +(`Lease` or `ConfigMap`). Among other fields, this record contains `leaseDuration` +(configured via `spring.cloud.kubernetes.leader.election.leaseDuration`, defaulting to 15 seconds, +type `java.time.Duration`). This value acts as a TTL for the lock: no other pod can acquire it +until this duration has expired since the last renewal. -Once a certain pod establishes itself as the leader (by acquiring the lock), it will continuously (every `spring.cloud.kubernetes.leader.election.retryPeriod`) try to renew its lease, or in other words: it will try to extend its leadership. When a renewal happens, the "record" that is stored inside the lock, is updated. For example, `renewTime` is updated inside the record, to denote when the last renewal happened. (You can always peek inside these fields by using `kubectl describe lease...` for example). +Once a pod becomes the leader, it periodically (every `retryPeriod`) attempts to renew its +leadership. On each successful renewal, the record stored in the lock is updated, including the +`renewTime` field. These values can be inspected using tools such as +`kubectl describe lease ...`. -Renewal must happen within a certain interval, specified by `spring.cloud.kubernetes.leader.election.renewDeadline`. By default, it is equal to 10 seconds, and it means that the leader pod has a maximum of 10 seconds to renew its leadership. If that does not happen, this pod loses its leadership and leader election starts again. Because other pods try to become leaders every 2 seconds (by default), it could mean that the pod that just lost leadership, will become leader again. If you want other pods to have a higher chance of becoming leaders, you can set the property (specified in seconds, by default it is 3) : +Renewal must occur within the interval specified by +`spring.cloud.kubernetes.leader.election.renewDeadline` +(default 10 seconds). If the leader fails to renew within this interval, it loses leadership +and a new leader election cycle begins. Because follower pods attempt acquisition every +`retryPeriod`, the same pod may immediately regain leadership. + +To give other pods a better chance of becoming leader after a renewal failure, you can configure +the following property (specified as a `Duration`, defaulting to 3 seconds): [source] ---- -spring.cloud.kubernetes.leader.election.wait-after-renewal-failure=3 +spring.cloud.kubernetes.leader.election.wait-after-renewal-failure=3s ---- -This will mean that the pod (that could not renew its lease) and lost leadership, will wait this many seconds, before trying to become leader again. +This setting causes a pod that lost leadership due to a renewal failure to wait before attempting +to reacquire leadership. + +A pod can lose leadership in three ways: + +- During a graceful application shutdown, in which case all leader election resources are cleaned up. + +- When leadership is voluntarily relinquished without an exception; in this case, the pod will attempt to acquire leadership again. + +- When an exception occurs during leadership. If + +[source] +---- +spring.cloud.kubernetes.leader.election.restart-on-failure +---- -Let's try to explain these settings based on an example: there are two pods that participate in leader election. For simplicity let's call them `podA` and `podB`. They both start at the same time: `12:00:00`, but `podA` establishes itself as the leader. This means that every two seconds (`retryPeriod`), `podB` will try to become the new leader. So at `12:00:02`, then at `12:00:04` and so on, it will basically ask : "Can I become the leader?". In our simplified example, the answer to that question can be answered based on `podA` activity. +is set to `true`, the pod will attempt to rejoin the leader election process. Otherwise, the +exception is logged and the pod will not participate in leader election again. -After `podA` has become the leader, at every 2 seconds, it will try to "extend" or _renew_ its leadership. So at `12:00:02`, then at `12:00:04` and so on, `podA` goes to the lock and updates its record to reflect that it is still the leader. Between the last successful renewal and the next one, it has exactly 10 seconds (`renewalDeadline`). If it fails to renew its leadership (there is a connection problem or a big GC pause, etc.) within those 10 seconds, it stops leading and `podB` can acquire the leadership now. When `podA` stops being a leader in a graceful way, the lock record is "cleared", basically meaning that `podB` can acquire leadership immediately. +To illustrate these settings, consider two pods participating in leader election: `podA` and +`podB`. Both start at `12:00:00`, and `podA` becomes the leader. Every two seconds (`retryPeriod`), +`podB` attempts to acquire leadership by checking the state of the lock. -A different story happens when `podA` dies with an OutOfMemory for example, without being able to gracefully update lock record and this is when `leaseDuration` argument matters. The easiest way to explain is via an example: +After `podA` becomes the leader, it renews its leadership every two seconds by updating the lock +record. The time between the last successful renewal and the next must not exceed the +`renewDeadline` (10 seconds by default). If `podA` fails to renew within this window (for example, +due to a long GC pause or a connectivity issue), it loses leadership and `podB` can acquire it. +If leadership is relinquished gracefully, the lock is cleared and `podB` can acquire leadership +immediately. -`podA` has renewed its leadership at `12:00:04`, but at `12:00:05` it has been killed by the OOMKiller. At `12:00:06`, `podB` will try to become the leader. It will check if "now" (`12:00:06`) is _after_ last renewal + lease duration, essentially it will check: +A different scenario occurs if `podA` terminates abruptly (for example, due to an OOM kill) +without clearing the lock. Suppose `podA` renews leadership at `12:00:04` and is killed at +`12:00:05`. At `12:00:06`, `podB` attempts to acquire leadership and checks whether the current +time is after the last renewal plus the `leaseDuration`: [source] ---- -12:00:06 > (12:00:04 + 00:00:10) +12:00:06 > (12:00:04 + 00:00:15) ---- -The condition is not fulfilled, so it can't become the leader. Same result will be at `12:00:08`, `12:00:10` and so on, until `12:00:16` and this is where the TTL (`leaseDuration`) of the lock will expire and `podB` can acquire it. As such, a lower value of `leaseDuration` will mean a faster acquiring of leadership by other pods. +This condition is false, so leadership cannot be acquired. The same check will fail until the +lease expires, at which point `podB` can acquire leadership. A lower `leaseDuration` therefore +results in faster leadership takeover after abrupt failures. -You might have to give proper RBAC to be able to use this functionality, for example: +You may need to configure appropriate RBAC permissions to use leader election, for example: [source] ---- diff --git a/pom.xml b/pom.xml index 78bd9172ba..683e6e8a65 100644 --- a/pom.xml +++ b/pom.xml @@ -121,7 +121,6 @@ spring-cloud-starter-kubernetes-client-config spring-cloud-starter-kubernetes-client-loadbalancer spring-cloud-starter-kubernetes-client-all - spring-cloud-kubernetes-examples spring-cloud-kubernetes-fabric8-leader spring-cloud-kubernetes-fabric8-istio spring-cloud-kubernetes-controllers @@ -254,7 +253,6 @@ central-publishing-maven-plugin - spring-cloud-kubernetes-examples spring-cloud-kubernetes-integration-tests diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/Leader.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/Leader.java deleted file mode 100644 index 7de9e840e7..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/Leader.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2013-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.commons.leader; - -import java.util.Objects; - -import org.springframework.integration.leader.Candidate; - -/** - * @author Gytis Trikleris - */ -public class Leader { - - private final String role; - - private final String id; - - public Leader(String role, String id) { - this.role = role; - this.id = id; - } - - public String getRole() { - return role; - } - - public String getId() { - return id; - } - - public boolean isCandidate(Candidate candidate) { - if (candidate == null) { - return false; - } - - return Objects.equals(role, candidate.getRole()) && Objects.equals(id, candidate.getId()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o == null || getClass() != o.getClass()) { - return false; - } - - Leader leader = (Leader) o; - - return Objects.equals(role, leader.role) && Objects.equals(id, leader.id); - } - - @Override - public int hashCode() { - return Objects.hash(role, id); - } - - @Override - public String toString() { - return String.format("Leader{role='%s', id='%s'}", role, id); - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderContext.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderContext.java deleted file mode 100644 index 912cb6fc41..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderContext.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.commons.leader; - -import org.springframework.integration.leader.Candidate; -import org.springframework.integration.leader.Context; - -/** - * @author Gytis Trikleris - */ -public class LeaderContext implements Context { - - private final Candidate candidate; - - private final LeadershipController leadershipController; - - public LeaderContext(Candidate candidate, LeadershipController leadershipController) { - this.candidate = candidate; - this.leadershipController = leadershipController; - } - - @Override - public boolean isLeader() { - return leadershipController.getLocalLeader().filter(l -> l.isCandidate(candidate)).isPresent(); - } - - @Override - public void yield() { - leadershipController.revoke(); - } - - @Override - public String getRole() { - return candidate.getRole(); - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInfoContributor.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInfoContributor.java deleted file mode 100644 index 1814feb51a..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInfoContributor.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2019-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.commons.leader; - -import java.util.HashMap; -import java.util.Map; - -import org.springframework.boot.actuate.info.Info.Builder; -import org.springframework.boot.actuate.info.InfoContributor; -import org.springframework.integration.leader.Candidate; - -public class LeaderInfoContributor implements InfoContributor { - - private final LeadershipController leadershipController; - - private final Candidate candidate; - - public LeaderInfoContributor(LeadershipController leadershipController, Candidate candidate) { - this.leadershipController = leadershipController; - this.candidate = candidate; - } - - @Override - public void contribute(Builder builder) { - Map details = new HashMap<>(); - leadershipController.getLocalLeader().ifPresentOrElse(leader -> { - details.put("leaderId", leader.getId()); - details.put("role", leader.getRole()); - details.put("isLeader", leader.isCandidate(candidate)); - }, () -> details.put("leaderId", "Unknown")); - - builder.withDetail("leaderElection", details); - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInitiator.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInitiator.java deleted file mode 100644 index 150e79311a..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInitiator.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2013-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.commons.leader; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.springframework.context.SmartLifecycle; -import org.springframework.core.log.LogAccessor; - -/** - * @author Gytis Trikleris - */ -public class LeaderInitiator implements SmartLifecycle { - - private static final LogAccessor LOGGER = new LogAccessor(LeaderInitiator.class); - - private final LeaderProperties leaderProperties; - - private final LeadershipController leadershipController; - - private final LeaderRecordWatcher leaderRecordWatcher; - - private final PodReadinessWatcher hostPodWatcher; - - private ScheduledExecutorService scheduledExecutorService; - - private boolean isRunning; - - public LeaderInitiator(LeaderProperties leaderProperties, LeadershipController leadershipController, - LeaderRecordWatcher leaderRecordWatcher, PodReadinessWatcher hostPodWatcher) { - this.leaderProperties = leaderProperties; - this.leadershipController = leadershipController; - this.leaderRecordWatcher = leaderRecordWatcher; - this.hostPodWatcher = hostPodWatcher; - } - - @Override - public boolean isAutoStartup() { - return leaderProperties.isAutoStartup(); - } - - @Override - public void start() { - if (!isRunning()) { - LOGGER.debug(() -> "Leader initiator starting"); - leaderRecordWatcher.start(); - hostPodWatcher.start(); - scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); - scheduledExecutorService.scheduleAtFixedRate(leadershipController::update, - leaderProperties.getUpdatePeriod().toMillis(), leaderProperties.getUpdatePeriod().toMillis(), - TimeUnit.MILLISECONDS); - isRunning = true; - } - } - - @Override - public void stop() { - if (isRunning()) { - LOGGER.debug(() -> "Leader initiator stopping"); - scheduledExecutorService.shutdown(); - scheduledExecutorService = null; - hostPodWatcher.stop(); - leaderRecordWatcher.stop(); - leadershipController.revoke(); - isRunning = false; - } - } - - @Override - public void stop(Runnable callback) { - stop(); - callback.run(); - } - - @Override - public boolean isRunning() { - return isRunning; - } - - @Override - public int getPhase() { - return 0; - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderProperties.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderProperties.java deleted file mode 100644 index c2213cf355..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderProperties.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2013-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.commons.leader; - -import java.time.Duration; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.util.StringUtils; - -/** - * @author Gytis Trikleris - */ -@ConfigurationProperties("spring.cloud.kubernetes.leader") -public class LeaderProperties { - - /** - * Should leader election be enabled. Default: true - */ - private boolean enabled = true; - - /** - * Should leader election be started automatically on startup. Default: true - */ - private boolean autoStartup = true; - - /** - * Role for which leadership this candidate will compete. - */ - private String role; - - /** - * Kubernetes namespace where the leaders ConfigMap and candidates are located. - */ - private String namespace; - - /** - * Kubernetes ConfigMap where leaders information will be stored. Default: leaders - */ - private String configMapName = "leaders"; - - /** - * Leader id property prefix for the ConfigMap. Default: leader.id. - */ - private String leaderIdPrefix = "leader.id."; - - /** - * Leadership status check period. Default: 60s - */ - private Duration updatePeriod = Duration.ofMillis(60000); - - /** - * Enable/disable publishing events in case leadership acquisition fails. Default: - * false - */ - private boolean publishFailedEvents = false; - - /** - * Enable/disable creating ConfigMap if it does not exist. Default: true - */ - private boolean createConfigMap = true; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public boolean isAutoStartup() { - return autoStartup; - } - - public void setAutoStartup(boolean autoStartup) { - this.autoStartup = autoStartup; - } - - public String getRole() { - return role; - } - - public void setRole(String role) { - this.role = role; - } - - public String getNamespace() { - return namespace; - } - - public void setNamespace(String namespace) { - this.namespace = namespace; - } - - public String getNamespace(String defaultValue) { - if (!StringUtils.hasText(namespace)) { - return defaultValue; - } - - return namespace; - } - - public String getConfigMapName() { - return configMapName; - } - - public void setConfigMapName(String configMapName) { - this.configMapName = configMapName; - } - - public String getLeaderIdPrefix() { - return leaderIdPrefix; - } - - public void setLeaderIdPrefix(String leaderIdPrefix) { - this.leaderIdPrefix = leaderIdPrefix; - } - - public Duration getUpdatePeriod() { - return updatePeriod; - } - - public void setUpdatePeriod(Duration updatePeriod) { - this.updatePeriod = updatePeriod; - } - - public boolean isPublishFailedEvents() { - return publishFailedEvents; - } - - public void setPublishFailedEvents(boolean publishFailedEvents) { - this.publishFailedEvents = publishFailedEvents; - } - - public boolean isCreateConfigMap() { - return createConfigMap; - } - - public void setCreateConfigMap(boolean createConfigMap) { - this.createConfigMap = createConfigMap; - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderRecordWatcher.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderRecordWatcher.java deleted file mode 100644 index 4d6e5bcd1c..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderRecordWatcher.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2013-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.commons.leader; - -/** - * @author Ryan Baxter - */ -public interface LeaderRecordWatcher { - - void start(); - - void stop(); - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeadershipController.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeadershipController.java deleted file mode 100644 index f118063b7d..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeadershipController.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2013-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.commons.leader; - -import java.util.Collections; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -import org.springframework.core.log.LogAccessor; -import org.springframework.integration.leader.Candidate; -import org.springframework.integration.leader.Context; -import org.springframework.integration.leader.event.LeaderEventPublisher; -import org.springframework.util.StringUtils; - -/** - * @author Ryan Baxter - */ -public abstract class LeadershipController { - - private static final LogAccessor LOGGER = new LogAccessor(LeadershipController.class); - - protected static final String PROVIDER_KEY = "provider"; - - protected static final String PROVIDER = "spring-cloud-kubernetes"; - - protected static final String KIND_KEY = "kind"; - - protected static final String KIND = "leaders"; - - protected Candidate candidate; - - protected Leader localLeader; - - protected LeaderProperties leaderProperties; - - protected LeaderEventPublisher leaderEventPublisher; - - protected PodReadinessWatcher leaderReadinessWatcher; - - public LeadershipController(Candidate candidate, LeaderProperties leaderProperties, - LeaderEventPublisher leaderEventPublisher) { - this.candidate = candidate; - this.leaderProperties = leaderProperties; - this.leaderEventPublisher = leaderEventPublisher; - } - - public Optional getLocalLeader() { - return Optional.ofNullable(localLeader); - } - - public abstract void update(); - - public abstract void revoke(); - - protected String getLeaderKey() { - return leaderProperties.getLeaderIdPrefix() + candidate.getRole(); - } - - protected Map getLeaderData(Candidate candidate) { - String leaderKey = getLeaderKey(); - return Collections.singletonMap(leaderKey, candidate.getId()); - } - - protected Leader extractLeader(Map data) { - if (data == null) { - return null; - } - - String leaderKey = getLeaderKey(); - String leaderId = data.get(leaderKey); - LOGGER.debug(() -> "retrieved leaderId: " + leaderId + " from leaderKey : " + leaderId); - if (!StringUtils.hasText(leaderId)) { - return null; - } - - return new Leader(candidate.getRole(), leaderId); - } - - protected void handleLeaderChange(Leader newLeader) { - if (Objects.equals(localLeader, newLeader)) { - LOGGER.debug(() -> "Leader is still : " + localLeader); - return; - } - - Leader oldLeader = localLeader; - localLeader = newLeader; - - if (oldLeader != null && oldLeader.isCandidate(candidate)) { - notifyOnRevoked(); - } - else if (newLeader != null && newLeader.isCandidate(candidate)) { - notifyOnGranted(); - } - - restartLeaderReadinessWatcher(); - - LOGGER.debug(() -> "New leader is " + localLeader); - } - - protected void notifyOnGranted() { - LOGGER.debug(() -> "Leadership has been granted to : " + candidate); - - Context context = new LeaderContext(candidate, this); - leaderEventPublisher.publishOnGranted(this, context, candidate.getRole()); - try { - candidate.onGranted(context); - } - catch (InterruptedException e) { - LOGGER.warn(e::getMessage); - Thread.currentThread().interrupt(); - } - } - - protected void notifyOnRevoked() { - LOGGER.debug(() -> "Leadership has been revoked from :" + candidate); - - Context context = new LeaderContext(candidate, this); - leaderEventPublisher.publishOnRevoked(this, context, candidate.getRole()); - candidate.onRevoked(context); - } - - protected void notifyOnFailedToAcquire() { - if (leaderProperties.isPublishFailedEvents()) { - Context context = new LeaderContext(candidate, this); - leaderEventPublisher.publishOnFailedToAcquire(this, context, candidate.getRole()); - } - } - - protected void restartLeaderReadinessWatcher() { - if (leaderReadinessWatcher != null) { - leaderReadinessWatcher.stop(); - leaderReadinessWatcher = null; - } - - if (localLeader != null && !localLeader.isCandidate(candidate)) { - leaderReadinessWatcher = createPodReadinessWatcher(localLeader.getId()); - leaderReadinessWatcher.start(); - } - } - - protected abstract PodReadinessWatcher createPodReadinessWatcher(String localLeaderId); - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/PodReadinessWatcher.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/PodReadinessWatcher.java deleted file mode 100644 index 56cc24bd34..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/PodReadinessWatcher.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2013-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.commons.leader; - -/** - * @author Ryan Baxter - */ -public interface PodReadinessWatcher { - - void start(); - - void stop(); - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/ConditionalOnLeaderElectionDisabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/ConditionalOnLeaderElectionDisabled.java deleted file mode 100644 index 6fce5c9a6e..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/ConditionalOnLeaderElectionDisabled.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.commons.leader.election; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.boot.autoconfigure.condition.NoneNestedConditions; -import org.springframework.context.annotation.Conditional; - -/** - * @author wind57 - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -@Conditional(ConditionalOnLeaderElectionDisabled.OnLeaderElectionDisabled.class) -public @interface ConditionalOnLeaderElectionDisabled { - - class OnLeaderElectionDisabled extends NoneNestedConditions { - - OnLeaderElectionDisabled() { - super(ConfigurationPhase.REGISTER_BEAN); - } - - @ConditionalOnLeaderElectionEnabled - static class OnLeaderElectionDisabledClass { - - } - - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/ConditionalOnLeaderElectionEnabled.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/ConditionalOnLeaderElectionEnabled.java index a58a68e553..70a327af0d 100644 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/ConditionalOnLeaderElectionEnabled.java +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/ConditionalOnLeaderElectionEnabled.java @@ -25,7 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import static org.springframework.cloud.kubernetes.commons.leader.LeaderUtils.LEADER_ELECTION_ENABLED_PROPERTY; +import static org.springframework.cloud.kubernetes.commons.leader.election.LeaderUtils.LEADER_ELECTION_ENABLED_PROPERTY; /** * Provides a more succinct conditional for: @@ -37,7 +37,7 @@ @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@ConditionalOnProperty(value = LEADER_ELECTION_ENABLED_PROPERTY, havingValue = "true", matchIfMissing = false) +@ConditionalOnProperty(value = LEADER_ELECTION_ENABLED_PROPERTY, havingValue = "true", matchIfMissing = true) public @interface ConditionalOnLeaderElectionEnabled { } diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderElectionCallbacks.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderElectionCallbacks.java index a1c463c0b8..828b29a1d7 100644 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderElectionCallbacks.java +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderElectionCallbacks.java @@ -19,7 +19,6 @@ import java.net.UnknownHostException; import java.util.function.Consumer; -import org.springframework.cloud.kubernetes.commons.leader.LeaderUtils; import org.springframework.cloud.kubernetes.commons.leader.election.events.NewLeaderEvent; import org.springframework.cloud.kubernetes.commons.leader.election.events.StartLeadingEvent; import org.springframework.cloud.kubernetes.commons.leader.election.events.StopLeadingEvent; diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderElectionProperties.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderElectionProperties.java index 25e5dc35f0..ed8ebdf9ed 100644 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderElectionProperties.java +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderElectionProperties.java @@ -21,7 +21,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.bind.DefaultValue; -import static org.springframework.cloud.kubernetes.commons.leader.LeaderUtils.LEADER_ELECTION_PROPERTY_PREFIX; +import static org.springframework.cloud.kubernetes.commons.leader.election.LeaderUtils.LEADER_ELECTION_PROPERTY_PREFIX; /** *
diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderUtils.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderUtils.java
similarity index 92%
rename from spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderUtils.java
rename to spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderUtils.java
index 27d797e5d2..21a148bc34 100644
--- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/LeaderUtils.java
+++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.springframework.cloud.kubernetes.commons.leader;
+package org.springframework.cloud.kubernetes.commons.leader.election;
 
 import java.io.File;
 import java.io.IOException;
@@ -23,7 +23,6 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Optional;
-import java.util.concurrent.locks.ReentrantLock;
 
 import org.springframework.cloud.kubernetes.commons.EnvReader;
 import org.springframework.core.log.LogAccessor;
@@ -104,14 +103,4 @@ public static String hostName() throws UnknownHostException {
 		}
 	}
 
-	public static void guarded(ReentrantLock lock, Runnable runnable) {
-		try {
-			lock.lock();
-			runnable.run();
-		}
-		finally {
-			lock.unlock();
-		}
-	}
-
 }
diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInfoContributorTests.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInfoContributorTests.java
deleted file mode 100644
index aeba15354f..0000000000
--- a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderInfoContributorTests.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.commons.leader;
-
-import java.util.Map;
-
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-
-import org.springframework.boot.actuate.info.Info;
-import org.springframework.integration.leader.Candidate;
-import org.springframework.integration.leader.DefaultCandidate;
-import org.springframework.integration.leader.event.LeaderEventPublisher;
-
-/**
- * @author wind57
- */
-class LeaderInfoContributorTests {
-
-	@Test
-	void testLeaderMissing() {
-
-		Candidate candidate = new DefaultCandidate("id", "role");
-		LeaderProperties leaderProperties = new LeaderProperties();
-		LeaderEventPublisher leaderEventPublisher = Mockito.mock(LeaderEventPublisher.class);
-		LeadershipController leadershipController = new LeadershipControllerStub(candidate, leaderProperties,
-				leaderEventPublisher);
-
-		LeaderInfoContributor leaderInfoContributor = new LeaderInfoContributor(leadershipController, candidate);
-		Info.Builder builder = new Info.Builder();
-		leaderInfoContributor.contribute(builder);
-
-		Assertions.assertThat(builder.build().getDetails().get("leaderElection"))
-			.isEqualTo(Map.of("leaderId", "Unknown"));
-	}
-
-	@Test
-	void testLeaderPresentIsLeader() {
-
-		Candidate candidate = new DefaultCandidate("leaderId", "leaderRole");
-		LeaderProperties leaderProperties = new LeaderProperties();
-		LeaderEventPublisher leaderEventPublisher = Mockito.mock(LeaderEventPublisher.class);
-		LeadershipController leadershipController = new LeadershipControllerStub(candidate, leaderProperties,
-				leaderEventPublisher);
-
-		Leader leader = new Leader("leaderRole", "leaderId");
-
-		leadershipController.handleLeaderChange(leader);
-
-		LeaderInfoContributor leaderInfoContributor = new LeaderInfoContributor(leadershipController, candidate);
-		Info.Builder builder = new Info.Builder();
-		leaderInfoContributor.contribute(builder);
-
-		Assertions.assertThat(builder.build().getDetails().get("leaderElection"))
-			.isEqualTo(Map.of("role", "leaderRole", "isLeader", true, "leaderId", "leaderId"));
-	}
-
-	@Test
-	void testLeaderPresentIsNotLeader() {
-
-		Candidate candidate = new DefaultCandidate("leaderId", "notLeaderRole");
-		LeaderProperties leaderProperties = new LeaderProperties();
-		LeaderEventPublisher leaderEventPublisher = Mockito.mock(LeaderEventPublisher.class);
-		LeadershipController leadershipController = new LeadershipControllerStub(candidate, leaderProperties,
-				leaderEventPublisher);
-
-		Leader leader = new Leader("leaderRole", "leaderId");
-
-		leadershipController.handleLeaderChange(leader);
-
-		LeaderInfoContributor leaderInfoContributor = new LeaderInfoContributor(leadershipController, candidate);
-		Info.Builder builder = new Info.Builder();
-		leaderInfoContributor.contribute(builder);
-
-		Assertions.assertThat(builder.build().getDetails().get("leaderElection"))
-			.isEqualTo(Map.of("role", "leaderRole", "isLeader", false, "leaderId", "leaderId"));
-	}
-
-}
diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderPropertiesTests.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderPropertiesTests.java
deleted file mode 100644
index 9781b1135e..0000000000
--- a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderPropertiesTests.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.commons.leader;
-
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-/**
- * @author wind57
- */
-class LeaderPropertiesTests {
-
-	@Test
-	void getNamespaceNull() {
-		LeaderProperties leaderProperties = new LeaderProperties();
-		String namespace = leaderProperties.getNamespace("a");
-		Assertions.assertThat(namespace).isEqualTo("a");
-	}
-
-	@Test
-	void getNamespaceEmpty() {
-		LeaderProperties leaderProperties = new LeaderProperties();
-		leaderProperties.setNamespace("");
-		String namespace = leaderProperties.getNamespace("a");
-		Assertions.assertThat(namespace).isEqualTo("a");
-	}
-
-	@Test
-	void getNamespacePresent() {
-		LeaderProperties leaderProperties = new LeaderProperties();
-		leaderProperties.setNamespace("c");
-		String namespace = leaderProperties.getNamespace("a");
-		Assertions.assertThat(namespace).isEqualTo("c");
-	}
-
-}
diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeadershipControllerStub.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeadershipControllerStub.java
deleted file mode 100644
index 53b6648ef9..0000000000
--- a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeadershipControllerStub.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.commons.leader;
-
-import java.util.Optional;
-
-import org.springframework.integration.leader.Candidate;
-import org.springframework.integration.leader.event.LeaderEventPublisher;
-
-/**
- * @author wind57
- */
-final class LeadershipControllerStub extends LeadershipController {
-
-	private Leader leader;
-
-	LeadershipControllerStub(Candidate candidate, LeaderProperties leaderProperties,
-			LeaderEventPublisher leaderEventPublisher) {
-		super(candidate, leaderProperties, leaderEventPublisher);
-	}
-
-	@Override
-	public void update() {
-
-	}
-
-	@Override
-	public void revoke() {
-
-	}
-
-	@Override
-	protected PodReadinessWatcher createPodReadinessWatcher(String localLeaderId) {
-		return null;
-	}
-
-	@Override
-	protected void handleLeaderChange(Leader leader) {
-		this.leader = leader;
-	}
-
-	@Override
-	public Optional getLocalLeader() {
-		return Optional.ofNullable(leader);
-	}
-
-}
diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderUtilsTests.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderUtilsTests.java
similarity index 97%
rename from spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderUtilsTests.java
rename to spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderUtilsTests.java
index b3bad5be3b..5a95b84034 100644
--- a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/LeaderUtilsTests.java
+++ b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/leader/election/LeaderUtilsTests.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.springframework.cloud.kubernetes.commons.leader;
+package org.springframework.cloud.kubernetes.commons.leader.election;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/README.md b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/README.md
deleted file mode 100644
index dabb0d2e1d..0000000000
--- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/README.md
+++ /dev/null
@@ -1,162 +0,0 @@
-# Spring Cloud Kubernetes leader election example
-
-## Setting up the Environment
-
-This example uses a Fabric8 Maven Plugin to deploy an application to a Kubernetes cluster.
-To try it locally, download and install [Minikube](https://minikube.sigs.k8s.io/docs/start/).
-
-Once Minikube is downloaded, start it with the following command:
-```
-minikube start
-```
-
-And configure environment variables to point to the Minikube's Docker daemon:
-```
-eval $(minikube docker-env)
-```
-
-## Overview
-
-Spring Cloud Kubernetes leader election mechanism implements leader election API of Spring Integration using Kubernetes ConfigMap.
-Multiple instances of the same application compete for a leadership of a specified role.
-But only one of them can become a leader and receive an `OnGrantedEvent` application event with a leadership `Context`.
-All the instances periodically try to get a leadership and whichever comes first - becomes a leader.
-The new leader will remain until either its instance disappears from the cluster or it yields its leadership.
-Once the leader is gone, any of the existing instances can become a new leader (even the previous leader if it yielded leadership but stayed in the cluster). 
-And finally, if the leadership is yielded or revoked for some reason, the old leader receives `OnRevokedEvent` application event.
-
-## Example application usage
-
-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:
-```
-kubectl apply -f leader-role.yml
-kubectl apply -f leader-rolebinding.yml
-```
-
-Build an image using the Spring Boot Build Image Plugin
-```
-./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=org/kubernetes-leader-election-example
-```
-
-You can then deploy the application using the following yaml.
-
-```yaml
----
-apiVersion: v1
-kind: List
-items:
-  - apiVersion: v1
-    kind: Service
-    metadata:
-      labels:
-        app: kubernetes-leader-election-example
-      name: kubernetes-leader-election-example
-    spec:
-      ports:
-        - name: http
-          port: 80
-          targetPort: 8080
-      selector:
-        app: kubernetes-leader-election-example
-      type: ClusterIP
-  - apiVersion: v1
-    kind: ServiceAccount
-    metadata:
-      labels:
-        app: kubernetes-leader-election-example
-      name: kubernetes-leader-election-example
-  - apiVersion: rbac.authorization.k8s.io/v1
-    kind: RoleBinding
-    metadata:
-      labels:
-        app: kubernetes-leader-election-example
-      name: kubernetes-leader-election-example:view
-    roleRef:
-      kind: Role
-      apiGroup: rbac.authorization.k8s.io
-      name: namespace-reader
-    subjects:
-      - kind: ServiceAccount
-        name: kubernetes-leader-election-example
-  - apiVersion: rbac.authorization.k8s.io/v1
-    kind: Role
-    metadata:
-        namespace: default
-        name: namespace-reader
-    rules:
-        - apiGroups: ["", "extensions", "apps"]
-          resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
-          verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
-  - apiVersion: apps/v1
-    kind: Deployment
-    metadata:
-      name: kubernetes-leader-election-example
-    spec:
-      replicas: 4
-      selector:
-        matchLabels:
-          app: kubernetes-leader-election-example
-      template:
-        metadata:
-          labels:
-            app: kubernetes-leader-election-example
-        spec:
-          serviceAccountName: kubernetes-leader-election-example
-          containers:
-          - name: kubernetes-leader-election-example
-            image: org/kubernetes-leader-election-example:latest
-            imagePullPolicy: IfNotPresent
-            readinessProbe:
-              httpGet:
-                port: 8080
-                path: /actuator/health/readiness
-            livenessProbe:
-              httpGet:
-                port: 8080
-                path: /actuator/health/liveness
-            ports:
-            - containerPort: 8080
-
-
-```
-
-This will deploy a single application instance to the cluster and that instance will automatically become a leader.
-
-Create an environment variable for an easier application access:
-```
-SERVICE_URL=$(minikube service kubernetes-leader-election-example --url)
-```
-
-Get leadership information:
-```
-curl $SERVICE_URL
-```
-
-You should receive a message like this:
-```
-I am 'kubernetes-leader-election-example-1234567890-abcde' and I am the leader of the 'world'
-```
-
-Yield the leadership:
-```
-curl -X PUT $SERVICE_URL
-```
-
-And check the leadership information again:
-```
-curl $SERVICE_URL
-```
-
-If another instance was able to acquire the leadership you should see a different instance is now the leadership.  You may
-have to try this a few times depending on how the service is load balanced.
-
-`DEBUG` logging is enabled so you can view the logs of the instances in order to see which instance is acquiring leadership.
-
-> Note: with multiple replicas in the cluster, `curl` command will access one of them depending on the Kubernetes load balancing configuration.
-Thus, when trying to yield the leadership, request might go to a non-leader node first. Just execute command again until it reaches the correct 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.
- 
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
deleted file mode 100644
index c3d0ebeaf5..0000000000
--- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-role.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-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
-  verbs:
-  - watch
-  - get
-- apiGroups:
-  - ""
-  resources:
-  - configmaps
-  verbs:
-  - watch
-  - get
-  - update
-  # resourceNames:
-  #   - 
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
deleted file mode 100644
index 72e412167f..0000000000
--- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/leader-rolebinding.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-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
deleted file mode 100644
index 6bc91f0acb..0000000000
--- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/pom.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-	4.0.0
-	
-		org.springframework.cloud
-		spring-cloud-kubernetes-examples
-		5.0.1-SNAPSHOT
-	
-
-	kubernetes-leader-election-example
-	Spring Cloud Kubernetes :: Examples :: Leader Election
-	Leader election demonstration with Spring Integration and ConfigMap
-
-	
-		
-			
-				org.springframework.boot
-				spring-boot-dependencies
-				pom
-				import
-				${spring-boot.version}
-			
-			
-				org.springframework.cloud
-				spring-cloud-kubernetes-fabric8-leader
-				${project.version}
-			
-		
-	
-
-	
-		
-			org.springframework.boot
-			spring-boot-starter-web
-		
-		
-			org.springframework.boot
-			spring-boot-starter-actuator
-		
-		
-			org.springframework.cloud
-			spring-cloud-kubernetes-fabric8-leader
-		
-		
-			org.springframework.boot
-			spring-boot-starter-test
-			test
-		
-	
-
-	
-		
-			
-				
-					org.apache.maven.plugins
-					maven-deploy-plugin
-					${maven-deploy-plugin.version}
-				
-			
-		
-		
-			
-				org.springframework.boot
-				spring-boot-maven-plugin
-			
-			
-				org.apache.maven.plugins
-				maven-deploy-plugin
-				
-					true
-				
-			
-		
-	
-
-
diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/java/org/springframework/cloud/kubernetes/examples/App.java b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/java/org/springframework/cloud/kubernetes/examples/App.java
deleted file mode 100644
index 4fab7c43a0..0000000000
--- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/java/org/springframework/cloud/kubernetes/examples/App.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2018-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.examples;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class App {
-
-	public static void main(String[] args) {
-		SpringApplication.run(App.class, args);
-	}
-
-}
diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/java/org/springframework/cloud/kubernetes/examples/LeaderController.java b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/java/org/springframework/cloud/kubernetes/examples/LeaderController.java
deleted file mode 100644
index 27f634f4e9..0000000000
--- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/java/org/springframework/cloud/kubernetes/examples/LeaderController.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.examples;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.event.EventListener;
-import org.springframework.http.ResponseEntity;
-import org.springframework.integration.leader.Context;
-import org.springframework.integration.leader.event.OnGrantedEvent;
-import org.springframework.integration.leader.event.OnRevokedEvent;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-public class LeaderController {
-
-	private final String host;
-
-	@Value("${spring.cloud.kubernetes.leader.role}")
-	private String role;
-
-	private Context context;
-
-	public LeaderController() throws UnknownHostException {
-		this.host = InetAddress.getLocalHost().getHostName();
-	}
-
-	/**
-	 * Return a message whether this instance is a leader or not.
-	 * @return info
-	 */
-	@GetMapping("/")
-	public String getInfo() {
-		if (this.context == null) {
-			return String.format("I am '%s' but I am not a leader of the '%s'", this.host, this.role);
-		}
-
-		return String.format("I am '%s' and I am the leader of the '%s'", this.host, this.role);
-	}
-
-	/**
-	 * PUT request to try and revoke a leadership of this instance. If the instance is not
-	 * a leader, leadership cannot be revoked. Thus "HTTP Bad Request" response. If the
-	 * instance is a leader, it must have a leadership context instance which can be used
-	 * to give up the leadership.
-	 * @return info about leadership
-	 */
-	@PutMapping("/")
-	public ResponseEntity revokeLeadership() {
-		if (this.context == null) {
-			String message = String.format("Cannot revoke leadership because '%s' is not a leader", this.host);
-			return ResponseEntity.badRequest().body(message);
-		}
-
-		this.context.yield();
-
-		String message = String.format("Leadership revoked for '%s'", this.host);
-		return ResponseEntity.ok(message);
-	}
-
-	/**
-	 * Handle a notification that this instance has become a leader.
-	 * @param event on granted event
-	 */
-	@EventListener
-	public void handleEvent(OnGrantedEvent event) {
-		System.out.println(String.format("'%s' leadership granted", event.getRole()));
-		this.context = event.getContext();
-	}
-
-	/**
-	 * Handle a notification that this instance's leadership has been revoked.
-	 * @param event on revoked event
-	 */
-	@EventListener
-	public void handleEvent(OnRevokedEvent event) {
-		System.out.println(String.format("'%s' leadership revoked", event.getRole()));
-		this.context = null;
-	}
-
-}
diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/resources/application.properties b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/resources/application.properties
deleted file mode 100644
index faf8c085c4..0000000000
--- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/main/resources/application.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-# Role to which leader election this instance will participate
-spring.cloud.kubernetes.leader.role=world
-# Configmap to which leader election metadata will be saved
-spring.cloud.kubernetes.leader.config-map-name=leader
-logging.level.org.springframework.cloud.kubernetes.fabric8.leader=DEBUG
-logging.level.org.springframework.cloud.kubernetes.commons.leader=DEBUG
diff --git a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/test/java/org/springframework/cloud/kubernetes/examples/LeaderControllerTest.java b/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/test/java/org/springframework/cloud/kubernetes/examples/LeaderControllerTest.java
deleted file mode 100644
index 05d12fb14e..0000000000
--- a/spring-cloud-kubernetes-examples/kubernetes-leader-election-example/src/test/java/org/springframework/cloud/kubernetes/examples/LeaderControllerTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.examples;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.integration.leader.Context;
-import org.springframework.integration.leader.event.OnGrantedEvent;
-import org.springframework.integration.leader.event.OnRevokedEvent;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-@ExtendWith(MockitoExtension.class)
-public class LeaderControllerTest {
-
-	@Mock
-	private OnGrantedEvent mockOnGrantedEvent;
-
-	@Mock
-	private OnRevokedEvent mockOnRevokedEvent;
-
-	@Mock
-	private Context mockContext;
-
-	private String host;
-
-	private LeaderController leaderController;
-
-	@BeforeEach
-	public void before() throws UnknownHostException {
-		this.host = InetAddress.getLocalHost().getHostName();
-		this.leaderController = new LeaderController();
-	}
-
-	@Test
-	public void shouldGetNonLeaderInfo() {
-		String message = String.format("I am '%s' but I am not a leader of the 'null'", this.host);
-		assertThat(this.leaderController.getInfo()).isEqualTo(message);
-	}
-
-	@Test
-	public void shouldHandleGrantedEvent() {
-		given(this.mockOnGrantedEvent.getContext()).willReturn(this.mockContext);
-
-		this.leaderController.handleEvent(this.mockOnGrantedEvent);
-
-		String message = String.format("I am '%s' and I am the leader of the 'null'", this.host);
-		assertThat(this.leaderController.getInfo()).isEqualTo(message);
-	}
-
-	@Test
-	public void shouldHandleRevokedEvent() {
-		given(this.mockOnGrantedEvent.getContext()).willReturn(this.mockContext);
-
-		this.leaderController.handleEvent(this.mockOnGrantedEvent);
-		this.leaderController.handleEvent(this.mockOnRevokedEvent);
-
-		String message = String.format("I am '%s' but I am not a leader of the 'null'", this.host);
-		assertThat(this.leaderController.getInfo()).isEqualTo(message);
-	}
-
-	@Test
-	public void shouldRevokeLeadership() {
-		given(this.mockOnGrantedEvent.getContext()).willReturn(this.mockContext);
-
-		this.leaderController.handleEvent(this.mockOnGrantedEvent);
-		ResponseEntity responseEntity = this.leaderController.revokeLeadership();
-
-		String message = String.format("Leadership revoked for '%s'", this.host);
-		assertThat(responseEntity.getBody()).isEqualTo(message);
-		assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
-		verify(this.mockContext).yield();
-	}
-
-	@Test
-	public void shouldNotRevokeLeadershipIfNotLeader() {
-		ResponseEntity responseEntity = this.leaderController.revokeLeadership();
-
-		String message = String.format("Cannot revoke leadership because '%s' is not a leader", this.host);
-		assertThat(responseEntity.getBody()).isEqualTo(message);
-		assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
-		verify(this.mockContext, times(0)).yield();
-	}
-
-}
diff --git a/spring-cloud-kubernetes-examples/pom.xml b/spring-cloud-kubernetes-examples/pom.xml
deleted file mode 100644
index 0c83edb1aa..0000000000
--- a/spring-cloud-kubernetes-examples/pom.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-	4.0.0
-	
-		spring-cloud-kubernetes
-		org.springframework.cloud
-		5.0.1-SNAPSHOT
-	
-
-	spring-cloud-kubernetes-examples
-	pom
-
-	Spring Cloud Kubernetes :: Examples
-	Examples showing how to use features of Spring Cloud Kubernetes.
-	
-
-	
-		kubernetes-leader-election-example
-	
-
-	
-		
-			
-				org.apache.maven.plugins
-				maven-deploy-plugin
-				${maven-deploy-plugin.version}
-				
-					true
-				
-			
-		
-	
-
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderAutoConfiguration.java b/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderAutoConfiguration.java
deleted file mode 100644
index 0f511d2375..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderAutoConfiguration.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import java.net.UnknownHostException;
-
-import io.fabric8.kubernetes.client.KubernetesClient;
-
-import org.springframework.boot.actuate.autoconfigure.info.ConditionalOnEnabledInfoContributor;
-import org.springframework.boot.actuate.info.InfoContributor;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderInfoContributor;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderInitiator;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderUtils;
-import org.springframework.cloud.kubernetes.commons.leader.election.ConditionalOnLeaderElectionDisabled;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.integration.leader.Candidate;
-import org.springframework.integration.leader.DefaultCandidate;
-import org.springframework.integration.leader.event.DefaultLeaderEventPublisher;
-import org.springframework.integration.leader.event.LeaderEventPublisher;
-
-/**
- * @author Gytis Trikleris
- */
-@Configuration(proxyBeanMethods = false)
-@EnableConfigurationProperties(LeaderProperties.class)
-@ConditionalOnBean(KubernetesClient.class)
-@ConditionalOnProperty(value = "spring.cloud.kubernetes.leader.enabled", matchIfMissing = true)
-@ConditionalOnLeaderElectionDisabled
-public class Fabric8LeaderAutoConfiguration {
-
-	/*
-	 * Used for publishing application events that happen: granted, revoked or failed to
-	 * acquire mutex.
-	 */
-	@Bean
-	@ConditionalOnMissingBean(LeaderEventPublisher.class)
-	public LeaderEventPublisher defaultLeaderEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
-		return new DefaultLeaderEventPublisher(applicationEventPublisher);
-	}
-
-	/*
-	 * This can be thought as "self" or the pod that participates in leader election
-	 * process. The implementation that we return simply logs events that happen during
-	 * that process.
-	 */
-	@Bean
-	public Candidate candidate(LeaderProperties leaderProperties) throws UnknownHostException {
-		String id = LeaderUtils.hostName();
-		String role = leaderProperties.getRole();
-		return new DefaultCandidate(id, role);
-	}
-
-	/*
-	 * Add an info contributor with leader information.
-	 */
-	@Bean
-	@ConditionalOnClass(InfoContributor.class)
-	@ConditionalOnEnabledInfoContributor("leader")
-	public LeaderInfoContributor leaderInfoContributor(Fabric8LeadershipController fabric8LeadershipController,
-			Candidate candidate) {
-		return new LeaderInfoContributor(fabric8LeadershipController, candidate);
-	}
-
-	/**
-	 * watches the readiness of the pod. In case of a readiness change, it has to go
-	 * through leader process again.
-	 */
-	@Bean
-	public Fabric8PodReadinessWatcher hostPodWatcher(Candidate candidate, KubernetesClient kubernetesClient,
-			Fabric8LeadershipController fabric8LeadershipController) {
-		return new Fabric8PodReadinessWatcher(candidate.getId(), kubernetesClient, fabric8LeadershipController);
-	}
-
-	@Bean
-	public Fabric8LeadershipController leadershipController(Candidate candidate, LeaderProperties leaderProperties,
-			LeaderEventPublisher leaderEventPublisher, KubernetesClient kubernetesClient) {
-		return new Fabric8LeadershipController(candidate, leaderProperties, leaderEventPublisher, kubernetesClient);
-	}
-
-	@Bean
-	public Fabric8LeaderRecordWatcher leaderRecordWatcher(LeaderProperties leaderProperties,
-			Fabric8LeadershipController fabric8LeadershipController, KubernetesClient kubernetesClient) {
-		return new Fabric8LeaderRecordWatcher(leaderProperties, fabric8LeadershipController, kubernetesClient);
-	}
-
-	@Bean
-	public LeaderInitiator leaderInitiator(LeaderProperties leaderProperties,
-			Fabric8LeadershipController fabric8LeadershipController,
-			Fabric8LeaderRecordWatcher fabric8LeaderRecordWatcher, Fabric8PodReadinessWatcher hostPodWatcher) {
-		return new LeaderInitiator(leaderProperties, fabric8LeadershipController, fabric8LeaderRecordWatcher,
-				hostPodWatcher);
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderRecordWatcher.java b/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderRecordWatcher.java
deleted file mode 100644
index dacadebab3..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderRecordWatcher.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import java.util.concurrent.locks.ReentrantLock;
-
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.Watch;
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
-
-import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderRecordWatcher;
-import org.springframework.core.log.LogAccessor;
-
-import static org.springframework.cloud.kubernetes.commons.leader.LeaderUtils.guarded;
-
-/**
- * @author Gytis Trikleris
- */
-public class Fabric8LeaderRecordWatcher implements LeaderRecordWatcher, Watcher {
-
-	private static final LogAccessor LOGGER = new LogAccessor(Fabric8LeaderRecordWatcher.class);
-
-	private final ReentrantLock lock = new ReentrantLock();
-
-	private final Fabric8LeadershipController fabric8LeadershipController;
-
-	private final LeaderProperties leaderProperties;
-
-	private final KubernetesClient kubernetesClient;
-
-	private volatile Watch configMapWatch;
-
-	public Fabric8LeaderRecordWatcher(LeaderProperties leaderProperties,
-			Fabric8LeadershipController fabric8LeadershipController, KubernetesClient kubernetesClient) {
-		this.fabric8LeadershipController = fabric8LeadershipController;
-		this.leaderProperties = leaderProperties;
-		this.kubernetesClient = kubernetesClient;
-	}
-
-	public void start() {
-		if (configMapWatch == null) {
-			guarded(lock, () -> {
-				if (configMapWatch == null) {
-					LOGGER.debug(() -> "Starting leader record watcher");
-					configMapWatch = kubernetesClient.configMaps()
-						.inNamespace(leaderProperties.getNamespace(kubernetesClient.getNamespace()))
-						.withName(leaderProperties.getConfigMapName())
-						.watch(this);
-				}
-			});
-		}
-	}
-
-	public void stop() {
-		if (configMapWatch != null) {
-			guarded(lock, () -> {
-				if (configMapWatch != null) {
-					LOGGER.debug(() -> "Stopping leader record watcher");
-					configMapWatch.close();
-					configMapWatch = null;
-				}
-			});
-		}
-	}
-
-	@Override
-	public void eventReceived(Action action, ConfigMap configMap) {
-		LOGGER.debug(() -> action + " event received, triggering leadership update");
-
-		if (!Action.ERROR.equals(action)) {
-			fabric8LeadershipController.update();
-		}
-	}
-
-	@Override
-	public void onClose(WatcherException cause) {
-		if (cause != null) {
-			guarded(lock, () -> {
-				LOGGER.warn(() -> "Watcher stopped unexpectedly, will restart because of : " + cause);
-				configMapWatch = null;
-				start();
-			});
-		}
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeadershipController.java b/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeadershipController.java
deleted file mode 100644
index 5712573793..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeadershipController.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import java.util.Map;
-import java.util.concurrent.locks.ReentrantLock;
-
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.KubernetesClientException;
-
-import org.springframework.cloud.kubernetes.commons.leader.Leader;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
-import org.springframework.cloud.kubernetes.commons.leader.LeadershipController;
-import org.springframework.cloud.kubernetes.commons.leader.PodReadinessWatcher;
-import org.springframework.core.log.LogAccessor;
-import org.springframework.integration.leader.Candidate;
-import org.springframework.integration.leader.event.LeaderEventPublisher;
-
-import static org.springframework.cloud.kubernetes.commons.leader.LeaderUtils.guarded;
-
-/**
- * @author Gytis Trikleris
- */
-public class Fabric8LeadershipController extends LeadershipController {
-
-	private static final LogAccessor LOGGER = new LogAccessor(Fabric8LeadershipController.class);
-
-	private final KubernetesClient kubernetesClient;
-
-	private final ReentrantLock lock = new ReentrantLock();
-
-	public Fabric8LeadershipController(Candidate candidate, LeaderProperties leaderProperties,
-			LeaderEventPublisher leaderEventPublisher, KubernetesClient kubernetesClient) {
-		super(candidate, leaderProperties, leaderEventPublisher);
-		this.kubernetesClient = kubernetesClient;
-	}
-
-	@Override
-	public void update() {
-		guarded(lock, () -> {
-			LOGGER.debug(() -> "Checking leader state");
-			ConfigMap configMap = getConfigMap();
-			if (configMap == null && !leaderProperties.isCreateConfigMap()) {
-				LOGGER.warn("ConfigMap '" + leaderProperties.getConfigMapName()
-						+ "' does not exist and leaderProperties.isCreateConfigMap() "
-						+ "is false, cannot acquire leadership");
-				notifyOnFailedToAcquire();
-				return;
-			}
-			Leader leader = extractLeader(configMap);
-
-			if (leader != null && isPodReady(leader.getId())) {
-				handleLeaderChange(leader);
-				return;
-			}
-
-			if (leader != null && leader.isCandidate(candidate)) {
-				revoke(configMap);
-			}
-			else {
-				acquire(configMap);
-			}
-		});
-
-	}
-
-	public void revoke() {
-		guarded(lock, () -> {
-			ConfigMap configMap = getConfigMap();
-			Leader leader = extractLeader(configMap);
-
-			if (leader != null && leader.isCandidate(candidate)) {
-				revoke(configMap);
-			}
-		});
-	}
-
-	private void revoke(ConfigMap configMap) {
-		LOGGER.debug(() -> "Trying to revoke leadership from :" + candidate);
-
-		try {
-			String leaderKey = getLeaderKey();
-			removeConfigMapEntry(configMap, leaderKey);
-			handleLeaderChange(null);
-		}
-		catch (KubernetesClientException e) {
-			LOGGER.warn("Failure when revoking leadership for : " + candidate + "because : " + e.getMessage());
-		}
-	}
-
-	private void acquire(ConfigMap configMap) {
-		LOGGER.debug(() -> "Trying to acquire leadership for :" + candidate);
-
-		if (!isPodReady(candidate.getId())) {
-			LOGGER.debug("Pod : " + candidate + "is not ready at the moment, cannot acquire leadership");
-			return;
-		}
-
-		try {
-			Map data = getLeaderData(candidate);
-
-			if (configMap == null) {
-				createConfigMap(data);
-			}
-			else {
-				updateConfigMapEntry(configMap, data);
-			}
-
-			Leader newLeader = new Leader(candidate.getRole(), candidate.getId());
-			handleLeaderChange(newLeader);
-		}
-		catch (KubernetesClientException e) {
-			LOGGER.warn(() -> "Failure when acquiring leadership for : " + candidate + " because : " + e.getMessage());
-			notifyOnFailedToAcquire();
-		}
-	}
-
-	@Override
-	protected PodReadinessWatcher createPodReadinessWatcher(String localLeaderId) {
-		return new Fabric8PodReadinessWatcher(localLeaderId, kubernetesClient, this);
-	}
-
-	private Leader extractLeader(ConfigMap configMap) {
-		if (configMap == null) {
-			return null;
-		}
-
-		return extractLeader(configMap.getData());
-	}
-
-	private boolean isPodReady(String name) {
-		return kubernetesClient.pods().withName(name).isReady();
-	}
-
-	private ConfigMap getConfigMap() {
-		return kubernetesClient.configMaps()
-			.inNamespace(leaderProperties.getNamespace(kubernetesClient.getNamespace()))
-			.withName(leaderProperties.getConfigMapName())
-			.get();
-	}
-
-	private void createConfigMap(Map data) {
-		LOGGER.debug(() -> "Creating new config map with data: " + data);
-
-		ConfigMap newConfigMap = new ConfigMapBuilder().withNewMetadata()
-			.withName(leaderProperties.getConfigMapName())
-			.addToLabels(PROVIDER_KEY, PROVIDER)
-			.addToLabels(KIND_KEY, KIND)
-			.endMetadata()
-			.addToData(data)
-			.build();
-
-		kubernetesClient.configMaps()
-			.inNamespace(leaderProperties.getNamespace(kubernetesClient.getNamespace()))
-			.resource(newConfigMap)
-			.create();
-	}
-
-	private void updateConfigMapEntry(ConfigMap configMap, Map newData) {
-		LOGGER.debug(() -> "Adding new data to config map: " + newData);
-		ConfigMap newConfigMap = new ConfigMapBuilder(configMap).addToData(newData).build();
-		updateConfigMap(configMap, newConfigMap);
-	}
-
-	private void removeConfigMapEntry(ConfigMap configMap, String key) {
-		LOGGER.debug(() -> "Removing config map entry: " + key);
-		ConfigMap newConfigMap = new ConfigMapBuilder(configMap).removeFromData(key).build();
-		updateConfigMap(configMap, newConfigMap);
-	}
-
-	private void updateConfigMap(ConfigMap oldConfigMap, ConfigMap newConfigMap) {
-		String oldResourceVersion = oldConfigMap.getMetadata().getResourceVersion();
-		kubernetesClient.configMaps()
-			.inNamespace(leaderProperties.getNamespace(kubernetesClient.getNamespace()))
-			.resource(newConfigMap)
-			.lockResourceVersion(oldResourceVersion)
-			.update();
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8PodReadinessWatcher.java b/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8PodReadinessWatcher.java
deleted file mode 100644
index 8932cd6b6c..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8PodReadinessWatcher.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import java.util.concurrent.locks.ReentrantLock;
-
-import io.fabric8.kubernetes.api.model.Pod;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.Watch;
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
-import io.fabric8.kubernetes.client.dsl.PodResource;
-import io.fabric8.kubernetes.client.readiness.Readiness;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.cloud.kubernetes.commons.leader.PodReadinessWatcher;
-import org.springframework.core.log.LogAccessor;
-
-import static org.springframework.cloud.kubernetes.commons.leader.LeaderUtils.guarded;
-
-/**
- * @author Gytis Trikleris
- */
-public class Fabric8PodReadinessWatcher implements PodReadinessWatcher, Watcher {
-
-	private static final LogAccessor LOGGER = new LogAccessor(LogFactory.getLog(Fabric8PodReadinessWatcher.class));
-
-	private final ReentrantLock lock = new ReentrantLock();
-
-	private final String podName;
-
-	private final KubernetesClient kubernetesClient;
-
-	private final Fabric8LeadershipController fabric8LeadershipController;
-
-	private volatile boolean previousState;
-
-	private volatile Watch watch;
-
-	public Fabric8PodReadinessWatcher(String podName, KubernetesClient kubernetesClient,
-			Fabric8LeadershipController fabric8LeadershipController) {
-		this.podName = podName;
-		this.kubernetesClient = kubernetesClient;
-		this.fabric8LeadershipController = fabric8LeadershipController;
-	}
-
-	@Override
-	public void start() {
-		if (watch == null) {
-			guarded(lock, () -> {
-				if (watch == null) {
-					LOGGER.debug(() -> "Starting pod readiness watcher for :" + podName);
-					PodResource podResource = kubernetesClient.pods().withName(podName);
-					previousState = podResource.isReady();
-					watch = podResource.watch(this);
-				}
-			});
-		}
-	}
-
-	@Override
-	public void stop() {
-		if (watch != null) {
-			guarded(lock, () -> {
-				if (watch != null) {
-					LOGGER.debug(() -> "Stopping pod readiness watcher for :" + podName);
-					watch.close();
-					watch = null;
-				}
-			});
-		}
-	}
-
-	@Override
-	public void eventReceived(Action action, Pod pod) {
-		boolean currentState = Readiness.isPodReady(pod);
-		if (previousState != currentState) {
-			guarded(lock, () -> {
-				if (previousState != currentState) {
-					LOGGER.debug(() -> "readiness status changed for pod : " + podName + " to state: " + currentState
-							+ ", triggering leadership update");
-					previousState = currentState;
-					fabric8LeadershipController.update();
-				}
-			});
-		}
-	}
-
-	@Override
-	public void onClose(WatcherException cause) {
-		if (cause != null) {
-			guarded(lock, () -> {
-				LOGGER.warn(() -> "Watcher stopped unexpectedly, will restart" + cause.getMessage());
-				watch = null;
-				start();
-			});
-		}
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionAutoConfiguration.java b/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionAutoConfiguration.java
index 56f7d5231d..9cf004b139 100644
--- a/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionAutoConfiguration.java
+++ b/spring-cloud-kubernetes-fabric8-leader/src/main/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionAutoConfiguration.java
@@ -45,9 +45,9 @@
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.log.LogAccessor;
 
-import static org.springframework.cloud.kubernetes.commons.leader.LeaderUtils.COORDINATION_GROUP;
-import static org.springframework.cloud.kubernetes.commons.leader.LeaderUtils.COORDINATION_VERSION;
-import static org.springframework.cloud.kubernetes.commons.leader.LeaderUtils.LEASE;
+import static org.springframework.cloud.kubernetes.commons.leader.election.LeaderUtils.COORDINATION_GROUP;
+import static org.springframework.cloud.kubernetes.commons.leader.election.LeaderUtils.COORDINATION_VERSION;
+import static org.springframework.cloud.kubernetes.commons.leader.election.LeaderUtils.LEASE;
 
 /**
  * @author wind57
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderAutoConfigurationTests.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderAutoConfigurationTests.java
deleted file mode 100644
index 35373df243..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderAutoConfigurationTests.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import org.junit.jupiter.api.Test;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.server.LocalManagementPort;
-import org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;
-import org.springframework.http.MediaType;
-import org.springframework.test.web.reactive.server.WebTestClient;
-
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
-		properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.leader.autoStartup=false",
-				"management.endpoints.web.exposure.include=info", "management.endpoint.info.show-details=always",
-				"management.info.kubernetes.enabled=true" })
-@AutoConfigureWebTestClient
-class Fabric8LeaderAutoConfigurationTests {
-
-	@LocalManagementPort
-	private int port;
-
-	@Autowired
-	private WebTestClient webClient;
-
-	@Test
-	void contextLoads() {
-	}
-
-	@Test
-	void infoEndpointShouldContainLeaderElection() {
-		webClient.get()
-			.uri("http://localhost:{port}/actuator/info", port)
-			.accept(MediaType.APPLICATION_JSON)
-			.exchange()
-			.expectStatus()
-			.isOk()
-			.expectBody()
-			.jsonPath("kubernetes")
-			.exists()
-			.jsonPath("leaderElection")
-			.exists()
-			.jsonPath("leaderElection.leaderId")
-			.exists();
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderContextTest.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderContextTest.java
deleted file mode 100644
index e000a79112..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderContextTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import java.util.Optional;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-
-import org.springframework.cloud.kubernetes.commons.leader.Leader;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderContext;
-import org.springframework.integration.leader.Candidate;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.verify;
-
-/**
- * @author Gytis Trikleris
- */
-class Fabric8LeaderContextTest {
-
-	private final Candidate mockCandidate = Mockito.mock(Candidate.class);
-
-	private final Fabric8LeadershipController mockFabric8LeadershipController = Mockito
-		.mock(Fabric8LeadershipController.class);
-
-	private final Leader mockLeader = Mockito.mock(Leader.class);
-
-	private LeaderContext leaderContext;
-
-	@BeforeEach
-	void beforeEach() {
-		leaderContext = new LeaderContext(mockCandidate, mockFabric8LeadershipController);
-	}
-
-	@Test
-	void testIsLeaderWithoutLeader() {
-		Mockito.when(mockFabric8LeadershipController.getLocalLeader()).thenReturn(Optional.empty());
-		boolean result = leaderContext.isLeader();
-		assertThat(result).isFalse();
-	}
-
-	@Test
-	void testIsLeaderWithAnotherLeader() {
-		Mockito.when(mockFabric8LeadershipController.getLocalLeader()).thenReturn(Optional.of(mockLeader));
-		boolean result = leaderContext.isLeader();
-		assertThat(result).isFalse();
-	}
-
-	@Test
-	void testIsLeaderWhenLeader() {
-		Mockito.when(mockFabric8LeadershipController.getLocalLeader()).thenReturn(Optional.of(mockLeader));
-		Mockito.when(mockLeader.isCandidate(mockCandidate)).thenReturn(true);
-		boolean result = this.leaderContext.isLeader();
-		assertThat(result).isTrue();
-	}
-
-	@Test
-	void shouldYieldLeadership() {
-		leaderContext.yield();
-		verify(mockFabric8LeadershipController).revoke();
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderInfoContributorDisabledTests.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderInfoContributorDisabledTests.java
deleted file mode 100644
index 363c929f73..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderInfoContributorDisabledTests.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import org.junit.jupiter.api.Test;
-
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.SpringBootConfiguration;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderInfoContributor;
-import org.springframework.context.ApplicationContext;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-/**
- * Tests that verify LeaderInfoContributor can be disabled via configuration property.
- */
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
-		properties = { "spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.leader.autoStartup=false",
-				"management.info.leader.enabled=false" })
-class Fabric8LeaderInfoContributorDisabledTests {
-
-	@Autowired
-	private ApplicationContext context;
-
-	/**
-	 * Test that the LeaderInfoContributor bean is NOT present when
-	 * management.info.leader.enabled=false
-	 */
-	@Test
-	void leaderInfoContributorShouldNotBePresent() {
-		assertThatThrownBy(() -> context.getBean(LeaderInfoContributor.class))
-			.isInstanceOf(NoSuchBeanDefinitionException.class);
-	}
-
-	@SpringBootConfiguration
-	@EnableAutoConfiguration
-	protected static class TestConfig {
-
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderInitiatorTest.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderInitiatorTest.java
deleted file mode 100644
index 3d44002463..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderInitiatorTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import java.time.Duration;
-
-import org.awaitility.Awaitility;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-
-import org.springframework.cloud.kubernetes.commons.leader.LeaderInitiator;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.verify;
-import static org.mockito.internal.verification.VerificationModeFactory.atLeastOnce;
-
-/**
- * @author Gytis Trikleris
- */
-class Fabric8LeaderInitiatorTest {
-
-	private final LeaderProperties leaderProperties = new LeaderProperties();
-
-	private final Fabric8LeadershipController mockFabric8LeadershipController = Mockito
-		.mock(Fabric8LeadershipController.class);
-
-	private final Fabric8LeaderRecordWatcher mockFabric8LeaderRecordWatcher = Mockito
-		.mock(Fabric8LeaderRecordWatcher.class);
-
-	private final Fabric8PodReadinessWatcher mockFabric8PodReadinessWatcher = Mockito
-		.mock(Fabric8PodReadinessWatcher.class);
-
-	private final Runnable runnable = Mockito.mock(Runnable.class);
-
-	private LeaderInitiator leaderInitiator;
-
-	@BeforeEach
-	void beforeEach() {
-		leaderInitiator = new LeaderInitiator(leaderProperties, mockFabric8LeadershipController,
-				mockFabric8LeaderRecordWatcher, mockFabric8PodReadinessWatcher);
-	}
-
-	@AfterEach
-	void afterEach() {
-		leaderInitiator.stop();
-		Mockito.reset(mockFabric8LeadershipController, mockFabric8LeaderRecordWatcher, mockFabric8PodReadinessWatcher);
-	}
-
-	@Test
-	void testIsAutoStartup() {
-		assertThat(leaderInitiator.isAutoStartup()).isTrue();
-	}
-
-	@Test
-	void shouldStart() {
-		leaderProperties.setUpdatePeriod(Duration.ofMillis(1L));
-
-		leaderInitiator.start();
-
-		assertThat(leaderInitiator.isRunning()).isTrue();
-		verify(mockFabric8LeaderRecordWatcher).start();
-		verify(mockFabric8PodReadinessWatcher).start();
-
-		Awaitility.await().untilAsserted(() -> verify(mockFabric8LeadershipController, atLeastOnce()).update());
-
-	}
-
-	@Test
-	void shouldStartOnlyOnce() {
-		leaderInitiator.start();
-		leaderInitiator.start();
-
-		verify(mockFabric8LeaderRecordWatcher).start();
-	}
-
-	@Test
-	void shouldStop() {
-		leaderInitiator.start();
-		leaderInitiator.stop();
-
-		assertThat(leaderInitiator.isRunning()).isFalse();
-		verify(mockFabric8LeaderRecordWatcher).stop();
-		verify(mockFabric8PodReadinessWatcher).start();
-		verify(mockFabric8LeadershipController).revoke();
-	}
-
-	@Test
-	void shouldStopOnlyOnce() {
-		leaderInitiator.start();
-		leaderInitiator.stop();
-		leaderInitiator.stop();
-
-		verify(mockFabric8LeaderRecordWatcher).stop();
-	}
-
-	@Test
-	void shouldStopAndExecuteCallback() {
-		leaderInitiator.start();
-		leaderInitiator.stop(runnable);
-
-		assertThat(leaderInitiator.isRunning()).isFalse();
-		verify(mockFabric8LeaderRecordWatcher).stop();
-		verify(mockFabric8PodReadinessWatcher).start();
-		verify(mockFabric8LeadershipController).revoke();
-		verify(runnable).run();
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderRecordWatcherTest.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderRecordWatcherTest.java
deleted file mode 100644
index 9f72712f22..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderRecordWatcherTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.api.model.ConfigMapList;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.Watch;
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
-import io.fabric8.kubernetes.client.dsl.MixedOperation;
-import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
-import io.fabric8.kubernetes.client.dsl.Resource;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-
-import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
-
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-/**
- * @author Gytis Trikleris
- */
-class Fabric8LeaderRecordWatcherTest {
-
-	private final LeaderProperties mockLeaderProperties = Mockito.mock(LeaderProperties.class);
-
-	private final Fabric8LeadershipController mockFabric8LeadershipController = Mockito
-		.mock(Fabric8LeadershipController.class);
-
-	private final KubernetesClient mockKubernetesClient = Mockito.mock(KubernetesClient.class);
-
-	@SuppressWarnings("unchecked")
-	private final MixedOperation> mockConfigMapsOperation = Mockito
-		.mock(MixedOperation.class);
-
-	@SuppressWarnings("unchecked")
-	private final NonNamespaceOperation> mockInNamespaceOperation = Mockito
-		.mock(NonNamespaceOperation.class);
-
-	@SuppressWarnings("unchecked")
-	private final Resource mockWithNameResource = Mockito.mock(Resource.class);
-
-	private final Watch mockWatch = Mockito.mock(Watch.class);
-
-	private final ConfigMap mockConfigMap = Mockito.mock(ConfigMap.class);
-
-	private final WatcherException mockKubernetesClientException = Mockito.mock(WatcherException.class);
-
-	private Fabric8LeaderRecordWatcher watcher;
-
-	@BeforeEach
-	void beforeEach() {
-		watcher = new Fabric8LeaderRecordWatcher(mockLeaderProperties, mockFabric8LeadershipController,
-				mockKubernetesClient);
-	}
-
-	@Test
-	void shouldStartOnce() {
-		initStubs();
-		watcher.start();
-		watcher.start();
-		verify(mockWithNameResource).watch(watcher);
-	}
-
-	@Test
-	void shouldStopOnce() {
-		initStubs();
-		watcher.start();
-		watcher.stop();
-		watcher.stop();
-		verify(mockWatch).close();
-	}
-
-	@Test
-	void shouldHandleEvent() {
-		watcher.eventReceived(Watcher.Action.ADDED, mockConfigMap);
-		watcher.eventReceived(Watcher.Action.DELETED, mockConfigMap);
-		watcher.eventReceived(Watcher.Action.MODIFIED, mockConfigMap);
-		verify(mockFabric8LeadershipController, times(3)).update();
-	}
-
-	@Test
-	void shouldIgnoreErrorEvent() {
-		watcher.eventReceived(Watcher.Action.ERROR, mockConfigMap);
-		verify(mockFabric8LeadershipController, times(0)).update();
-	}
-
-	@Test
-	void shouldHandleClose() {
-		initStubs();
-		watcher.onClose(mockKubernetesClientException);
-		verify(mockWithNameResource).watch(watcher);
-	}
-
-	@Test
-	void shouldIgnoreCloseWithoutCause() {
-		watcher.onClose(null);
-		verify(mockWithNameResource, times(0)).watch(watcher);
-	}
-
-	private void initStubs() {
-		Mockito.when(mockKubernetesClient.configMaps()).thenReturn(mockConfigMapsOperation);
-		Mockito.when(mockConfigMapsOperation.inNamespace(null)).thenReturn(mockInNamespaceOperation);
-		Mockito.when(mockInNamespaceOperation.withName(null)).thenReturn(mockWithNameResource);
-		Mockito.when(mockWithNameResource.watch(watcher)).thenReturn(mockWatch);
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderTest.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderTest.java
deleted file mode 100644
index d027177694..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeaderTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.cloud.kubernetes.commons.leader.Leader;
-import org.springframework.integration.leader.Candidate;
-import org.springframework.integration.leader.DefaultCandidate;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * @author Gytis Trikleris
- */
-class Fabric8LeaderTest {
-
-	private static final String ROLE = "test-role";
-
-	private static final String ID = "test-id";
-
-	private Leader leader;
-
-	@BeforeEach
-	void before() {
-		leader = new Leader(ROLE, ID);
-	}
-
-	@Test
-	void shouldGetRole() {
-		assertThat(leader.getRole()).isEqualTo(ROLE);
-	}
-
-	@Test
-	void shouldGetId() {
-		assertThat(leader.getId()).isEqualTo(ID);
-	}
-
-	@Test
-	void shouldCheckWithNullCandidate() {
-		assertThat(leader.isCandidate(null)).isEqualTo(false);
-	}
-
-	@Test
-	void shouldCheckCandidate() {
-		Candidate candidate = new DefaultCandidate(ID, ROLE);
-		assertThat(leader.isCandidate(candidate)).isTrue();
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeadershipControllerTest.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeadershipControllerTest.java
deleted file mode 100644
index eb55e0025f..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8LeadershipControllerTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.api.model.ConfigMapList;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
-import io.fabric8.kubernetes.client.dsl.Resource;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mockito;
-
-import org.springframework.boot.test.system.CapturedOutput;
-import org.springframework.boot.test.system.OutputCaptureExtension;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties;
-import org.springframework.integration.leader.Candidate;
-import org.springframework.integration.leader.event.LeaderEventPublisher;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-/**
- * @author Gytis Trikleris
- */
-public class Fabric8LeadershipControllerTest {
-
-	private final Candidate mockCandidate = Mockito.mock(Candidate.class);
-
-	private final LeaderProperties mockLeaderProperties = Mockito.mock(LeaderProperties.class);
-
-	private final LeaderEventPublisher mockLeaderEventPublisher = Mockito.mock(LeaderEventPublisher.class);
-
-	private final KubernetesClient mockKubernetesClient = Mockito.mock(KubernetesClient.class,
-			Mockito.RETURNS_DEEP_STUBS);
-
-	private Fabric8LeadershipController fabric8LeadershipController;
-
-	@BeforeEach
-	void beforeEach() {
-		fabric8LeadershipController = new Fabric8LeadershipController(mockCandidate, mockLeaderProperties,
-				mockLeaderEventPublisher, mockKubernetesClient);
-	}
-
-	@Test
-	void shouldGetEmptyLocalLeader() {
-		assertThat(fabric8LeadershipController.getLocalLeader().isPresent()).isFalse();
-	}
-
-	@Test
-	@ExtendWith(OutputCaptureExtension.class)
-	void whenNonExistentConfigmapAndCreationNotAllowedStopLeadershipAcquire(CapturedOutput output) {
-		// given
-		String testNamespace = "test-namespace";
-		String testConfigmap = "test-configmap";
-		@SuppressWarnings("unchecked")
-		Resource mockResource = Mockito.mock(Resource.class);
-		@SuppressWarnings("unchecked")
-		NonNamespaceOperation> mockNonNamespaceOperation = Mockito
-			.mock(NonNamespaceOperation.class);
-
-		Fabric8LeadershipController fabric8LeadershipController = new Fabric8LeadershipController(mockCandidate,
-				mockLeaderProperties, mockLeaderEventPublisher, mockKubernetesClient);
-
-		when(mockLeaderProperties.isCreateConfigMap()).thenReturn(false);
-		when(mockLeaderProperties.isPublishFailedEvents()).thenReturn(true);
-		when(mockLeaderProperties.getConfigMapName()).thenReturn(testConfigmap);
-		when(mockKubernetesClient.getNamespace()).thenReturn(testNamespace);
-		when(mockLeaderProperties.getNamespace(anyString())).thenReturn(testNamespace);
-		when(mockKubernetesClient.configMaps().inNamespace(anyString())).thenReturn(mockNonNamespaceOperation);
-		when(mockNonNamespaceOperation.withName(any())).thenReturn(mockResource);
-		when(mockResource.get()).thenReturn(null);
-
-		// when
-		fabric8LeadershipController.update();
-
-		// then
-		assertThat(output).contains(
-				"ConfigMap 'test-configmap' does not exist and leaderProperties.isCreateConfigMap() is false, cannot acquire leadership");
-		verify(mockLeaderEventPublisher).publishOnFailedToAcquire(any(), any(), any());
-
-		verify(mockKubernetesClient, never()).pods();
-		verify(mockCandidate, never()).getId();
-		verify(mockLeaderProperties, never()).getLeaderIdPrefix();
-		verify(mockLeaderEventPublisher, never()).publishOnGranted(any(), any(), any());
-		verify(mockLeaderEventPublisher, never()).publishOnRevoked(any(), any(), any());
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8PodReadinessWatcherTest.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8PodReadinessWatcherTest.java
deleted file mode 100644
index 77007af1fc..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/Fabric8PodReadinessWatcherTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader;
-
-import io.fabric8.kubernetes.api.model.Pod;
-import io.fabric8.kubernetes.api.model.PodList;
-import io.fabric8.kubernetes.api.model.PodStatus;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.Watch;
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
-import io.fabric8.kubernetes.client.dsl.MixedOperation;
-import io.fabric8.kubernetes.client.dsl.PodResource;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-/**
- * @author Gytis Trikleris
- */
-public class Fabric8PodReadinessWatcherTest {
-
-	private static final String POD_NAME = "test-pod";
-
-	private final Fabric8LeadershipController mockFabric8LeadershipController = Mockito
-		.mock(Fabric8LeadershipController.class);
-
-	private final KubernetesClient mockKubernetesClient = Mockito.mock(KubernetesClient.class);
-
-	@SuppressWarnings("unchecked")
-	private final MixedOperation mockPodsOperation = Mockito.mock(MixedOperation.class);
-
-	private final PodResource mockPodResource = Mockito.mock(PodResource.class);
-
-	private final Pod mockPod = Mockito.mock(Pod.class);
-
-	private final PodStatus mockPodStatus = Mockito.mock(PodStatus.class);
-
-	private final Watch mockWatch = Mockito.mock(Watch.class);
-
-	private final WatcherException mockKubernetesClientException = Mockito.mock(WatcherException.class);
-
-	private Fabric8PodReadinessWatcher watcher;
-
-	@BeforeEach
-	void beforeEach() {
-		watcher = new Fabric8PodReadinessWatcher(POD_NAME, mockKubernetesClient, mockFabric8LeadershipController);
-	}
-
-	@Test
-	void shouldStartOnce() {
-		initStubs();
-		watcher.start();
-		watcher.start();
-		verify(mockPodResource).watch(watcher);
-	}
-
-	@Test
-	void shouldStopOnce() {
-		initStubs();
-		watcher.start();
-		watcher.stop();
-		watcher.stop();
-		verify(mockWatch).close();
-	}
-
-	@Test
-	void shouldHandleEventWithStateChange() {
-		initStubs();
-		Mockito.when(mockPodResource.isReady()).thenReturn(true);
-		Mockito.when(mockPod.getStatus()).thenReturn(mockPodStatus);
-
-		watcher.start();
-		watcher.eventReceived(Watcher.Action.ADDED, mockPod);
-		verify(mockFabric8LeadershipController).update();
-	}
-
-	@Test
-	void shouldIgnoreEventIfStateDoesNotChange() {
-		initStubs();
-		Mockito.when(mockPod.getStatus()).thenReturn(mockPodStatus);
-
-		watcher.start();
-		watcher.eventReceived(Watcher.Action.ADDED, mockPod);
-		verify(mockFabric8LeadershipController, times(0)).update();
-	}
-
-	@Test
-	void shouldHandleClose() {
-		initStubs();
-		watcher.onClose(mockKubernetesClientException);
-		verify(mockPodResource).watch(watcher);
-	}
-
-	@Test
-	void shouldIgnoreCloseWithoutCause() {
-		watcher.onClose(null);
-		verify(mockPodResource, times(0)).watch(watcher);
-	}
-
-	private void initStubs() {
-		Mockito.when(mockKubernetesClient.pods()).thenReturn(mockPodsOperation);
-		Mockito.when(mockPodsOperation.withName(POD_NAME)).thenReturn(mockPodResource);
-		Mockito.when(mockPodResource.watch(watcher)).thenReturn(mockWatch);
-	}
-
-}
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderAutoConfigurationTests.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderAutoConfigurationTests.java
index f878317c98..ab9eeb94c4 100644
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderAutoConfigurationTests.java
+++ b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderAutoConfigurationTests.java
@@ -16,13 +16,15 @@
 
 package org.springframework.cloud.kubernetes.fabric8.leader.election;
 
+import java.util.function.BooleanSupplier;
+
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 
-import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.TestConfiguration;
 import org.springframework.boot.test.context.runner.ApplicationContextRunner;
-import org.springframework.cloud.kubernetes.fabric8.leader.Fabric8LeaderAutoConfiguration;
-import org.springframework.cloud.kubernetes.fabric8.leader.Fabric8PodReadinessWatcher;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
 
 /**
  * tests that ensure 'spring.cloud.kubernetes.leader.election' enabled correct
@@ -38,23 +40,21 @@ class Fabric8LeaderAutoConfigurationTests {
 	 *
 	 *     As such:
 	 *
-	 *     - Fabric8LeaderAutoConfiguration must be picked up
-	 *     - Fabric8LeaderElectionAutoConfiguration must not be picked up
+	 *     - Fabric8LeaderElectionAutoConfiguration          is present
+	 *     - Fabric8LeaderElectionCallbacksAutoConfiguration is present
 	 * 
*/ @Test void leaderElectionAnnotationMissing() { new ApplicationContextRunner().withUserConfiguration(Fabric8LeaderApp.class) - .withConfiguration(AutoConfigurations.of(Fabric8LeaderAutoConfiguration.class, - Fabric8LeaderElectionAutoConfiguration.class, - Fabric8LeaderElectionCallbacksAutoConfiguration.class)) + .withAllowBeanDefinitionOverriding(true) + .withUserConfiguration(Fabric8LeaderElectionAutoConfiguration.class, + Fabric8LeaderElectionCallbacksAutoConfiguration.class, TestConfig.class) + .withPropertyValues("spring.main.cloud-platform=KUBERNETES") .run(context -> { - - // this one comes from Fabric8LeaderElectionAutoConfiguration - Assertions.assertThat(context).doesNotHaveBean(Fabric8LeaderElectionInitiator.class); - - // this one comes from Fabric8LeaderAutoConfiguration - Assertions.assertThat(context).hasSingleBean(Fabric8PodReadinessWatcher.class); + // matchIfMissing = true in the annotation, so both are present + Assertions.assertThat(context).hasSingleBean(Fabric8LeaderElectionAutoConfiguration.class); + Assertions.assertThat(context).hasSingleBean(Fabric8LeaderElectionCallbacksAutoConfiguration.class); }); } @@ -64,30 +64,26 @@ void leaderElectionAnnotationMissing() { * * As such: * - * - Fabric8LeaderAutoConfiguration must be picked up - * - Fabric8LeaderElectionAutoConfiguration must not be picked up + * - Fabric8LeaderElectionAutoConfiguration is not present + * - Fabric8LeaderElectionCallbacksAutoConfiguration is not present * */ @Test void leaderElectionAnnotationPresentEqualToFalse() { - new ApplicationContextRunner().withUserConfiguration(Fabric8LeaderApp.class) - .withConfiguration(AutoConfigurations.of(Fabric8LeaderAutoConfiguration.class, - Fabric8LeaderElectionAutoConfiguration.class, - Fabric8LeaderElectionCallbacksAutoConfiguration.class)) - .withPropertyValues("spring.cloud.kubernetes.leader.election.enabled=false") + new ApplicationContextRunner() + .withUserConfiguration(Fabric8LeaderApp.class, Fabric8LeaderElectionAutoConfiguration.class, + Fabric8LeaderElectionCallbacksAutoConfiguration.class, TestConfig.class) + .withPropertyValues("spring.cloud.kubernetes.leader.election.enabled=false", + "spring.main.cloud-platform=KUBERNETES") .run(context -> { - - // this one comes from Fabric8LeaderElectionAutoConfiguration - Assertions.assertThat(context).doesNotHaveBean(Fabric8LeaderElectionInitiator.class); - - // this one comes from Fabric8LeaderAutoConfiguration - Assertions.assertThat(context).hasSingleBean(Fabric8PodReadinessWatcher.class); + Assertions.assertThat(context).doesNotHaveBean(Fabric8LeaderElectionAutoConfiguration.class); + Assertions.assertThat(context).doesNotHaveBean(Fabric8LeaderElectionCallbacksAutoConfiguration.class); }); } /** *
-	 *     - spring.cloud.kubernetes.leader.election = false
+	 *     - spring.cloud.kubernetes.leader.election = true
 	 *
 	 *     As such:
 	 *
@@ -97,20 +93,27 @@ void leaderElectionAnnotationPresentEqualToFalse() {
 	 */
 	@Test
 	void leaderElectionAnnotationPresentEqualToTrue() {
-		new ApplicationContextRunner().withUserConfiguration(Fabric8LeaderApp.class)
-			.withConfiguration(AutoConfigurations.of(Fabric8LeaderAutoConfiguration.class,
-					Fabric8LeaderElectionAutoConfiguration.class,
-					Fabric8LeaderElectionCallbacksAutoConfiguration.class))
+		new ApplicationContextRunner()
+			.withUserConfiguration(Fabric8LeaderApp.class, Fabric8LeaderElectionAutoConfiguration.class,
+					Fabric8LeaderElectionCallbacksAutoConfiguration.class, TestConfig.class)
+			.withAllowBeanDefinitionOverriding(true)
 			.withPropertyValues("spring.cloud.kubernetes.leader.election.enabled=true",
-					"spring.main.cloud-platform=kubernetes")
+					"spring.main.cloud-platform=KUBERNETES")
 			.run(context -> {
+				Assertions.assertThat(context).hasSingleBean(Fabric8LeaderElectionAutoConfiguration.class);
+				Assertions.assertThat(context).hasSingleBean(Fabric8LeaderElectionCallbacksAutoConfiguration.class);
+			});
+	}
 
-				// this one comes from Fabric8LeaderElectionAutoConfiguration
-				Assertions.assertThat(context).hasSingleBean(Fabric8LeaderElectionInitiator.class);
+	@TestConfiguration
+	static class TestConfig {
+
+		@Bean
+		@Primary
+		BooleanSupplier podReadySupplier() {
+			return () -> false;
+		}
 
-				// this one comes from Fabric8LeaderAutoConfiguration
-				Assertions.assertThat(context).doesNotHaveBean(Fabric8PodReadinessWatcher.class);
-			});
 	}
 
 }
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsLeaderTest.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsLeaderTest.java
index 375628a527..3517024fea 100644
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsLeaderTest.java
+++ b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsLeaderTest.java
@@ -41,7 +41,7 @@
 import org.springframework.boot.test.context.TestConfiguration;
 import org.springframework.boot.test.web.server.LocalManagementPort;
 import org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderUtils;
+import org.springframework.cloud.kubernetes.commons.leader.election.LeaderUtils;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Primary;
 import org.springframework.http.MediaType;
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsNotLeaderTest.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsNotLeaderTest.java
index 9b4252a398..433babc24f 100644
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsNotLeaderTest.java
+++ b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsNotLeaderTest.java
@@ -41,7 +41,7 @@
 import org.springframework.boot.test.context.TestConfiguration;
 import org.springframework.boot.test.web.server.LocalManagementPort;
 import org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;
-import org.springframework.cloud.kubernetes.commons.leader.LeaderUtils;
+import org.springframework.cloud.kubernetes.commons.leader.election.LeaderUtils;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Primary;
 import org.springframework.http.MediaType;
diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderOldAndNewImplementationTests.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderOldAndNewImplementationTests.java
deleted file mode 100644
index 589ed75fe3..0000000000
--- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderOldAndNewImplementationTests.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright 2013-present the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.kubernetes.fabric8.leader.election;
-
-import io.fabric8.kubernetes.api.model.APIGroupList;
-import io.fabric8.kubernetes.api.model.APIGroupListBuilder;
-import io.fabric8.kubernetes.api.model.APIResourceBuilder;
-import io.fabric8.kubernetes.api.model.APIResourceListBuilder;
-import io.fabric8.kubernetes.api.model.ConfigMap;
-import io.fabric8.kubernetes.api.model.GroupVersionForDiscoveryBuilder;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.dsl.MixedOperation;
-import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
-import io.fabric8.kubernetes.client.dsl.PodResource;
-import io.fabric8.kubernetes.client.dsl.Resource;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-
-import org.springframework.boot.autoconfigure.AutoConfigurations;
-import org.springframework.boot.test.context.TestConfiguration;
-import org.springframework.boot.test.context.runner.ApplicationContextRunner;
-import org.springframework.cloud.kubernetes.commons.KubernetesCommonsAutoConfiguration;
-import org.springframework.cloud.kubernetes.fabric8.Fabric8AutoConfiguration;
-import org.springframework.cloud.kubernetes.fabric8.leader.Fabric8LeaderAutoConfiguration;
-import org.springframework.context.annotation.Bean;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests that prove that previous and new leader implementation works based on the flags
- * we set.
- *
- * @author wind57
- */
-class Fabric8LeaderOldAndNewImplementationTests {
-
-	private ApplicationContextRunner applicationContextRunner;
-
-	/**
-	 * 
-	 *     - 'spring.cloud.kubernetes.leader.enabled'           is not set
-	 *     - 'spring.cloud.kubernetes.leader.election.enabled'  is not set
-	 *
-	 *     As such :
-	 *
-	 *     - 'Fabric8LeaderAutoConfiguration'                   is active
-	 *     - 'Fabric8LeaderElectionAutoConfiguration'           is not active
-	 * 
- */ - @Test - void noFlagsSet() { - setup("spring.main.cloud-platform=KUBERNETES"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(Fabric8LeaderAutoConfiguration.class); - assertThat(context).doesNotHaveBean(Fabric8LeaderElectionAutoConfiguration.class); - }); - } - - /** - *
-	 *     - 'spring.cloud.kubernetes.leader.enabled'          =  true
-	 *     - 'spring.cloud.kubernetes.leader.election.enabled'    is not set
-	 *
-	 *     As such :
-	 *
-	 *     - 'Fabric8LeaderAutoConfiguration'                   is active
-	 *     - 'Fabric8LeaderElectionAutoConfiguration'           is not active
-	 * 
- */ - @Test - void oldImplementationEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.leader.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(Fabric8LeaderAutoConfiguration.class); - assertThat(context).doesNotHaveBean(Fabric8LeaderElectionAutoConfiguration.class); - }); - } - - /** - *
-	 *     - 'spring.cloud.kubernetes.leader.enabled'          = false
-	 *     - 'spring.cloud.kubernetes.leader.election.enabled'   is not set
-	 *
-	 *     As such :
-	 *
-	 *     - 'Fabric8LeaderAutoConfiguration'                   is not active
-	 *     - 'Fabric8LeaderElectionAutoConfiguration'           is not active
-	 * 
- */ - @Test - void oldImplementationDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.leader.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(Fabric8LeaderAutoConfiguration.class); - assertThat(context).doesNotHaveBean(Fabric8LeaderElectionAutoConfiguration.class); - }); - } - - /** - *
-	 *     - 'spring.cloud.kubernetes.leader.enabled'            is not set
-	 *     - 'spring.cloud.kubernetes.leader.election.enabled' = false
-	 *
-	 *     As such :
-	 *
-	 *     - 'Fabric8LeaderAutoConfiguration'                   is active
-	 *     - 'Fabric8LeaderElectionAutoConfiguration'           is not active
-	 * 
- */ - @Test - void newImplementationDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.leader.election.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).hasSingleBean(Fabric8LeaderAutoConfiguration.class); - assertThat(context).doesNotHaveBean(Fabric8LeaderElectionAutoConfiguration.class); - }); - } - - /** - *
-	 *     - 'spring.cloud.kubernetes.leader.enabled'            is not set
-	 *     - 'spring.cloud.kubernetes.leader.election.enabled' = true
-	 *
-	 *     As such :
-	 *
-	 *     - 'Fabric8LeaderAutoConfiguration'                   is not active
-	 *     - 'Fabric8LeaderElectionAutoConfiguration'           is active
-	 * 
- */ - @Test - void newImplementationEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.leader.election.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(Fabric8LeaderAutoConfiguration.class); - assertThat(context).hasSingleBean(Fabric8LeaderElectionAutoConfiguration.class); - }); - } - - /** - *
-	 *     - 'spring.cloud.kubernetes.leader.enabled'          = false
-	 *     - 'spring.cloud.kubernetes.leader.election.enabled' = false
-	 *
-	 *     As such :
-	 *
-	 *     - 'Fabric8LeaderAutoConfiguration'                   is not active
-	 *     - 'Fabric8LeaderElectionAutoConfiguration'           is not active
-	 * 
- */ - @Test - void bothDisabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.leader.enabled=false", - "spring.cloud.kubernetes.leader.election.enabled=false"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(Fabric8LeaderAutoConfiguration.class); - assertThat(context).doesNotHaveBean(Fabric8LeaderElectionAutoConfiguration.class); - }); - } - - /** - *
-	 *     - 'spring.cloud.kubernetes.leader.enabled'          = true
-	 *     - 'spring.cloud.kubernetes.leader.election.enabled' = true
-	 *
-	 *     As such :
-	 *
-	 *     - 'Fabric8LeaderAutoConfiguration'                   is not active
-	 *     - 'Fabric8LeaderElectionAutoConfiguration'           is active
-	 *
-	 *     You can't enable both of them, only the new one will work.
-	 * 
- */ - @Test - void bothEnabled() { - setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.leader.enabled=true", - "spring.cloud.kubernetes.leader.election.enabled=true"); - applicationContextRunner.run(context -> { - assertThat(context).doesNotHaveBean(Fabric8LeaderAutoConfiguration.class); - assertThat(context).hasSingleBean(Fabric8LeaderElectionAutoConfiguration.class); - }); - } - - private void setup(String... properties) { - applicationContextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(Fabric8LeaderElectionCallbacksAutoConfiguration.class, - Fabric8AutoConfiguration.class, KubernetesCommonsAutoConfiguration.class, - Fabric8LeaderElectionAutoConfiguration.class, Fabric8LeaderAutoConfiguration.class)) - .withUserConfiguration(Fabric8LeaderOldAndNewImplementationTests.Configuration.class) - .withPropertyValues(properties); - } - - @TestConfiguration - static class Configuration { - - @Bean - @SuppressWarnings({ "rawtypes", "unchecked" }) - KubernetesClient mockKubernetesClient() { - KubernetesClient client = Mockito.mock(KubernetesClient.class); - - Mockito.when(client.getNamespace()).thenReturn("namespace"); - - MixedOperation mixedOperation = Mockito.mock(MixedOperation.class); - NonNamespaceOperation nonNamespaceOperation = Mockito.mock(NonNamespaceOperation.class); - Mockito.when(client.configMaps()).thenReturn(mixedOperation); - - Mockito.when(mixedOperation.inNamespace(Mockito.anyString())).thenReturn(nonNamespaceOperation); - Resource configMapResource = Mockito.mock(Resource.class); - Mockito.when(nonNamespaceOperation.withName(Mockito.anyString())).thenReturn(configMapResource); - - Mockito.when(client.pods()).thenReturn(mixedOperation); - PodResource podResource = Mockito.mock(PodResource.class); - Mockito.when(mixedOperation.withName(Mockito.anyString())).thenReturn(podResource); - - Mockito.when(client.getApiResources("coordination.k8s.io/v1")) - .thenReturn( - new APIResourceListBuilder().withResources(new APIResourceBuilder().withKind("Lease").build()) - .build()); - - APIGroupList apiGroupList = new APIGroupListBuilder().addNewGroup() - .withVersions(new GroupVersionForDiscoveryBuilder().withGroupVersion("coordination.k8s.io/v1").build()) - .endGroup() - .build(); - - Mockito.when(client.getApiGroups()).thenReturn(apiGroupList); - return client; - } - - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-leader-election/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/AbstractLeaderElection.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-leader-election/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/AbstractLeaderElection.java index 7d0657cb3a..c5f494f7f8 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-leader-election/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/AbstractLeaderElection.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-leader-election/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/AbstractLeaderElection.java @@ -35,7 +35,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.system.OutputCaptureExtension; -import org.springframework.cloud.kubernetes.commons.leader.LeaderUtils; +import org.springframework.cloud.kubernetes.commons.leader.election.LeaderUtils; import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; From 5419abc975545eabaa89014b37a7662bcbdea5f3 Mon Sep 17 00:00:00 2001 From: wind57 Date: Fri, 19 Dec 2025 16:25:49 +0200 Subject: [PATCH 2/3] fix build Signed-off-by: wind57 --- ...ot.autoconfigure.AutoConfiguration.imports | 1 - .../Fabric8LeaderAutoConfigurationTests.java | 10 +++---- ...p.java => Fabric8LeaderConfiguration.java} | 4 ++- ...erElectionInfoContributorIsLeaderTest.java | 2 +- .../leader/election/FabricLeaderApp.java | 29 +++++++++++++++++++ 5 files changed, 38 insertions(+), 8 deletions(-) rename spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/{Fabric8LeaderApp.java => Fabric8LeaderConfiguration.java} (91%) create mode 100644 spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/FabricLeaderApp.java diff --git a/spring-cloud-kubernetes-fabric8-leader/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-kubernetes-fabric8-leader/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index c94b99ab84..f045c40845 100644 --- a/spring-cloud-kubernetes-fabric8-leader/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-cloud-kubernetes-fabric8-leader/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,3 +1,2 @@ -org.springframework.cloud.kubernetes.fabric8.leader.Fabric8LeaderAutoConfiguration org.springframework.cloud.kubernetes.fabric8.leader.election.Fabric8LeaderElectionCallbacksAutoConfiguration org.springframework.cloud.kubernetes.fabric8.leader.election.Fabric8LeaderElectionAutoConfiguration diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderAutoConfigurationTests.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderAutoConfigurationTests.java index ab9eeb94c4..2bc7913c01 100644 --- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderAutoConfigurationTests.java +++ b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderAutoConfigurationTests.java @@ -46,11 +46,11 @@ class Fabric8LeaderAutoConfigurationTests { */ @Test void leaderElectionAnnotationMissing() { - new ApplicationContextRunner().withUserConfiguration(Fabric8LeaderApp.class) + new ApplicationContextRunner().withUserConfiguration(Fabric8LeaderConfiguration.class) .withAllowBeanDefinitionOverriding(true) .withUserConfiguration(Fabric8LeaderElectionAutoConfiguration.class, Fabric8LeaderElectionCallbacksAutoConfiguration.class, TestConfig.class) - .withPropertyValues("spring.main.cloud-platform=KUBERNETES") + .withPropertyValues("spring.main.cloud-platform=KUBERNETES", "use.mock.config=true") .run(context -> { // matchIfMissing = true in the annotation, so both are present Assertions.assertThat(context).hasSingleBean(Fabric8LeaderElectionAutoConfiguration.class); @@ -71,7 +71,7 @@ void leaderElectionAnnotationMissing() { @Test void leaderElectionAnnotationPresentEqualToFalse() { new ApplicationContextRunner() - .withUserConfiguration(Fabric8LeaderApp.class, Fabric8LeaderElectionAutoConfiguration.class, + .withUserConfiguration(Fabric8LeaderConfiguration.class, Fabric8LeaderElectionAutoConfiguration.class, Fabric8LeaderElectionCallbacksAutoConfiguration.class, TestConfig.class) .withPropertyValues("spring.cloud.kubernetes.leader.election.enabled=false", "spring.main.cloud-platform=KUBERNETES") @@ -94,11 +94,11 @@ void leaderElectionAnnotationPresentEqualToFalse() { @Test void leaderElectionAnnotationPresentEqualToTrue() { new ApplicationContextRunner() - .withUserConfiguration(Fabric8LeaderApp.class, Fabric8LeaderElectionAutoConfiguration.class, + .withUserConfiguration(Fabric8LeaderConfiguration.class, Fabric8LeaderElectionAutoConfiguration.class, Fabric8LeaderElectionCallbacksAutoConfiguration.class, TestConfig.class) .withAllowBeanDefinitionOverriding(true) .withPropertyValues("spring.cloud.kubernetes.leader.election.enabled=true", - "spring.main.cloud-platform=KUBERNETES") + "spring.main.cloud-platform=KUBERNETES", "use.mock.config=true") .run(context -> { Assertions.assertThat(context).hasSingleBean(Fabric8LeaderElectionAutoConfiguration.class); Assertions.assertThat(context).hasSingleBean(Fabric8LeaderElectionCallbacksAutoConfiguration.class); diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderApp.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderConfiguration.java similarity index 91% rename from spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderApp.java rename to spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderConfiguration.java index fa224c425a..f588654afc 100644 --- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderApp.java +++ b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderConfiguration.java @@ -24,12 +24,14 @@ import io.fabric8.kubernetes.client.extended.leaderelection.resourcelock.Lock; import org.mockito.Mockito; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration -public class Fabric8LeaderApp { +@ConditionalOnProperty(value = "use.mock.config", havingValue = "true", matchIfMissing = false) +public class Fabric8LeaderConfiguration { @SuppressWarnings({ "rawtypes", "unchecked" }) @Bean diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsLeaderTest.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsLeaderTest.java index 3517024fea..9c206fb663 100644 --- a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsLeaderTest.java +++ b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/Fabric8LeaderElectionInfoContributorIsLeaderTest.java @@ -52,7 +52,7 @@ */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { "spring.main.cloud-platform=KUBERNETES", "management.endpoints.web.exposure.include=info", - "management.endpoint.info.show-details=always", "management.info.kubernetes.enabled=true", + "management.endpoint.info.show-details=always", "spring.cloud.kubernetes.leader.election.enabled=true" }) @AutoConfigureWebTestClient class Fabric8LeaderElectionInfoContributorIsLeaderTest { diff --git a/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/FabricLeaderApp.java b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/FabricLeaderApp.java new file mode 100644 index 0000000000..e868b3c639 --- /dev/null +++ b/spring-cloud-kubernetes-fabric8-leader/src/test/java/org/springframework/cloud/kubernetes/fabric8/leader/election/FabricLeaderApp.java @@ -0,0 +1,29 @@ +/* + * Copyright 2013-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.kubernetes.fabric8.leader.election; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FabricLeaderApp { + + public static void main(String[] args) { + SpringApplication.run(FabricLeaderApp.class, args); + } + +} From dd48b375d7e8bdd505d60228870cb7e8673f130a Mon Sep 17 00:00:00 2001 From: wind57 Date: Fri, 19 Dec 2025 18:30:38 +0200 Subject: [PATCH 3/3] remove spring integration dependency Signed-off-by: wind57 --- .../pom.xml | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/spring-cloud-kubernetes-fabric8-leader/pom.xml b/spring-cloud-kubernetes-fabric8-leader/pom.xml index 05094ab998..e564afc5de 100644 --- a/spring-cloud-kubernetes-fabric8-leader/pom.xml +++ b/spring-cloud-kubernetes-fabric8-leader/pom.xml @@ -1,20 +1,4 @@ - @@ -33,10 +17,6 @@ org.springframework.cloud spring-cloud-kubernetes-fabric8-autoconfig - - org.springframework.integration - spring-integration-core - org.springframework.boot spring-boot-starter-actuator