diff --git a/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfiguration.java b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfiguration.java
new file mode 100644
index 00000000..149c692d
--- /dev/null
+++ b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderAutoConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 Red Hat, Inc, and individual contributors.
+ *
+ * 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
+ *
+ * http://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.leader;
+
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
+
+import io.fabric8.kubernetes.client.KubernetesClient;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.leader.Candidate;
+import org.springframework.integration.leader.DefaultCandidate;
+
+/**
+ * @author Gytis Trikleris
+ */
+@Configuration
+@EnableConfigurationProperties(LeaderProperties.class)
+@ConditionalOnBean(KubernetesClient.class)
+@ConditionalOnProperty(value = "spring.cloud.kubernetes.leader.enabled", matchIfMissing = true)
+public class LeaderAutoConfiguration {
+
+ @Bean
+ public LeaderInitiator leaderInitiator(KubernetesClient kubernetesClient, LeaderProperties leaderProperties)
+ throws UnknownHostException {
+ String candidateId = Inet4Address.getLocalHost().getHostName();
+ Candidate candidate = new DefaultCandidate(candidateId, leaderProperties.getRole());
+ LeaderInitiator leaderInitiator = new LeaderInitiator(kubernetesClient, candidate, leaderProperties);
+ leaderInitiator.start();
+ return leaderInitiator;
+ }
+
+}
diff --git a/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderInitiator.java b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderInitiator.java
index 079b6cd9..3e17a9b5 100644
--- a/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderInitiator.java
+++ b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderInitiator.java
@@ -42,22 +42,21 @@ public class LeaderInitiator implements SmartLifecycle {
private final Candidate candidate;
- private final LeaderConfiguration leaderConfiguration;
+ private final LeaderProperties leaderProperties;
private ScheduledExecutorService scheduledExecutorService;
private String currentLeaderId; // TODO remove once events are implemented
- public LeaderInitiator(KubernetesClient kubernetesClient, Candidate candidate,
- LeaderConfiguration leaderConfiguration) {
+ public LeaderInitiator(KubernetesClient kubernetesClient, Candidate candidate, LeaderProperties leaderProperties) {
this.kubernetesClient = kubernetesClient;
this.candidate = candidate;
- this.leaderConfiguration = leaderConfiguration;
+ this.leaderProperties = leaderProperties;
}
@Override
public boolean isAutoStartup() {
- return leaderConfiguration.isAutoStartup();
+ return leaderProperties.isAutoStartup();
}
@Override
@@ -115,40 +114,40 @@ public class LeaderInitiator implements SmartLifecycle {
try {
takeLeadership(configMap);
currentLeaderId = candidate.getId();
- scheduleUpdate(leaderConfiguration.getLeaseDuration());
+ scheduleUpdate(leaderProperties.getLeaseDuration());
} catch (Exception e) {
// Leadership takeover failed, try again later
System.out.println("Leadership takeover failed: " + e.getMessage());
- scheduleUpdate(leaderConfiguration.getRetryPeriod());
+ scheduleUpdate(leaderProperties.getRetryPeriod());
}
} else if (!isValidLeader(leader)) {
System.out.println("Old leader is not valid any more, try to take over");
try {
takeLeadership(configMap);
currentLeaderId = candidate.getId();
- scheduleUpdate(leaderConfiguration.getLeaseDuration()); // Is this needed?
+ scheduleUpdate(leaderProperties.getLeaseDuration()); // Is this needed?
} catch (Exception e) {
// Leadership takeover failed, try again later
System.out.println("Leadership takeover failed: " + e.getMessage());
- scheduleUpdate(leaderConfiguration.getRetryPeriod());
+ scheduleUpdate(leaderProperties.getRetryPeriod());
}
} else if (!isCandidateALeader(leader)) {
currentLeaderId = leader.getId();
System.out.println(currentLeaderId + " is a leader, check in later");
- scheduleUpdate(leaderConfiguration.getLeaseDuration());
+ scheduleUpdate(leaderProperties.getLeaseDuration());
} else {
System.out.println("I am a leader, check in later");
currentLeaderId = candidate.getId();
- scheduleUpdate(leaderConfiguration.getLeaseDuration()); // Is this needed?
+ scheduleUpdate(leaderProperties.getLeaseDuration()); // Is this needed?
}
}
private void takeLeadership(ConfigMap oldConfigMap) {
- String leaderIdKey = leaderConfiguration.getLeaderIdPrefix() + candidate.getRole();
+ String leaderIdKey = leaderProperties.getLeaderIdPrefix() + candidate.getRole();
if (oldConfigMap == null) {
ConfigMap newConfigMap = new ConfigMapBuilder().withNewMetadata()
- .withName(leaderConfiguration.getConfigMapName())
+ .withName(leaderProperties.getConfigMapName())
.addToLabels("provider", "spring-cloud-kubernetes")
.addToLabels("kind", "locks")
.endMetadata()
@@ -156,7 +155,7 @@ public class LeaderInitiator implements SmartLifecycle {
.build();
kubernetesClient.configMaps()
- .inNamespace(leaderConfiguration.getNamespace(kubernetesClient.getNamespace()))
+ .inNamespace(leaderProperties.getNamespace(kubernetesClient.getNamespace()))
.create(newConfigMap);
} else {
ConfigMap newConfigMap = new ConfigMapBuilder(oldConfigMap)
@@ -164,8 +163,8 @@ public class LeaderInitiator implements SmartLifecycle {
.build();
kubernetesClient.configMaps()
- .inNamespace(leaderConfiguration.getNamespace(kubernetesClient.getNamespace()))
- .withName(leaderConfiguration.getConfigMapName())
+ .inNamespace(leaderProperties.getNamespace(kubernetesClient.getNamespace()))
+ .withName(leaderProperties.getConfigMapName())
.lockResourceVersion(oldConfigMap.getMetadata().getResourceVersion())
.replace(newConfigMap);
}
@@ -176,8 +175,8 @@ public class LeaderInitiator implements SmartLifecycle {
private ConfigMap getConfigMap() {
try {
return kubernetesClient.configMaps()
- .inNamespace(leaderConfiguration.getNamespace(kubernetesClient.getNamespace()))
- .withName(leaderConfiguration.getConfigMapName())
+ .inNamespace(leaderProperties.getNamespace(kubernetesClient.getNamespace()))
+ .withName(leaderProperties.getConfigMapName())
.get();
} catch (Exception e) {
System.out.println("Failed to get a ConfigMap: " + e.getMessage());
@@ -191,7 +190,7 @@ public class LeaderInitiator implements SmartLifecycle {
}
Map data = configMap.getData();
- String leaderIdKey = leaderConfiguration.getLeaderIdPrefix() + candidate.getRole();
+ String leaderIdKey = leaderProperties.getLeaderIdPrefix() + candidate.getRole();
String leaderId = data.get(leaderIdKey);
if (leaderId == null) {
return null;
@@ -205,7 +204,7 @@ public class LeaderInitiator implements SmartLifecycle {
}
private long jitter(long num) {
- return (long) (num * (1 + Math.random() * (leaderConfiguration.getJitterFactor() - 1)));
+ return (long) (num * (1 + Math.random() * (leaderProperties.getJitterFactor() - 1)));
}
private boolean isCandidateALeader(Leader leader) {
@@ -214,8 +213,8 @@ public class LeaderInitiator implements SmartLifecycle {
private boolean isValidLeader(Leader leader) {
return kubernetesClient.pods()
- .inNamespace(leaderConfiguration.getNamespace(kubernetesClient.getNamespace()))
- .withLabels(leaderConfiguration.getLabels())
+ .inNamespace(leaderProperties.getNamespace(kubernetesClient.getNamespace()))
+ .withLabels(leaderProperties.getLabels())
.list()
.getItems()
.stream()
diff --git a/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderConfiguration.java b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderProperties.java
similarity index 73%
rename from spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderConfiguration.java
rename to spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderProperties.java
index 0f646a7f..37926512 100644
--- a/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderConfiguration.java
+++ b/spring-cloud-kubernetes-leader/src/main/java/org/springframework/cloud/kubernetes/leader/LeaderProperties.java
@@ -19,10 +19,13 @@ package org.springframework.cloud.kubernetes.leader;
import java.util.Collections;
import java.util.Map;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
/**
* @author Gytis Trikleris
*/
-public class LeaderConfiguration {
+@ConfigurationProperties("spring.cloud.kubernetes.leader")
+public class LeaderProperties {
private static final String DEFAULT_LEADER_ID_PREFIX = "leader.id.";
@@ -36,20 +39,56 @@ public class LeaderConfiguration {
private static final double DEFAULT_JITTER_FACTOR = 1.2;
+ /**
+ * Should leader election be started automatically on startup.
+ * Default: true
+ */
private boolean autoStartup = DEFAULT_AUTO_STARTUP;
+ /**
+ * 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 = DEFAULT_CONFIG_MAP_NAME;
+ /**
+ * Kubernetes labels common to all leadership candidates.
+ * Default: empty
+ */
private Map labels = Collections.emptyMap();
+ /**
+ * Leader id property prefix for the ConfigMap.
+ * Default: leader.id.
+ */
private String leaderIdPrefix = DEFAULT_LEADER_ID_PREFIX;
+ /**
+ * Time period after which leader should check it's leadership or new leader should be elected.
+ * Default: 30s
+ */
private long leaseDuration = DEFAULT_LEASE_DURATION;
+ /**
+ * Time period after connections should be retired after failure.
+ * Default: 5s
+ */
private long retryPeriod = DEFAULT_RETRY_PERIOD;
+ /**
+ * A parameter to randomise scheduler.
+ * Default: 1.2
+ */
private double jitterFactor = DEFAULT_JITTER_FACTOR;
public boolean isAutoStartup() {
@@ -60,6 +99,14 @@ public class LeaderConfiguration {
this.autoStartup = autoStartup;
}
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
public String getNamespace() {
return namespace;
}
diff --git a/spring-cloud-kubernetes-leader/src/main/resources/META-INF/spring.factories b/spring-cloud-kubernetes-leader/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000..6c05ac37
--- /dev/null
+++ b/spring-cloud-kubernetes-leader/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.springframework.cloud.kubernetes.leader.LeaderAutoConfiguration