diff --git a/pom.xml b/pom.xml
index a79e8f16..204a4cf2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -87,6 +87,7 @@
spring-cloud-starter-kubernetes-zipkin
spring-cloud-starter-kubernetes-all
spring-cloud-kubernetes-examples
+ spring-cloud-kubernetes-lock
diff --git a/spring-cloud-kubernetes-lock/pom.xml b/spring-cloud-kubernetes-lock/pom.xml
new file mode 100644
index 00000000..29e30e81
--- /dev/null
+++ b/spring-cloud-kubernetes-lock/pom.xml
@@ -0,0 +1,74 @@
+
+
+
+ 4.0.0
+
+ org.springframework.cloud
+ spring-cloud-kubernetes
+ 0.3.0.BUILD-SNAPSHOT
+
+
+ spring-cloud-kubernetes-lock
+ Spring Cloud Kubernetes :: Lock
+
+
+
+ org.springframework.cloud
+ spring-cloud-kubernetes-core
+
+
+ org.springframework.integration
+ spring-integration-core
+
+
+ org.jboss.arquillian.junit
+ arquillian-junit-standalone
+ test
+
+
+ org.arquillian.cube
+ arquillian-cube-kubernetes
+ test
+
+
+ org.arquillian.cube
+ arquillian-cube-requirement
+ test
+
+
+ junit
+ junit
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ ${maven-failsafe-plugin.version}
+
+
+
+
diff --git a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepository.java b/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepository.java
new file mode 100644
index 00000000..6717ab2c
--- /dev/null
+++ b/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepository.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 to the original 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
+ *
+ * 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.lock;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigMapLockRepository {
+
+ static final String CONFIG_MAP_PREFIX = "lock";
+
+ static final String HOLDER_KEY = "holder";
+
+ static final String EXPIRATION_KEY = "expiration";
+
+ private static final String PROVIDER_LABEL = "provider";
+
+ private static final String PROVIDER_LABEL_VALUE = "spring-cloud-kubernetes";
+
+ private static final String KIND_LABEL = "kind";
+
+ private static final String KIND_LABEL_VALUE = "lock";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ConfigMapLockRepository.class);
+
+ private KubernetesClient kubernetesClient;
+
+ private String namespace;
+
+ public ConfigMapLockRepository(KubernetesClient kubernetesClient, String namespace) {
+ this.kubernetesClient = kubernetesClient;
+ this.namespace = namespace;
+ }
+
+ public ConfigMap get(String name) {
+ return kubernetesClient.configMaps()
+ .inNamespace(namespace)
+ .withName(getConfigMapName(name))
+ .get();
+ }
+
+ public boolean create(String name, String holder, long expiration) {
+ ConfigMap configMap = new ConfigMapBuilder().withNewMetadata()
+ .withName(getConfigMapName(name))
+ .addToLabels(PROVIDER_LABEL, PROVIDER_LABEL_VALUE)
+ .addToLabels(KIND_LABEL, KIND_LABEL_VALUE)
+ .endMetadata()
+ .addToData(HOLDER_KEY, holder)
+ .addToData(EXPIRATION_KEY, String.valueOf(expiration))
+ // TODO add information about the creator
+ .build();
+
+ try {
+ kubernetesClient.configMaps()
+ .inNamespace(namespace)
+ .create(configMap);
+ } catch (KubernetesClientException e) {
+ LOGGER.warn("Failed to create ConfigMap for name '{}': ", name, e.getMessage());
+ return false;
+ }
+
+ return true;
+ }
+
+ public void deleteAll() {
+ kubernetesClient.configMaps()
+ .inNamespace(namespace)
+ .withLabel(PROVIDER_LABEL, PROVIDER_LABEL_VALUE)
+ .withLabel(KIND_LABEL, KIND_LABEL_VALUE)
+ .delete();
+ }
+
+ public void deleteExpired() {
+ long now = System.currentTimeMillis();
+ // TODO check that it was created by this process
+ List configMaps = kubernetesClient.configMaps()
+ .inNamespace(namespace)
+ .withLabel(PROVIDER_LABEL, PROVIDER_LABEL_VALUE)
+ .withLabel(KIND_LABEL, KIND_LABEL_VALUE)
+ .list()
+ .getItems()
+ .stream()
+ .filter(c -> Long.valueOf(c.getData().get("expiration")) < now)
+ .collect(Collectors.toList());
+
+ kubernetesClient.configMaps()
+ .inNamespace(namespace)
+ .delete(configMaps);
+ }
+
+ private String getConfigMapName(String name) {
+ return String.format("%s-%s", CONFIG_MAP_PREFIX, name);
+ }
+
+}
diff --git a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepositoryIT.java b/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepositoryIT.java
new file mode 100644
index 00000000..8d7d9044
--- /dev/null
+++ b/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/ConfigMapLockRepositoryIT.java
@@ -0,0 +1,87 @@
+package org.springframework.cloud.kubernetes.lock;
+
+import java.util.Map;
+
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import org.arquillian.cube.kubernetes.api.Session;
+import org.arquillian.cube.kubernetes.impl.requirement.RequiresKubernetes;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(Arquillian.class)
+@RequiresKubernetes
+public class ConfigMapLockRepositoryIT {
+
+ @ArquillianResource
+ private KubernetesClient kubernetesClient;
+
+ @ArquillianResource
+ private Session session;
+
+ private ConfigMapLockRepository repository;
+
+ @Before
+ public void before() {
+ repository = new ConfigMapLockRepository(kubernetesClient, session.getNamespace());
+ }
+
+ @After
+ public void after() {
+ deleteConfigMap("test-name");
+ deleteConfigMap("test-name-2");
+ }
+
+ @Test
+ public void shouldCreateConfigMap() {
+ long expiration = System.currentTimeMillis();
+ boolean result = repository.create("test-name", "test-holder", expiration);
+ assertThat(result).isTrue();
+
+ ConfigMap configMap = repository.get("test-name");
+ Map data = configMap.getData();
+ assertThat(data).containsEntry(ConfigMapLockRepository.HOLDER_KEY, "test-holder");
+ assertThat(data).containsEntry(ConfigMapLockRepository.EXPIRATION_KEY, String.valueOf(expiration));
+ }
+
+ @Test
+ public void shouldNotOverwriteConfigMap() {
+ boolean firstResult = repository.create("test-name", "test-holder", 0);
+ assertThat(firstResult).isTrue();
+
+ boolean secondResult = repository.create("test-name", "test-holder", 0);
+ assertThat(secondResult).isFalse();
+ }
+
+ @Test
+ public void shouldDeleteAllConfigMaps() {
+ repository.create("test-name", "test-holder", 0);
+ repository.create("test-name-2", "test-holder-2", 0);
+ repository.deleteAll();
+ assertThat(repository.get("test-name")).isNull();
+ assertThat(repository.get("test-name-2")).isNull();
+ }
+
+ @Test
+ public void shouldDeleteExpiredConfigMaps() {
+ repository.create("test-name", "test-holder", System.currentTimeMillis() - 1);
+ repository.create("test-name-2", "test-holder-2", System.currentTimeMillis() + 10000);
+ repository.deleteExpired();
+ assertThat(repository.get("test-name")).isNull();
+ assertThat(repository.get("test-name-2")).isNotNull();
+ }
+
+ private void deleteConfigMap(String name) {
+ kubernetesClient.configMaps()
+ .inNamespace(session.getNamespace())
+ .withName(String.format("%s-%s", ConfigMapLockRepository.CONFIG_MAP_PREFIX, name))
+ .delete();
+ }
+
+}