diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..b3072d4
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,19 @@
+.classpath
+.git
+.gitignore
+.project
+.settings
+.travis.yml
+LICENSE
+README.md
+pom.xml
+src
+target/classes
+target/etcd-viewer-*-SNAPSHOT
+target/generated-sources
+target/generated-test-sources
+target/maven-archiver
+target/surefire-reports
+target/test-classes
+target/test-resources
+target/work
diff --git a/Dockerfile b/Dockerfile
index 0fc74c5..698ccfd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM jetty:9.2.12-jre7
+FROM jetty:9.2-jre8
MAINTAINER Nikos Fountas "nikfoundas@gmail.com"
@@ -11,6 +11,3 @@ RUN curl --silent -L `cat /tmp/etcd-viewer-release-archive` > /var/lib/jetty/web
# To build your own local custom etcd viewer docker image comment the above RUN commands and uncomment the following
# ADD ./target/*.war /var/lib/jetty/webapps/ROOT.war
-
-RUN chmod 644 /var/lib/jetty/webapps/ROOT.war
-RUN chown jetty:jetty /var/lib/jetty/webapps/ROOT.war
diff --git a/pom.xml b/pom.xml
index d8c3bdd..5f78a1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,6 +22,7 @@
1.6.4
1.2.16
4.11
+ 2.15.0
3.3.4
4.3.0
@@ -189,6 +190,13 @@
${junit.version}
test
+
+
+ org.mockito
+ mockito-core
+ ${mockito.version}
+ test
+
diff --git a/src/main/java/org/github/etcd/service/EtcdCluster.java b/src/main/java/org/github/etcd/service/EtcdCluster.java
index a9a375d..7a051cd 100644
--- a/src/main/java/org/github/etcd/service/EtcdCluster.java
+++ b/src/main/java/org/github/etcd/service/EtcdCluster.java
@@ -1,6 +1,3 @@
-/**
- *
- */
package org.github.etcd.service;
import java.util.Date;
diff --git a/src/main/java/org/github/etcd/service/RestModule.java b/src/main/java/org/github/etcd/service/RestModule.java
index a81c905..4463dac 100644
--- a/src/main/java/org/github/etcd/service/RestModule.java
+++ b/src/main/java/org/github/etcd/service/RestModule.java
@@ -1,15 +1,12 @@
-/**
- *
- */
package org.github.etcd.service;
import javax.inject.Inject;
import javax.inject.Singleton;
-import org.github.etcd.service.api.v3.EtcdV3ProxyImpl;
-import org.github.etcd.service.impl.ClusterManagerImpl;
import org.github.etcd.service.api.EtcdProxy;
import org.github.etcd.service.api.v2.EtcdV2ProxyImpl;
+import org.github.etcd.service.api.v3.EtcdV3ProxyImpl;
+import org.github.etcd.service.impl.ClusterManagerImpl;
import org.github.etcd.viewer.EtcdWebSession;
import com.google.inject.AbstractModule;
@@ -17,24 +14,24 @@
public class RestModule extends AbstractModule {
- private static final String ETCD_NODE = "etcd.clientURL";
-
public static final String SELECTED_CLUSTER_NAME = "selectedCluster";
@Override
protected void configure() {
-
- String etcdAddress = System.getenv(ETCD_NODE);
- if (etcdAddress == null) {
- etcdAddress = System.getProperty(ETCD_NODE, "http://localhost:2379/");
- }
-
- bindConstant().annotatedWith(Names.named(ETCD_NODE)).to(etcdAddress);
+ bindParameterValue(ClusterManagerImpl.DEFAULT_CLIENT_URL_KEY);
+ bindParameterValue(ClusterManagerImpl.CLUSTER_STORE_PATH_KEY);
bind(ClusterManager.class).to(ClusterManagerImpl.class).in(Singleton.class);
bind(EtcdProxyFactory.class).to(EtcdProxyFactoryImpl.class).in(Singleton.class);
+ }
+ private void bindParameterValue(String parameterName) {
+ String parameterValue = System.getenv(parameterName);
+ if (parameterValue == null) {
+ parameterValue = System.getProperty(parameterName, "");
+ }
+ bindConstant().annotatedWith(Names.named(parameterName)).to(parameterValue);
}
private static class EtcdProxyFactoryImpl implements EtcdProxyFactory {
diff --git a/src/main/java/org/github/etcd/service/api/EtcdNode.java b/src/main/java/org/github/etcd/service/api/EtcdNode.java
index 8319df8..f898022 100644
--- a/src/main/java/org/github/etcd/service/api/EtcdNode.java
+++ b/src/main/java/org/github/etcd/service/api/EtcdNode.java
@@ -1,6 +1,3 @@
-/**
- *
- */
package org.github.etcd.service.api;
import java.io.Serializable;
diff --git a/src/main/java/org/github/etcd/service/impl/ClusterManagerImpl.java b/src/main/java/org/github/etcd/service/impl/ClusterManagerImpl.java
index 1190fdc..7233483 100644
--- a/src/main/java/org/github/etcd/service/impl/ClusterManagerImpl.java
+++ b/src/main/java/org/github/etcd/service/impl/ClusterManagerImpl.java
@@ -1,5 +1,8 @@
package org.github.etcd.service.impl;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -21,6 +24,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Strings;
+import com.google.inject.name.Named;
+
public class ClusterManagerImpl implements ClusterManager {
private static final Logger log = LoggerFactory.getLogger(ClusterManager.class);
@@ -41,24 +49,47 @@ public int compare(EtcdMember o1, EtcdMember o2) {
STATE_MAPPINGS.put("StateFollower", "follower");
}
- @Inject
- private EtcdProxyFactory proxyFactory;
+ private final EtcdProxyFactory proxyFactory;
private Map clusters = Collections.synchronizedMap(new LinkedHashMap());
- private static final String DEFAULT_ETCD_CLIENT = "ETCD_CLIENT_URL";
-
- public ClusterManagerImpl() {
-
- String etcdAddress = System.getenv(DEFAULT_ETCD_CLIENT);
- if (etcdAddress == null) {
- etcdAddress = System.getProperty(DEFAULT_ETCD_CLIENT, "http://localhost:2379");
+ public static final String DEFAULT_CLIENT_URL_KEY = "ETCD_CLIENT_URL";
+ private static final String DEFAULT_CLIENT_URL = "http://localhost:2379/";
+ public static final String CLUSTER_STORE_PATH_KEY = "CLUSTER_STORE_PATH";
+ private static final String CLUSTER_STORE_FILENAME = "clusters.json";
+
+ private final File clusterStoreFile;
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ @Inject
+ public ClusterManagerImpl(@Named(DEFAULT_CLIENT_URL_KEY) String defaultClientUrl,
+ @Named(CLUSTER_STORE_PATH_KEY) String clusterStorePath,
+ EtcdProxyFactory proxyFactory) {
+ log.debug("{}: {}", DEFAULT_CLIENT_URL_KEY, defaultClientUrl);
+ log.debug("{}: {}", CLUSTER_STORE_PATH_KEY, clusterStorePath);
+
+ if (Strings.isNullOrEmpty(defaultClientUrl)) {
+ defaultClientUrl = DEFAULT_CLIENT_URL;
+ log.debug("Using default {}: {}", DEFAULT_CLIENT_URL_KEY, defaultClientUrl);
+ }
+
+ this.proxyFactory = proxyFactory;
+
+ if (!Strings.isNullOrEmpty(clusterStorePath)) {
+ clusterStoreFile = new File(clusterStorePath, CLUSTER_STORE_FILENAME);
+ if (clusterStoreFile.exists()) {
+ loadClusters();
+ }
+ } else {
+ clusterStoreFile = null;
}
- addCluster("default", etcdAddress, ApiVersion.V3);
- // addCluster("kvm", "http://192.168.122.201:2379/");
+ if (clusters.isEmpty()) {
+ addCluster("Local V2", defaultClientUrl, ApiVersion.V2);
+ addCluster("Local V3", defaultClientUrl, ApiVersion.V3);
+ }
}
-
+
@Override
public boolean exists(String name) {
return clusters.containsKey(name);
@@ -73,12 +104,17 @@ public EtcdCluster getCluster(String name) {
public EtcdCluster addCluster(String name, String etcdPeerAddress, ApiVersion apiVersion) {
EtcdCluster cluster = new EtcdCluster(name, etcdPeerAddress, apiVersion);
clusters.put(name, cluster);
+
+ persistClusters();
+
return cluster;
}
@Override
public void removeCluster(String name) {
clusters.remove(name);
+
+ persistClusters();
}
@Override
@@ -157,6 +193,40 @@ public void refreshCluster(String name) {
cluster.setLastRefreshTime(new Date());
cluster.setRefreshed(true);
+ persistClusters();
+ }
+
+ private void loadClusters() {
+ log.info("Loading {}", clusterStoreFile.getAbsolutePath());
+ try {
+ Map incoming = mapper.readValue(clusterStoreFile,
+ new TypeReference